4. Digital filtering for crash signals

Raw accelerometer data from a crash test is never used directly for injury criteria. A typical piezoelectric or piezoresistive accelerometer sampled at 10–20 kHz carries high-frequency content that is physically meaningless for the occupant's body: sensor resonance, structural ringing of the sled or vehicle body, cable microphonics, and quantization noise. Injury criteria such as HIC, 3 ms clip, chest deflection rate, and Nij are all defined on signals that have been low-pass filtered to a specified cutoff. Filtering is therefore not cosmetic — it is part of the measurement definition. Two labs that filter the same raw channel differently will report different HIC values, and neither is "wrong" in isolation; the filter is part of the test specification.

This chapter covers the three filter families you will actually meet in crash work: Butterworth (maximally flat passband), Chebyshev Type I (steeper rolloff at the cost of passband ripple), and the SAE J211 channel frequency class (CFC) filters, which are the regulatory standard for occupant injury signals. It then addresses the practical issue that dominates real processing: phase distortion, and why scipy.signal.filtfilt is the default choice for offline crash analysis.

Filter specifications and what the numbers mean

Every digital filter in this domain is specified by a passband edge, a stopband edge, passband ripple, and stopband attenuation. For crash signals the key parameter is the cutoff frequency (the −3 dB point for Butterworth and Chebyshev) and the rolloff order. SAE J211 defines four channel frequency classes, each with a specified −3 dB cutoff and a tolerance envelope on the magnitude response:

CFC−3 dB cutoffTypical use
CFC 60100 HzHead CG acceleration, HIC
CFC 180300 HzChest acceleration, 3 ms clip
CFC 6001000 HzPelvis, femur, stiff structures
CFC 10001650 HzHigh-rate structural channels

Note the naming convention: CFC 60 means the filter's −3 dB point is at 100 Hz, not 60 Hz. The number is a class label, not a frequency. This trips up nearly everyone the first time. J211 also specifies the filter as a 4th-order (two cascaded 2nd-order) Butterworth-equivalent response with a defined tolerance band, so a plain butter(4, ...) is close but not automatically compliant — the tolerance envelope must be checked against the realized response.

Butterworth vs. Chebyshev: choosing the response shape

The Butterworth magnitude response is maximally flat in the passband and rolls off at 6·N dB per octave for order N. It has no ripple, which makes it the safe default when you need a clean, monotonic passband and the exact cutoff is not critical. Its weakness is a gentle transition: to get strong attenuation just above the cutoff you need a high order, and high orders bring numerical conditioning problems in the second-order-section (SOS) representation.

Chebyshev Type I trades passband flatness for a steeper transition. With a ripple parameter rp (in dB), the response oscillates within ±rp dB across the passband and then falls off faster than Butterworth of the same order. For crash signals this is rarely worth it: the passband ripple introduces amplitude modulation that can bias peak values, and injury criteria are peak-sensitive. Chebyshev Type II (stopband ripple, flat passband) is a better compromise when you need a sharp cutoff but cannot tolerate passband ripple, though its transition band is still wider than Type I at equal order.

For J211-compliant work, start from a 4th-order Butterworth-equivalent design and verify the magnitude response against the J211 tolerance envelope at the specified frequencies. Do not assume butter(4, fc, fs=fs) is compliant without checking — the bilinear transform warps the response near Nyquist, and the realized −3 dB point drifts from the requested fc.

Zero-phase filtering with filtfilt

A causal IIR filter delays the signal, and the delay is frequency-dependent (group delay). For a crash pulse, this means the filtered peak arrives later than the true peak, and different frequency components shift by different amounts — the waveform is distorted in shape, not just delayed. Since injury criteria are computed from peak values and time windows, phase distortion directly corrupts the result.

