Reading a dwell against time¶
A dwell holds one tone at one frequency for a time: a tone the environment really has (a rotor rate, an engine order), or a resonance a search found, held for fatigue. A sweep's level is read against frequency because the frequency is what changes. A dwell's frequency does not change, so against frequency its level is one point, and what it has to say is in time.
At a resonance the response does not jump to its steady height when the tone arrives. It builds, cycle by cycle, and when the tone stops it rings down at the same pace. For a mode of quality factor Q driven at its own frequency from rest, the share of the steady height reached after n cycles is very nearly
so after Q cycles it stands at 1 − e^−π, 95.7 %, and after 2Q cycles at 99.8 %, whatever the frequency and whatever the Q; n cycles after the stop, e^−πn/Q of it remains. About Q cycles to arrive and about Q to die away: a mode at 20 Hz with a Q of 30 takes a second and a half to reach its full response.
A dwell in the specification¶
A controller cannot hold a segment with no span, and neither does a
sine specification here, so a dwell is written the way a controller's
file writes it: a linear segment across a hair of a hertz, crossed in
the time the tone holds. SineTone.dwell builds one, sweeping a
millionth of its frequency (DWELL_SWEEP), and SineTone.is_dwell
reads any segment that spans no more than one part in ten thousand of
its frequency (DWELL_SPAN) as a dwell, so a controller's file reads
the same and nothing new is written to any file:
from visualdynamics.core.sine import (DWELL_SWEEP, LINEAR, LOG,
SineSweepSpecification, SineTone)
hold = SineTone.dwell('Dwell', 20.0, [9.80665], 4.5) # 1 g at 20 Hz, 4.5 s
spec = SineSweepSpecification([hold], ['1Z+'], ordinate_unit='m/s**2')
hold.dwell_segments() # [0]
# or as one segment of a tone that sweeps too: 10 to 20 Hz at 5 Hz/s,
# 20 Hz held for 30 s, then on up at 1 octave a minute
hair = 20.0 * DWELL_SWEEP
mixed = SineTone('Search and hold', 0.0, [10.0, 20.0, 20.0 + hair, 40.0],
[[9.8]] * 4, [LINEAR, LINEAR, LOG], [5.0, hair / 30.0, 1.0])
mixed.dwell_segments() # [1]
The reading¶
read_dwell places the tone on the recording (by matched filter on the
control channels, as the tracking readings do, or at onset=) and reads
one channel with a sine-tracking detector at the end of every whole
cycle of the dwell, then on at the same frequency after the stop, to the
end of the record. By default it reads a response (the first channel
the specification does not control, since the controller holds the
control at its level and the control does not build) with the peak over
each cycle, unfiltered; setting= takes any band and detector
the tracking readings take. It reports:
- the steady level, the median of the readings over the last quarter of the dwell;
- the build-up, the cycles from the dwell's start until the level first
reaches a share of the steady level, 95 % by default (
share=); - the ring-down, the cycles after the stop until it first falls to the rest of that share, 5 %;
- whether the level had settled (
settled), and notes on anything the numbers cannot be trusted for.
Take a 1 g tone at 20 Hz on a one-mass resonator of Q 30, held ninety cycles and then stopped:
from visualdynamics.core.dwell import read_dwell
from visualdynamics.plot import plot_dwell
from visualdynamics.units import DEFAULT_SYSTEM
reading = read_dwell(history, spec, onset=0.0) # 101Z+, the response
reading.level[29] / 9.80665, reading.seconds[29] # 28.72 g at 1.50 s
reading.share_at(30), reading.share_at(60) # 0.957, 0.998
reading.remaining_at(30) # 0.043, e to the -pi
print(reading.describe())
# steady 294.3 m/s², 95 % in 28.6 cycles (1.43 s), down to 5 % 28.6
# cycles after the stop
print(reading.describe(DEFAULT_SYSTEM))
# steady 30.01 g, 95 % in 28.6 cycles (1.43 s), ...
plot_dwell(history, spec, onset=0.0, path='dwell.png')

plot_dwell takes the same arguments as read_dwell. The steady level
is the wide gray line, the share is dashed and its complement dotted,
the two crossings are a filled circle and a filled triangle, and the
legend names each with its count, so the figure reads in gray as well
as in color.
In the window, select the record and turn on the sine view with the
specification in the project. When the specification holds a dwell, a
Dwell readout sits under the extraction's settings: the channel and
the share, then the frequency, the steady level, the build-up and the
ring-down in cycles and seconds, whether it settled, and the same
picture, small. It is a reading, so there is no button; each edit reads
again and is journaled as the plot_dwell call that draws it.
Where judgment lives¶
- A reading is reported after the instant it stands for. The peak over
a cycle is reported at the cycle's end, but in a decay the largest
value is at the cycle's start, a whole cycle earlier; RMS and mean
stand for the middle of what they average. Counted on the reported
clock, the ring-down would read a cycle longer than the build-up. So
every number the reading gives (the counts,
share_at,remaining_atand the plot) places each reading where it stands (reading.stands): the build-up and the ring-down of one Q read alike, and each number is the response's, whatever the detector. - The steady level is the record's, not the mode's. A dwell too short
to settle, or a resonance that moved during it as the article warmed
or cracked, reaches a level that is not the mode's steady response.
The reading says so (
settled, and a note) rather than borrowing a number from the formula above. - A dwell between sweeps does not start from rest or stop. A sweep that runs into the dwell leaves a response the build-up starts from, and a sweep that leaves it keeps driving, so nothing rings down from a stop and no ring-down count is read.
- A record that starts after the dwell has built holds no build-up. Its first reading is already over the share, so no count is given and a note says how many cycles into the dwell the record starts. A channel that reads no level at all over the dwell's last quarter, as a dead one does, is refused; read anyway, its zero would pass for a build-up done in one cycle.
- The matched filter places a held tone's start to within a sample on
a clean control; noise on the control moves it further. A pure tone
looks the same one cycle along, so its edges place it; the
correlation is taken against the tone's cosine and sine together, so
the phase the tone starts at does not move it. Give
onset=when the start is known otherwise.