A mixed-mode test as one specification¶
A sine-on-random test drives one signal made of parts: a broadband random floor written as breakpoints, and tones written in amplitude (peak), each at a fixed frequency or swept. A random-on-random test lays narrow bands of random over the floor instead, each a few percent of its center wide, fixed or swept. The parts are judged by different rules, and a report that quotes one rms figure for the test has said nothing, because there are three: the floor's rms with the tone lines left out, each tone in amplitude, and the total rms of the whole drive.
Take four tones of 0.12, 1.944, 2.5 and 1.5 g peak over a 1.0 grms floor. The tones' mean squares, \(A^2/2\), are 0.0072, 1.89, 3.13 and 1.13 g², 2.48 g rms together. The parts are independent, so their mean squares add, and the total is
with \(W_j\) a narrowband's level and \(B_j\) its width. All three are right, and each misleads when quoted alone as "the test level": 2.67 read as the floor is nearly three times too high, and a tone's g peak set beside the floor's grms compares two different quantities.
The specification¶
MixedSpecification holds the parts together: the floor (a random
Specification), the tones (a SineSweepSpecification), the
narrowbands (Narrowband) and the width left out of the floor either
side of each tone.
from visualdynamics.core.mixed_mode import (MixedSpecification,
Narrowband, Tone)
g = 9.80665
spec = MixedSpecification(
floor, # the random specification
[Tone(4.86, 0.12 * g), Tone(19.44, 1.944 * g),
Tone(38.88, 2.50 * g), Tone(58.32, 1.50 * g)],
seconds=60.0, # how long a fixed tone holds
exclusion=2.0) # Hz left out either side
spec.reference_rms() # floor, tones, bands, total
The tone table is entered as Tone rows. A fixed tone is a row with a
frequency and an amplitude; a swept tone adds sweep_to, a rate and
a mode (LINEAR in Hz/s, LOG in octaves a minute). A fixed tone
is written into the sine specification as the dwell a controller's
file holds (SineTone.dwell). A tone's written mean square is its
level squared over two, averaged over its run, so a tone held at two
levels in turn counts each for the time it is held.
spec.tone_table() reads any sine specification back as rows, fixed
where every segment holds one frequency.
A narrowband is written the way a standard writes it, or by its edges:
Narrowband.plus_minus(400.0, 5.0, 0.01 * g**2) # 380 to 420 Hz
Narrowband.between(380.0, 420.0, 0.01 * g**2) # the same band
Narrowband(56.0, 0.05 * g**2, width=4.0, # swept 56 to 93 Hz
sweep_to=93.0, rate=2.0) # and back, at 2 Hz/s
Its level is the density it adds over the floor between its edges, so
its mean square is the level times its width. A band given as a share
of its center (plus_minus) widens with the center as it sweeps, the
way a harmonic's band does; one given in hertz keeps its width. A
"5" typed into a field that wants the full width makes a band half as
wide, with half the mean square, which is why a band is checked by its
edges in hertz: band.edges(), and on the plot below. tolerance_db
is the tolerance the plan states for a band, since a swept band cannot
have the floor's statistics.
Nothing new in the file¶
A mixed test adds no object of its own to a project file. The floor is
saved as the random specification it is and the tones as the sine
specification they are, the two objects a random and sine project
already holds; MixedSpecification(floor, sweep) puts them back
together. A fixed tone is a dwell, so no segment type is added. The
narrowbands and the width left out are attributes of the floor,
Specification.narrowbands and Specification.tone_exclusion, saved
with it the way its band constraints are, so a file written with them
opens in an older version as the plain random specification. Given to
MixedSpecification, they are written onto a copy of the floor, which
spec.floor then holds; add that to the project to keep them.
The data sheet¶
judge_mixed(history, spec) reads one channel of a record against it,
part by part:
- Where the tones begin in the record is found by matched filter, as
the extraction finds it, unless
onsetis given. Each tone is read through a tracking band locked to its frequency (0.5 Hz wide by default), the way a controller reads it (How a tracking filter reads a sweep). The band settles in about one over its width, so nothing before that is read; the tone's level is the median of the readings after it, compared with the table at plus or minus 10 percent, an example of what test documents ask for. A small tone near the floor scatters through its band from reading to reading, and the median reads its level through that scatter. - What each band passed is taken out of the record. What is left, the residual, is the floor and the narrowbands.
- The floor is judged on the residual's averaged spectrum with the
lines that held a tone, and every narrowband's lines, left out. A
line held a tone when the tone spent a tenth of its run or more
within the left-out width of it: every line beside a fixed tone, and
few or none of the lines a long sweep passes, since it is near each
only briefly (a tone that dwells at two frequencies in turn holds
the lines beside each, not the ones its hop between them crosses) and what the band took with it is a small share of that
line's power. The floor is judged as a comparison is
(
compliance.judge): its rms against the reference's over the same lines (plus or minus 10 percent), and its lines against the reference moved 3 dB either way. An averaged line scatters, so a correctly controlled floor has a few lines outside 3 dB on a short record: on a 10 s record read from 2 s, about 28 degrees of freedom a line, 1.4 percent of lines, five of 384. The lines fail only when more are outside than chance would put there one time in a thousand; the sheet gives the count beside the number chance expects and the number allowed. A floor with no line left to judge is not judged, and the reading says so. - Each narrowband is judged at the degrees of freedom of a narrow band. A fixed band's level is the mean of its lines, worth what their correlation under the window leaves it, about half their count under Hann (Combining lines). A swept band stays over any one frequency only as long as it takes to move its own width, so it is read in slices half that long, each worth only the few frames it holds, and its level is the slices pooled. Its tolerance is the stated one, or the floor's, widened to the chi-square scatter at those degrees of freedom (90 percent by default), so a band of few degrees of freedom is not failed for scatter wider than its tolerance. A band with no line under it, or a swept band with no slice, is not judged.
- The total is every line of the record's spectrum. It has no tolerance of its own: it is the figure the amplifier, the coil and the fixture see, and the first one another lab computes.
from visualdynamics.core.mixed_mode import judge_mixed
reading = judge_mixed(history, spec, onset=0.0) # tones from the start
reading.floor.residual / g # 1.003, the residual over every line
reading.tones_measured / g # 2.477, the tracked tones' rms
reading.total.measured / g # 2.671, the whole drive
print(reading.describe('g', 1 / g))
visualdynamics.plot.plot_mixed_mode(history, spec, onset=0.0,
path='sheet.png')
The figures are for one minute of the composite above, the guide
composite of Reading a tone off an ASD. The tracked
tones read 0.122, 1.945, 2.496 and 1.498 g peak, 2.477 g rms together
against 2.479 written; the residual 1.003 grms over every line, and
0.986 against 0.986 written with the tone lines left out (2.8 percent
of the floor's lines); and the whole drive 2.671. Every value is
stored in SI, as every record is; describe and the plot take the display unit.
plot_mixed_mode draws the residual's spectrum over the reference, the
record with its tones dotted, a tone marker on each fixed tone (the
height its spike stands at for the spacing and window, with its
amplitude read off the spectrum in words), the lines left out hatched
and labeled "left out", and the data sheet beside it: the floor, the
tones together and each tone, each narrowband and the total, each with
its written and measured figure, its tolerance and its verdict in
words, and the settings that decide what the numbers mean under them.


In the second figure the swept band is read in 37 slices of about 9
degrees of freedom each, where a floor line has 112; one slice's
scatter alone is wider than 3 dB either way, and the band's level
pooled over the slices reads 0.2 dB over its written level. Its edges
are drawn dash-dotted and its travel cross-hatched, so the plot shows
where the band went as well as how strong it was. The figures are made
by tools/make_concept_figures.py.
In the app¶
In a random and sine project, select the record and choose the sine
view on the bar. When the project also holds the floor's random
specification at a channel the record has, a Mixed Mode readout
sits under the extraction's settings: the channel, the width left out
either side of a tone, the tracking band and the tones' tolerance.
Reading a long record takes seconds, so the first reading waits for
Read Data Sheet, and runs with the progress bar up; once the sheet
is up, an edit reads again at once. A refusal (a dead or constant channel, a sample
that is not finite, a record of another quantity) is shown in place of
the sheet and on the status line. The status line also carries the
sheet in one line once it is read, with its notes, so a part not judged
or a band that may read low says so there as well as on the sheet.
The sheet shows the same rows as the plot, the settings under them,
and a small spectrum of the residual over the reference with the
left-out lines hatched. The narrowbands are the floor's own
(Specification.narrowbands). The reading is journaled as its
plot_mixed_mode call.
What to watch¶
- A tone's spike on the spectrum is not its level. The tone is judged in amplitude, read through its band; the marker on the plot shows where the spike stands for this spacing, and is a picture.
- The width left out is part of the result. A floor feature inside it, a fixture resonance at a tone, is not judged against the floor's tolerance at all. The sheet gives the width and the share of the floor's lines it took, and says so in a note when more than half the floor was left out.
- A steady tone has nothing in time for the matched filter to lock onto
but where it starts, so with no
onsetgiven it is placed somewhere it plays, never before it, and the floor is read from there. Giveonsetwhen the tones' start is known. A swept narrowband needs it: where the band is at a moment is counted from the start, so with steady tones and noonsetit is not judged, and a note says why. - A channel holding a sample that is not finite, zero throughout or one value throughout is refused, naming the cause: one sample that is not finite spreads over every line of its frame's spectrum, and a dead or constant channel has no floor or tones to judge. A part with nothing left to judge reads "not judged", never "passes", and shows no count of lines outside and no degrees of freedom; a sheet that judged nothing has not passed.
- The channel is read by its full identity. Where a record holds two
quantities at the control DOF (a force and an acceleration at
1Z+), the one read is the quantity the floor is the density of; two records of that one quantity at the DOF are refused, since the sheet reads one. - A record of another quantity than the floor or the tones (velocity against an acceleration floor) is refused, by the rule every comparison uses.
- A tone at the floor's edge has no floor under it on one side. The reading says so in a note.
- A swept band moving faster than a frame fine enough to resolve it reads low; the note says so and gives the line spacing used.