Skip to main content

Examples

Worked recipes for plant data. Each runs in any scope: the Script Console, a gateway timer, a tag change script or a Perspective binding transform. They assume x holds evenly sampled values, times their timestamps, and fs the samples per second, as in Quick start.

Clean a noisy signal without lag​

A causal filter delays every feature; filtering forwards and backwards cancels the delay, so steps and peaks stay where they happened.

sos = system.signal.butter(4, 0.05, fs=fs, output="sos") # 4th order, 0.05 Hz cut-off
clean = system.signal.sosfiltfilt(sos, x)
rows = [[t, raw, c] for t, raw, c in zip(times, x, clean)]
chart = system.dataset.toDataSet(["t_stamp", "raw", "clean"], rows)

Use sections (output="sos" with sosfiltfilt) rather than b, a with filtfilt: they stay accurate at high orders and low cutoffs.

Choose a filter from a specification​

Let order selection find the lowest order that meets the specification, then check the response.

import math
# pass 0.2 Hz within 1 dB, attenuate 1 Hz by 40 dB, at 10 samples per second
N, Wn = system.signal.buttord(0.2, 1.0, 1, 40, fs=10.0)
sos = system.signal.butter(N, Wn, fs=10.0, output="sos")
f, h = system.signal.freqz_sos(sos, worN=[0.2, 1.0], fs=10.0)
print N, [20 * math.log10(abs(v)) for v in h] # 4, then about -1.0 dB and -51.2 dB

Remove spikes and get a smooth rate of change​

A median filter removes single-sample spikes and keeps real steps sharp; a Savitzky-Golay filter then gives the derivative directly.

despiked = system.signal.medfilt(x, 5)
rate = system.signal.savgol_filter(despiked, 31, 3, deriv=1, delta=1.0 / fs) # units per second
rate_per_minute = [60.0 * r for r in rate]

Find batch peaks and when they happened​

Prominence keeps the peaks that stand out from their surroundings; distance and widths are in samples.

peaks, props = system.signal.find_peaks(clean, prominence=2.0, distance=int(300 * fs))
for i, p in enumerate(peaks):
print times[p], clean[p], props["prominences"][i]
widths, heights, left, right = system.signal.peak_widths(clean, peaks, rel_height=0.5)
durations_s = [w / fs for w in widths] # duration at half prominence

Find the period of an oscillating loop​

A control loop that cycles shows up as a peak in its power spectral density.

f, pxx = system.signal.welch(x, fs=fs, nperseg=2048, nfft=16384)
k = pxx.index(max(pxx[1:])) # skip the zero-frequency bin
period_s = 1.0 / f[k]

Each segment (nperseg samples) should span several periods of the slowest oscillation you look for, and nfft places the peak between the coarse bins. With two hours of one-second data, these settings find periods of 60 s, 300 s and 900 s to within about 1%; with nperseg=1024 and no nfft, a 900 s period reads as 1,024 s, the nearest bin. To see how the spectrum changes over time, use spectrogram.

Vibration envelope​

The magnitude of the analytic signal is the amplitude envelope, which shows impacts and beating.

envelope = [abs(z) for z in system.signal.hilbert(vibration)]

Align and thin tags​

Bring a tag logged every 5 s onto a 1 s time base, or thin a long 1 s pull to one sample per minute without aliasing.

aligned = system.signal.resample_poly(tag_5s, 5, 1)
per_minute = system.signal.decimate(system.signal.decimate(x_1s, 6), 10)

For large factors, decimate in stages as above (6 then 10, rather than 60): the default IIR filter is designed for factors up to 13.

Complete example: pressure rate-of-rise leak test​

The repository's examples/leak-test folder holds a complete Ignition application: the rate-of-rise leak test used on vacuum chambers, freeze dryers, autoclaves and sealed vessels.

  • The chamber is pumped down, isolated and left to settle, then its pressure rise is recorded from the historian.
  • detrend fits a line to the rise: its slope times the chamber volume is the leak rate, in mbar·L/s, and what remains gives the noise.
  • A second detrend with breakpoints at the quarter points compares the rise rate at the start and end of the test. A rate that is still falling means outgassing, not a leak, and the test reports INCONCLUSIVE instead of a false FAIL.
  • A built-in simulator runs a test every 14 minutes with a known leak rate, so every verdict can be checked against the truth; in 240 simulated tests every verdict was right.

It ships as a project library script with six setup steps: tags, a gateway timer, a tag change script and an optional Perspective view.