scipy.signal.filtfilt solves this by running the filter forward, reversing the signal, running it again, and reversing back. The forward and backward passes have opposite phase responses that cancel, leaving zero net phase shift. The magnitude response is squared, so the effective order doubles: a 2nd-order design applied with filtfilt behaves like a 4th-order magnitude response. This is why J211's 4th-order requirement is often met with a 2nd-order Butterworth passed through filtfilt — but you must confirm the squared magnitude still fits the tolerance envelope, because squaring also steepens the rolloff and shifts the −3 dB point.

import numpy as np
from scipy import signal

fs = 10000.0          # sample rate, Hz
fc = 100.0            # CFC 60 -3 dB point
order = 2             # doubled to 4th-order magnitude by filtfilt

# Design as second-order sections for numerical stability
sos = signal.butter(order, fc, btype='low', fs=fs, output='sos')

# Zero-phase application; padlen default is 3 * (2 * len(sos) + 1 - min(...))
y = signal.filtfilt(sos, np.ones(1), raw_accel, padtype='odd', padlen=1500)

# Verify realized -3 dB point
w, h = signal.sosfreqz(sos, worN=8192, fs=fs)
mag_db = 20 * np.log10(np.abs(h))
f_crossover = w[np.argmin(np.abs(mag_db + 3.0))]
print(f"realized -3 dB: {f_crossover:.1f} Hz")

Two details in that snippet matter. First, output='sos' is not optional for orders above about 4 — the transfer-function (ba) form loses precision and can produce an unstable filter. Second, padtype='odd' with an explicit padlen controls the edge transient. filtfilt pads the signal to suppress startup transients, but the default padding length may be too short for a low cutoff relative to the sample rate, leaving a visible artifact at the first and last few milliseconds — exactly where the crash pulse begins. Set padlen to at least several times the filter's impulse response length, and inspect the first 20 ms of the output.

Order selection and the edge-effect trap

Higher order gives sharper cutoff but longer impulse response, more edge transient, and greater sensitivity to the padding choice. For CFC 60 at 10 kHz, a 2nd-order design (4th-order effective) has an impulse response lasting tens of milliseconds; padding must cover that. A practical rule: choose the lowest order that meets the J211 tolerance envelope, then verify the first and last 50 ms of the filtered record against the unfiltered trend. If the filtered signal shows a non-physical ramp or overshoot at the boundaries, increase padlen or switch to padtype='even'.

The figure below shows the processing chain and the two failure modes to watch: passband ripple from an over-aggressive Chebyshev design, and edge transient from insufficient padding in filtfilt.

Crash signal filtering chain and failure modes Raw accel 10–20 kHz, noisy Design butter / cheby1 → SOS filtfilt zero-phase, padlen Verify −3 dB, edges, J211 HIC criteria Magnitude response frequency (log) gain (dB) −3 dB Butterworth (flat) Chebyshev I (ripple) Edge transient in filtfilt output time (ms) adequate padlen padlen too short startup artifact

Practical checklist for a compliant filter pass

  • Confirm the required CFC class from the test specification, and map it to the correct −3 dB frequency (CFC 60 → 100 Hz, CFC 180 → 300 Hz, CFC 600 → 1000 Hz, CFC 1000 → 1650 Hz).
  • Design in SOS form; never use ba for order ≥ 4.
  • Use filtfilt for offline analysis; remember the effective magnitude order doubles.
  • Set padlen explicitly and inspect the first and last 50 ms of the output for non-physical ramps.
  • Verify the realized −3 dB point with sosfreqz and compare the full magnitude response against the J211 tolerance envelope.
  • Record the filter parameters (family, order, cutoff, padlen, sample rate) alongside the processed channel — the filter is part of the result.

The most common failure in practice is not a wrong filter family but an unverified one: a 4th-order Butterworth at 100 Hz applied with default padding to a 20 kHz record, producing a 5–10 ms startup ramp that inflates or deflates the first HIC window. Always plot the filtered signal over the raw one at the boundaries before trusting any injury number derived from it.