How a tracking filter reads a sweep¶
A swept-sine controller measures the response differently from
Extract Sine Levels. It reads the response at the drive frequency
through a tracking filter, a band-pass centered on the drive
frequency that follows it along the sweep, and turns the filter's
output into a level with a detector. Both are settings, and the same
response record gives a different level curve for each. When a
controller's level and an extracted one disagree, the reason is
usually in those two settings, and
visualdynamics.core.sine_tracking reads a record each way so the
difference can be seen.
The band and the detector¶
The band has a fixed width in Hz (fixed=), or a width proportional
to the drive frequency, given as a fraction of it (proportional=).
A common setting on the test floor is proportional, around half the
drive frequency. A proportional band must be narrower than twice the
drive frequency, and a band is one kind or the other, never both.
With no band, the detector reads the record as it stands, and the
filter-output detector needs a band.
The detector is one of four:
| Detector | detector= |
Reads | Reported as |
|---|---|---|---|
| Filter output | 'filtered' |
the band's own output amplitude, at the instant | itself |
| Peak | 'peak' |
the largest absolute sample over the last cycle | itself |
| RMS | 'rms' |
the root mean square over the last cycle | times √2 |
| Mean | 'mean' |
the mean absolute value over the last cycle | times π/2 |
The last two are reported as the peak of the sine they would be, so
for a clean tone all four read its amplitude. For any other waveform
they read differently. The waveform detectors read over the last
cycle of the drive by default (cycles=), and the filter is fourth
order by default (order=).
What a harmonic does¶
A clipped amplifier drive puts a third harmonic on the response. Read without a filter, a peak detector counts the harmonic's peaks: a harmonic of 30 % in phase with its tone reads 30 % high. An RMS detector counts its power instead: the same harmonic reads √(1 + 0.3²), about 4.4 % high. Through the band, neither is seen: the harmonic is at three times the drive frequency, outside any band narrower than four times the drive. A mean detector on the same record reads about 10 % low: the harmonic in phase sharpens the peaks and lowers the shoulders, and the shoulders hold more of the area. Broadband noise behaves the same way: an unfiltered RMS reading counts all of its power, and a band counts only the part inside it.
![]()
What the band costs¶
A band takes time to follow a change in level, roughly one over its width. A level that doubles part way through a sweep is followed in a millisecond by an unfiltered peak detector, in 7 ms through a 50 % band at 250 Hz, in 37 ms through a 10 % band, and in 180 ms through a 5 Hz fixed band (the time to reach half way, in each case). On a sweep at 100 Hz/s, 180 ms is 18 Hz of the frequency axis, read low. The fourth-order filter also overshoots a step by about a tenth of it before it settles.
![]()
The choice of width is a trade between settling time and rejection. A narrow band rejects harmonics and noise and lags a change in level, such as a resonance passed through quickly; a wide band follows the change and includes more of what is not the tone.
Seeing the band on the record¶
A level curve shows what the band read but not why. The band is
easier to understand drawn on the record it was applied to, so
plot_tracking_filter draws one setting on one tone of the record,
in four parts:
- The record and what the band passes: the record in gray and the band's output over it in magenta. The band's output is the tone at its own amplitude, sample by sample, with the harmonic and the noise removed.
- The record's scalogram, time across and frequency up a log axis, colored in dB below its largest value so the noise floor is visible, with the cone of influence shaded as in the wavelet guide. Over it, the band is drawn as a corridor that follows the sweep: two dashed lines at the drive frequency plus and minus half the bandwidth, the band's −3 dB edges. The tone runs up the middle of the corridor, the third harmonic runs parallel to it outside, and the noise fills the rest of the picture.
- The band's shape at a cursor, beside the picture on the same frequency axis: its magnitude in dB, with the drive marked inside the band by a circle and the harmonic outside it by a triangle. A readout gives the drive frequency, the band's edges, the settling time (one over the bandwidth) and how far down the band holds the harmonic.
- The band's weight on the record, shaded behind the cursor. The band's output at an instant is the record before that instant, weighted by the filter's impulse response, so the shading shows how far back the reading reaches. That distance is the settling time.
A proportional band is a constant width on the log axis, so its corridor runs parallel to the tone. A fixed band is a constant width in hertz, so its corridor is wide at the bottom of the axis and narrows toward the top. At 100 Hz the 50 % band is 75 to 125 Hz, settles in about 20 ms and holds the harmonic 72 dB down. The 5 Hz band is 97.5 to 102.5 Hz and holds the harmonic below the shape's −80 dB floor, but it takes about 200 ms to settle, and its weight on the record is visibly wider.
![]()
![]()
The picture's wavelet resolves frequency to about 7 % either side of the tone, so a band narrower than that, such as a 10 % proportional band or a few hertz fixed, draws as a corridor inside the tone's ridge. That is a resolution limit of the time-frequency picture, and the band itself is still as narrow as set. Shown in a window, the cursor can be dragged along either time axis, and the shape, the marks, the weight and the readout follow it.
From a script¶
from visualdynamics.core.sine_tracking import (SineTracking, track_sine,
track_waveform)
from visualdynamics.plot import plot_sine_tracking, plot_tracking_filter
settings = [SineTracking(detector='peak'), # no band
SineTracking(proportional=0.5), # 50 % of the drive
SineTracking(proportional=0.1), # 10 %
SineTracking(fixed=10.0, detector='rms')]
levels = track_sine(history, specification, settings) # one SineLevel each
plot_sine_tracking(history, specification, settings, path='tracking.png')
band = SineTracking(proportional=0.5)
waveform = track_waveform(history, specification, band) # every sample
plot_tracking_filter(history, specification, band, cursor_hz=100.0,
path='band.png')
track_sine reads one tone (the specification's first, or tone=) on
the control channels, or on any channels named with channels=. The
tone's sweep is found in the record the way the extraction finds it,
or placed at onset=. Every setting is read at the same lines along
the sweep, so the levels overlay line for line. Each is a SineLevel
in the record's own units, stamped with the second each line was
read, its comment naming the reading (SineTracking.describe()).
SineTracking.settling(frequency) is the one-over-the-bandwidth rule
at a given drive frequency.
track_waveform runs the same band over every sample of the tone's
span and keeps the passed waveform (passed) and the band's output
amplitude (level), with the drive frequency at each sample;
instant(frequency) returns the time the drive passes a frequency.
SineTracking.response(drive, frequencies) is the band's shape in dB
at a given drive frequency, and SineTracking.weighting(drive, lags)
its weight on the record before an instant. plot_tracking_filter
draws all of them for one setting. Its cursor is placed by cursor=
in seconds or cursor_hz= in hertz (not both), span= sets the
stretch of record the time axes show, harmonics= names the multiples
of the drive to mark (the third by default), channel= picks the DOF
drawn (the first control channel by default), and low= and high=
set the scalogram's frequency range.
plot_sine_tracking draws one channel (channel=), each reading in
its own color and with its own marker shape, and the specification's
target behind them in gray.
Where judgment lives¶
- These readings are for understanding what a controller reported. For a report, use the extraction: it solves every tone jointly, removes the amplitude bias and chooses its smoothing from the data. A tracking filter reads one tone at a time and includes whatever its band lets through.
- What the band leaves out is the distortion check's subject: the record less the tracked tones against the tones, along the sweep (Checking a sine record for distortion).
- The filter runs forward only. A controller's filter cannot see ahead, so this one does not either, and its lag is part of what it reads. It starts settled on the tone's first cycle, as a controller's filter has settled during its ramp-up.
- A wide fixed band at the bottom of a sweep no longer isolates the drive frequency. Where half the band reaches past the drive frequency toward zero, the band includes everything below the drive as well, and the reading shows a ripple at twice the drive.
- A peak is the peak of the samples. It reads low by at most cos(π × drive / sample rate): 0.3 % at a fortieth of the sample rate, more on a harmonic near the top of the band.
- RMS and mean read the waveform between the samples. Near the top of a band a cycle can be a few samples long, and an average of the samples alone misses part of a sample at the ends of the span and the waveform's shape between samples. So the two are read from the record upsampled until a cycle has 64 points, over exactly the span's phase: a clean tone reads within 0.1 % down to under three samples a cycle.
- The readings and both plots are scripting calls only; the application has no view for them yet.