4. Filter Head Acceleration Data for HIC Calculation

Why the Filter Choice Decides the HIC Result

HIC is computed from the resultant head acceleration magnitude, but the raw signal from a head accelerometer is never used directly. The raw trace contains high-frequency content that is not physically meaningful for head injury assessment: sensor resonance, cable vibration, mounting ringing, and electrical noise. If these components survive into the HIC integration, they inflate the peak acceleration and shift the time of the peak, which changes both the window selection and the reported HIC value. The standard remedy is a low-pass filter applied before any HIC calculation.

SAE J211 defines the channel filter classes used in automotive crash testing. For head acceleration in HIC computation, the relevant class is CFC 1000 (Channel Frequency Class 1000), which corresponds to a low-pass characteristic with a −3 dB cutoff at approximately 1650 Hz and a specified magnitude tolerance band up to 1000 Hz. Some legacy or OEM-specific procedures still reference CFC 600 or CFC 180 for head data; the filter class must always be taken from the test specification, not chosen by convenience. The practical task in this case is: apply the specified CFC filter correctly, then prove that the filtered trace still carries the true peak and that the noise has actually been removed.

The Filter as a Signal Chain, Not a Single Button

Filtering is a chain of decisions, and each one can silently corrupt the HIC. The raw record must first be checked for its sample rate and units, then the filter must be applied in the forward and reverse direction (zero-phase, filtfilt-style) so that no phase lag shifts the peak in time. A causal single-pass IIR filter introduces group delay that moves the acceleration peak later by a few milliseconds — enough to move the HIC window and change the result. The figure below shows the chain and the two verification points that matter.

Raw a(t) 3-axis, g or m/s² fs ≥ 10 kHz Resultant a_res = √(ax²+ay²+az²) before filtering CFC 1000 low-pass zero-phase (fwd + rev) fc ≈ 1650 Hz, −3 dB Filtered a_res(t) → HIC window search → HIC15 / HIC36 Check 1: Peak peak time shift ≤ 1 ms peak amplitude drop < 5% Check 2: Noise high-freq ripple removed pre-peak baseline flat Trace comparison (illustrative) time (ms) a (g) raw (noisy) filtered (CFC 1000) peak preserved Filter parameters (example) Class: CFC 1000 · fs = 20 kHz Order: 4 (2 passes) · zero-phase Pad length: ≥ 3 × filter settling Units: g → m/s² (×9.80665)

Applying the Filter in Practice

The following Python fragment implements the chain for a single head channel. It assumes the raw record is already loaded as three equal-length arrays in g at a known sample rate. The filter is a 4th-order Butterworth applied forward and backward, which yields an effective 8th-order zero-phase response and satisfies the CFC 1000 magnitude tolerance in the passband. The cutoff is set from the CFC class, not guessed.

import numpy as np
from scipy.signal import butter, filtfilt

G = 9.80665  # m/s^2 per g

def cfc_cutoff(cfc_class):
    # SAE J211 CFC classes: cutoff = CFC / 0.6 (approx -3 dB point)
    return cfc_class / 0.6

def filter_head_accel(ax, ay, az, fs, cfc_class=1000, order=4):
    a_res = np.sqrt(ax**2 + ay**2 + az**2) * G   # resultant in m/s^2
    fc = cfc_cutoff(cfc_class)                    # 1666.7 Hz for CFC 1000
    wn = fc / (fs / 2)                            # normalized to Nyquist
    if wn >= 1.0:
        raise ValueError(f"fs={fs} Hz too low for CFC {cfc_class}")
    b, a = butter(order, wn, btype="low", analog=False)
    padlen = min(len(a_res) - 1, int(3 * fs / fc * 10))
    a_filt = filtfilt(b, a, a_res, padlen=padlen)
    return a_res, a_filt

# Example: 20 kHz record, 200 ms event
fs = 20000
t = np.arange(0, 0.2, 1/fs)
# synthetic pulse: 80 g half-sine over 40 ms + 5 g noise at 3 kHz
pulse = 80 * np.sin(np.pi * np.clip(t, 0.05, 0.09) / 0.04) * ((t >= 0.05) & (t <= 0.09))
noise = 5 * np.sin(2 * np.pi * 3000 * t)
ax = pulse + noise
ay = np.zeros_like(t)
az = np.zeros_like(t)

raw, filt = filter_head_accel(ax, ay, az, fs, cfc_class=1000)
print(f"raw peak  = {raw.max()/G:6.2f} g at {t[raw.argmax()]*1000:6.2f} ms")
print(f"filt peak = {filt.max()/G:6.2f} g at {t[filt.argmax()]*1000:6.2f} ms")

With the synthetic input above, the raw resultant peaks near 85 g because the 3 kHz noise rides on top of the 80 g pulse. After CFC 1000 filtering, the peak should return to approximately 80 g and the peak time should stay within about 1 ms of the pulse center. Those two numbers are the acceptance criteria for the filter step, and they must be checked before any HIC window is searched.

Do not filter the three axes independently and then take the resultant. Filtering is a linear operation, so filtering the resultant is equivalent and cheaper, but filtering each axis and then combining is only equivalent if the same filter is applied to all three. Mixing filter classes across axes, or filtering the resultant with a different class than the axes, produces a trace that no longer matches the test specification.

Verifying Peak Preservation and Noise Removal

Two checks close the loop. First, compare the peak amplitude and peak time of the raw and filtered resultants. A drop of more than about 5% in amplitude, or a shift of more than 1 ms in peak time, indicates the cutoff is too low or the filter order is too aggressive for the event duration. Second, inspect the pre-peak baseline: on a properly filtered trace the baseline before airbag contact should be flat within a few tenths of a g, while the raw trace will show visible high-frequency ripple. If the filtered baseline still oscillates, the filter did not remove the noise band and the CFC class or sample rate should be re-examined.

A common failure is applying the filter to a record whose sample rate is too low. CFC 1000 requires a sample rate well above 2 × 1650 Hz; 10 kHz is a practical minimum and 20 kHz is typical. If the record is at 5 kHz, the normalized cutoff approaches Nyquist and the Butterworth response becomes ill-conditioned, producing a filtered trace that either rings or attenuates the true peak. In that situation the correct action is to flag the record as under-sampled for CFC 1000 rather than to lower the filter class silently.

CheckAcceptance criterionFailure symptomLikely cause
Peak amplitudeFiltered peak within 5% of raw peakPeak drops 10–20%Cutoff too low or order too high
Peak timeShift ≤ 1 msPeak moves 3–5 ms laterCausal single-pass filter (group delay)
Baseline flatnessPre-contact ripple < 0.5 gVisible 2–5 kHz ripple remainsWrong CFC class or filter not applied
Sample ratefs ≥ 10 kHz for CFC 1000Ringing or peak attenuationUnder-sampled record
Keep the raw and filtered resultants side by side in the test report. The filtered trace is what feeds HIC, but the raw trace is the evidence that the filter did not manufacture or destroy the peak. Reviewers and correlation engineers will ask for both.

What the Filtered Trace Must Deliver to HIC

Once the two checks pass, the filtered resultant is the input to the HIC window search. The filter step does not compute HIC itself; its job is to guarantee that the trace handed forward has a physically meaningful peak at the correct time and a clean baseline. If the peak is preserved and the noise is gone, the subsequent 15 ms and 36 ms window search will select the same dominant loading phase that the raw event actually contained, and the reported HIC will be defensible. If either check fails, the HIC value is not wrong by a small margin — it is wrong by an amount that depends on how much noise survived, which is exactly the kind of error that makes airbag interaction troubleshooting unreliable.