Checking a shock record before its spectrum¶
A shock response spectrum is computed from whatever the record holds, including what the table never did. The commonest fault is a zero shift: after a severe shock a piezoelectric accelerometer can be left reading a few g that are not there, and on an acceleration plot that peaks in the hundreds of g, a few g are hard to see. A DC offset anywhere in the signal chain does the same. Both turn the spectrum's low end into a flat shelf, because an oscillator far below the shock's content responds to the step and to nothing else.
Integrated to velocity, the fault is plain. A shock on a shaker starts
and ends with the table at rest, so its velocity leaves zero, swings,
and comes back. A zero shift or an offset integrates to a ramp, and the
velocity never comes back. visualdynamics.core.shock_check makes that
check, and plot_shock_check draws it beside the spectra it protects.
Why the integration is raw¶
project.integrate and TimeHistory.integrate remove the record's
mean and apply a 2 Hz drift high-pass by default, which is the right
default for turning a good record into a displacement estimate. It is
the wrong one for this check, because the drift it removes is the fault
the check looks for. Integrated with the default, a zero-shifted
record's velocity ends at zero as though nothing were wrong, and every
classical pulse loses its velocity change with the mean.
The check integrates by the same trapezoid rule with nothing removed
(drift_corner=None), the record's acceleration channels only, twice:
once to velocity and once to displacement. Each window is read from its
own start, so every event begins at rest whatever the record did before
it. The windows are the ones the SRS is computed over: the record's
shocks, or its averaging frames, or the whole record.
What it reports¶
check_shock(history) returns one ShockCheck per acceleration channel
per window, with the raw velocity and displacement through the window
and these readings:
| Reading | What it is |
|---|---|
velocity_change |
the span from the lowest velocity to the highest; 2AT/π for a half-sine of peak A and duration T, and still the main pulse's change when compensation pulses sit either side of it |
end_velocity, end_velocity_share |
where the velocity ends, and that as a share of its largest excursion |
end_displacement, end_displacement_share |
the same for the displacement |
flagged |
the velocity ends further from rest than tolerance of its peak |
drifting |
the velocity is still changing when the window closes |
The tolerance is a tenth of the peak by default (RETURN_SHARE), and an
argument: a procedure that names its own figure passes it. A tenth is a
judgment; no standard gives the figure. A good record's velocity does
not end at exactly zero, because the sensor's noise is integrated too
and walks: by about the noise's standard deviation times the square
root of the number of samples times the sample interval. A zero shift
worth catching ramps the velocity well past its pulse. In the example
below, the ringing shock with its noise floor ends at 0.04 % of its
peak velocity, and with its zero shift at 100 %.
A flagged check says which of two things the velocity did. Still changing when the record stops is a zero shift or an offset, and the spectrum is false at its low end. Held at a net velocity change is a pulse with nothing to bring the velocity back, which a drop machine makes and a shaker cannot. A half-sine on its own is the second case: it ends at its full velocity change, 2AT/π, and holds there.
The positive and negative spectra¶
TimeHistory.compute_srs_polarities() returns the positive, negative
and maximax spectra from one pass of the filter, at the Q, spacing and
band compute_srs takes (Q = 10 and a twelfth of an octave unless
told otherwise). The negative spectrum is reported as a magnitude so the
two are drawn on one log axis. They are worth reading together: the
maximax spectrum is the larger of the two at every frequency, so a
response that went nearly all one way looks no different in it from
one that went both ways.
An example¶
A ringing shock, four decaying tones from 600 Hz to 6 kHz peaking near 400 g, sampled at 102.4 kHz for a quarter of a second, with a 4 g zero shift from the moment it arrives:
from visualdynamics.core.shock_check import check_shock, summarize
from visualdynamics.plot import plot_shock_check
from visualdynamics.units import IN_LBF_S
check, = check_shock(history)
check.flagged # True
check.end_velocity / 0.0254 # 355.2 in/s: no table did that
print(summarize([check]))
plot_shock_check(history, low=10.0, high=10000.0,
unit_system=IN_LBF_S.with_units(acceleration='g'),
path='shock-check.png')
On the acceleration the shift is hard to see. On the velocity it is a ramp to 355 in/s, far outside the band the velocity has to end in, and the verdict says so. The positive spectrum stands on a shelf near 7.4 g below about 100 Hz that the shock does not have, and the negative spectrum, which the step does not reach, falls away there:

The same record without the shift passes, its velocity ending at 0.007 in/s. A 50 g, 11 ms half-sine compensated by a 2.5 g half-sine either side, the shaker's way of bringing the table back to rest, passes too: the velocity runs down to −67.6 in/s through the pre-pulse, up through the main pulse to +67.6 in/s, a velocity change of 135.2 in/s, and back to rest. Its spectra part above the pulse: the positive settles at the pulse's 50 g and the negative at the compensation's 2.5 g.

In the app¶
The Shocks view states the check beside the windows, under the SRS
settings and before Compute SRS: one line when every channel
returns to rest in every window, and otherwise how many do not and the
verdict of the worst, by channel and shock. It is the same
check_shock over the same windows, read again whenever a window is
detected, added, dragged or typed in. A record with no shocks marked
(and no averaging) is not checked yet, because Compute SRS detects
its windows before it computes and the check would otherwise speak for
windows it was not read over; the view says so. A window holding a
sample that is not a finite number is refused, and the view says
which channel.
Where judgment lives¶
- What the record is from. The flag says the velocity did not come back to rest. For a shaker shock that is a fault; for a drop machine a held velocity change is the pulse doing what it should, and the words say which of the two the record did.
- The window's length. The check reads the velocity at the window's end, so a window that closes before the ringing or the compensation is over reads a velocity that had not finished. The shock windows on the trace are where to check.
- What to do with a flagged record. A zero shift is a sensor problem to be found, not a spectrum to be reported. Filtering the spectrum's low end away, or integrating with the drift high-pass on, hides the symptom and keeps the fault.