Judging an SRS against its tolerance¶
A shock test is accepted on a band and a count. The requirement is a shock response spectrum, the band is written in decibels below and above it, and the test document says how many of the measured spectrum's points must lie inside the band. This page describes that judgement in Visual Dynamics, how it differs from the RMS deviation the shock workflow's bars show, and how to run it from a script.
Two readings of one spectrum¶
srs_errors in visualdynamics.core.compliance gives one number per
channel and event: the RMS of the point-by-point deviation in dB,
signed by the side its mean falls on. It is a good summary of how far
a spectrum strays, and the SRS Error bars of the
shock workflow are drawn from it. It is
not the tolerance check. It does not count points, and a spectrum can
sit well inside 3 dB in RMS while several of its points are outside
the band: ten neighboring points 5 dB under, among 92 on the
requirement, read −1.6 dB in RMS and leave 89 percent of the points
inside.
srs_tolerance is the tolerance check. It reads every point of the
measured spectrum against the requirement at that natural frequency,
counts the points inside the band, and applies a rule to the count.
Both readings are kept, because they answer different questions: the
bars say which channels and events strayed and in which direction,
and the count says whether a spectrum met its tolerance.
The rule¶
- The points. The measured spectrum's own points are judged, at the natural frequencies its spacing defines, because a tolerance on an SRS is applied at those points. The requirement is read at each one log-log between its breakpoints, the way it is drawn. Points outside the band the requirement is written over are not judged.
- The distance. Each point's distance from the requirement is twenty log ten of the ratio, since an SRS is an amplitude. A point on a band's edge is inside it.
- The bands. A specification that carries limits is judged against
them: its warning limits are the inner band and its abort limits
the outer one, read at each point the way the comparison shades
them. A band given in the call replaces the limits, and
limits=Falsesets them aside. Without either, the inner band is −1.5 dB below and +3 dB above the requirement, and there is no outer band. When there is an outer band, every point must lie inside it whatever the rule says. - The count. Two rules are offered, as examples of the kinds of rule
test documents ask for. The test plan states which one applies and
with which numbers.
rule='share'(the default) passes when at leastpercentof the points (90 by default) lie inside the inner band.rule='above_lower'passes when every point is at or above the inner band's lower edge. The band has no upper edge under this rule, so every point at or above the lower edge counts as inside.
A rule that asks for a share of the points above the requirement is
the share rule with a band from 0 dB up:
inner=(0.0, numpy.inf), percent=50.0.
5. The worst point. The result names the point farthest outside the
band the rule applies, with its distance from the requirement. That
is not always the point farthest from the requirement: under
−1.5/+3 dB, a point 2.5 dB over is inside and one 2 dB under is
not.
The Q and the quantity must match. A spectrum computed at another Q
is a different curve, and a spectrum of velocity says nothing about a
requirement in acceleration, so such a pair is refused with the reason
instead of judged. Units follow the rule every comparison uses
(Units in a comparison): a pair
with only one side's units declared is refused, and a pair with
neither declared is judged as raw numbers and says so. srs_errors
refuses by the same rules. A refused pair keeps its row, with db NaN
and refused giving the reason, and the SRS Error bars, the table
under them and the report write that reason in the row where the bar
would be.
Each polarity¶
A spectrum is judged in the polarity it holds. To judge a pulse's
positive and negative spectra against one maximax requirement, compute
each (compute_srs(kind='positive'), kind='negative') and judge each.
A pulse that is not symmetric often meets the requirement in one
direction and not the other, and the maximax spectrum, which takes the
larger of the two at every point, hides that.
In the app¶
Select the shock specification and a measured SRS together, and choose
Points Rule on the bar, beside Spectra and SRS Error. To
judge several polarities at once, select the positive, negative or
maximax spectra together with the specification. Points Rule is
then the only reading on the bar, because the spectra and the bars
read one measurement at a time; the table under the plot gives each
polarity's RMS deviation on its own row. Spectra of one polarity are
one measurement each and are compared one at a time. The plot is the
picture below, at the channel and event chosen in the box on the bar.
The panel beside it holds the rule (a share inside, or every point at
or above the lower edge) and the share asked for. When the
specification carries limits, Spec limits is ticked and the
judgement is against them; untick it to set the bands by hand,
starting from the specification's own numbers. Otherwise the panel
holds the inner band and, when ticked, the outer band. Under them,
for each polarity, are the count and share of its points inside, the
verdict, and its worst point with its distance from the requirement
in dB.
Every edit redraws the judgement at once. Nothing is made, so there is
no Apply button; the console records the plot_srs_tolerance call
that draws what is on screen.
From a script¶
from visualdynamics.core.compliance import srs_tolerance, srs_tolerance_all
from visualdynamics.core.data import ShockSpecification
from visualdynamics.plot import plot_srs_tolerance
# the requirement as written: breakpoints, Q, spacing, type and bands
spec = ShockSpecification.from_breakpoints(
[10.0, 100.0, 2000.0], [10.0, 100.0, 100.0], '101Z+',
per_octave=12, q=10.0, kind='maximax', ordinate_unit='g',
warning=(-1.5, 3.0), abort=(-3.0, 6.0))
# the spectra, at the same Q and spacing, in each polarity
positive = history.compute_srs(low=10.0, per_octave=12, q=10.0,
kind='positive')
negative = history.compute_srs(low=10.0, per_octave=12, q=10.0,
kind='negative')
# the bands are the specification's limits, -1.5/+3 dB inside -3/+6 dB
result = srs_tolerance(spec, positive)
print(result['inside_count'], 'of', result['points'], 'inside;',
'passed' if result['passed'] else 'failed',
f"worst {result['worst_db']:+.1f} dB at {result['worst_frequency']:.0f} Hz")
# every channel and event, paired as srs_errors pairs them
for dof, event, row in srs_tolerance_all(spec, negative):
print(dof, event, row['inside_percent'], row['passed'])
plot_srs_tolerance([positive, negative], spec, path='tolerance.png')
ShockSpecification.from_breakpoints reads the breakpoints onto the
points of the spacing, from the first breakpoint up, so a spectrum
computed at the same spacing from the same lowest frequency lands on
the requirement's points. The spectrum's last point can fall past the
last breakpoint, where nothing is required, and is not judged. Each
band given becomes a pair of limit curves, so the specification
carries its tolerance, the comparison the application draws when the
spectrum and the specification are selected together shades it, and
the judgement reads it.
visualdynamics.core.compliance.srs_points is the same judgement on
plain arrays.
The picture¶
plot_srs_tolerance draws the requirement in gray, the zones of its
band the way a random specification's are shaded (yellow outside the
inner band, red above and blue below the outer one), and each spectrum
in its own color and marker. Every point the rule counts against a
spectrum is its marker filled. Each spectrum's legend entry gives its
polarity, the count and share of its points inside, and whether it
passed.

In the figure the maximax spectrum reads −0.97 dB in RMS, inside the 3 dB the bars shade at. It has 87 of its 92 points inside the inner band, which meets a 90 percent share, and it still fails, because three of the points in the dip are past the outer band. The negative spectrum fails on both counts.