4. Neck Force and Moment Signal Filtering per SAE J211

Why the Filter Class Changes the Nij You Report

Raw neck load cell data from a sled or crash test contains high-frequency content that is not physically meaningful for injury assessment: structural ringing of the dummy neck, load cell resonance, and electrical noise from the data acquisition chain. SAE J211/1 defines channel frequency classes (CFC) as standardized low-pass filters so that different laboratories, dummies, and test setups produce comparable signals. For neck force and moment channels used in Nij, the conventional class is CFC 600 for the upper-neck load cell in most automotive crash applications, while some programs specify CFC 1000 for the same channels. The filter class is not a cosmetic choice: it directly shifts the peak force, the peak moment, and therefore the peak Nij and its timestamp.

This case takes a raw six-channel upper-neck load cell record, applies CFC 600 and CFC 1000 filtering, and compares the resulting Nij peaks against the unfiltered signal. The goal is to document, with numbers, how much the filter class moves the injury metric and to establish a defensible reporting convention.

Input Data and Channel Definition

The example uses a synthetic but physically plausible frontal sled pulse sampled at 10 kHz. The upper-neck load cell provides Fx, Fy, Fz, Mx, My, Mz at the occipital condyle. For a frontal impact with the occupant facing forward, the Nij-relevant components are:

  • Fz — axial force (tension positive, compression negative)
  • My — bending moment about the lateral axis (flexion/extension)

The normalization constants used here are the standard adult-male values from the Nij formulation: F_int = 6800 N (tension) / F_int = 6160 N (compression), and M_int = 310 N·m (extension) / M_int = 135 N·m (flexion). These are held fixed across all filter classes so that the only variable is the filter itself.

Reference convention: Fz is positive in tension (neck pulled upward), My is positive in extension (head rotating backward relative to the neck). Nij is computed as the maximum over the pulse of:

Nij = Fz / F_int + My / M_int

using the tension-extension combination for the frontal case, with the compression-flexion combination evaluated separately and the larger of the two reported.

Implementing the SAE J211 CFC Filter

SAE J211/1 specifies a second-order Butterworth low-pass filter applied in both forward and reverse directions (zero-phase, filtfilt) so that no phase shift is introduced into the time history. The cutoff frequency for each class is derived from the class number:

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

def sae_j211_cfc(signal, dt, cfc):
    """Apply SAE J211/1 channel frequency class filter (zero-phase)."""
    # SAE J211 cutoff: fc = CFC / (2 * sqrt(2) * pi) ... but the standard
    # defines the -3 dB point at CFC * 0.6 approximately; use the
    # documented relationship fc = CFC / (2*pi) * sqrt(2) for the
    # Butterworth -3dB corner at the class frequency.
    fc = cfc / (2.0 * np.sqrt(2.0) * np.pi) * 2.0 * np.pi  # = cfc rad/s
    # Practical implementation: corner at CFC Hz for the 2nd-order Butterworth
    wn = cfc / (0.5 * 1.0 / dt)  # normalized to Nyquist
    b, a = butter(2, wn, btype='low')
    return filtfilt(b, a, signal)

# Example: CFC 600 on a 10 kHz channel
dt = 1e-4
fz_raw = np.loadtxt('fz_raw.csv')   # N, tension positive
my_raw = np.loadtxt('my_raw.csv')   # N·m, extension positive

fz_600 = sae_j211_cfc(fz_raw, dt, 600)
my_600 = sae_j211_cfc(my_raw, dt, 600)
fz_1000 = sae_j211_cfc(fz_raw, dt, 1000)
my_1000 = sae_j211_cfc(my_raw, dt, 1000)

The key implementation detail is the zero-phase requirement: a causal IIR filter would delay the peak by several milliseconds and misalign Fz and My, which corrupts the Nij sum. filtfilt applies the filter forward and backward, cancelling the phase response. The effective order doubles, so a 2nd-order Butterworth becomes a 4th-order zero-phase response — this is the SAE J211 convention and must not be "corrected" by using a 4th-order causal filter instead.

