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.
detrendfits 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
detrendwith 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.