Do not apply the filter to the already-computed Nij time history. SAE J211 filtering is defined on the raw channel signals (force and moment) before any nonlinear combination. Filtering Nij directly produces a different, non-compliant result because Nij is a sum of two independently filtered channels, not a linear channel of its own.

Comparing Unfiltered, CFC 600, and CFC 1000 Peaks

Running the three conditions on the same record gives the following peak values. The unfiltered column is shown only for reference — it is not a reportable Nij under SAE J211.

Condition Peak Fz (N) Peak My (N·m) Peak Nij t_peak (ms)
Unfiltered 4120 198 1.24 71.3
CFC 1000 3985 191 1.20 71.8
CFC 600 3810 183 1.15 72.4

The pattern is consistent and worth internalizing: lower CFC class → lower peak, because the filter removes more of the high-frequency content that inflates the raw peak. The unfiltered Nij of 1.24 overstates the injury metric by roughly 8% relative to CFC 600. The peak timestamp also shifts later as the class decreases, because the zero-phase filter smooths the rising edge and the maximum lands on the smoothed crest rather than the raw spike.

Raw load cell Fz, My @ 10 kHz structural ringing + electrical noise CFC 1000 2nd-order Butterworth zero-phase (filtfilt) CFC 600 2nd-order Butterworth zero-phase (filtfilt) Nij sum Fz/F_int + My/M_int peak over pulse Peak Nij unfiltered 1.24 CFC 1000 1.20 CFC 600 1.15 Δ = 8% (raw vs CFC 600) t_peak shifts 71.3 → 72.4 ms Filter class is applied to raw Fz and My before the Nij sum; lower CFC lowers the reported peak.

Documenting the Effect for Injury Diagnosis

The comparison above is the deliverable for this case. To make it defensible in a test report, record the following for each filter class:

  • The CFC number and the filter implementation (order, zero-phase, cutoff derivation).
  • Peak Fz, peak My, peak Nij, and the timestamp of each peak.
  • The percentage change in peak Nij relative to the unfiltered signal and relative to the other class.
  • Whether the Nij threshold (commonly 1.0 for AIS 3+ neck injury risk in the standard formulation) is crossed, and whether the crossing is filter-dependent.

In this example, all three conditions exceed Nij = 1.0, so the injury conclusion is robust to filter class. That is the useful diagnostic outcome: the filter changes the magnitude by about 8% but does not change the pass/fail decision. If the unfiltered Nij were 1.02 and the CFC 600 Nij were 0.96, the filter class would flip the conclusion — and that is exactly the situation where the reporting convention must be stated explicitly and the raw signal must be retained for audit.

Reporting convention: State the CFC class in the channel metadata, not in a footnote. A Nij value without its filter class is not a reproducible result. When comparing across labs or test series, confirm both use the same class before drawing conclusions about occupant severity.

Verification and Common Failure Symptoms

Verify the filter implementation before trusting the peak comparison:

  1. Impulse response check: feed a unit impulse through sae_j211_cfc and confirm the output is symmetric (zero-phase) and decays without ringing beyond the expected Butterworth response.
  2. Cutoff check: feed a sine sweep and confirm the −3 dB point lands at the class frequency (600 Hz or 1000 Hz) within tolerance.
  3. Peak monotonicity: confirm peak Nij decreases as CFC decreases. A violation usually means the filter was applied causally, or applied to Nij instead of the raw channels.

Typical failure symptoms: peak Nij increases after filtering (causal filter misalignment of Fz and My), peak timestamp jumps by more than a few milliseconds (phase shift not cancelled), or the filtered signal shows a DC offset (improper initial conditions in filtfilt — pad the signal or detrend first). Each of these points to a specific implementation error rather than a data problem, which is why the verification steps belong in the workflow, not in a post-hoc review.