4. Digital filtering standards and practices

Every acceleration, force, and displacement channel recorded during a crash test passes through an analog anti-alias stage and then a digital low-pass filter before it is used for injury criteria. The filter is not a cosmetic smoothing step: it defines the frequency content that the injury metric is allowed to "see," and therefore it directly changes peak values, pulse durations, and the resulting HIC, chest deflection, or femur load numbers. SAE J211/1 and ISO 6487 define a small family of standardized channel filter classes — CFC 60, 180, 600, and 1000 — so that a HIC computed from one laboratory's data is comparable with another's. This chapter explains what those classes actually specify, how to implement them correctly, and why phase correction is mandatory rather than optional.

What a Channel Filter Class Actually Specifies

CFC stands for Channel Frequency Class. The standard does not simply say "low-pass at 60 Hz." Instead it defines a class by a tolerance band on the frequency response of a second-order (two-pole) Butterworth-type low-pass filter, referenced to the class frequency fc (also written FH). The key anchor points are:

  • At f = fc, the gain must lie within a defined band around −3 dB (the exact tolerance is given in the standard's table, typically roughly −3 dB ±0.5 dB depending on class).
  • At f = 2·fc, the attenuation must be at least a specified minimum (for CFC 60 this is on the order of −30 dB).
  • At f = 3·fc and above, further attenuation is required, and the stopband behavior is bounded.

The practical consequence is that a compliant CFC 60 filter is not just "any 60 Hz low-pass." A first-order RC filter, a moving average, or a steep elliptic filter will all fail the tolerance mask even if their −3 dB point sits at 60 Hz. The standard's intent is a specific phase and magnitude shape so that the time-domain pulse is preserved in a known way.

ClassClass frequency fcTypical useSampling rate guidance
CFC 6060 HzHead CG acceleration (HIC), chest acceleration, pelvis acceleration≥ 600 Hz (≥10× fc)
CFC 180180 HzSome chest/thorax channels, certain restraint forces≥ 1800 Hz
CFC 600600 HzHigh-rate force channels, some neck loads≥ 6000 Hz
CFC 10001000 HzVery fast transients, contact forces, some component tests≥ 10000 Hz

The sampling-rate column is a practical rule, not a standard clause: you need enough oversampling that the digital filter's own transition band and the anti-alias stage do not distort the passband. A CFC 60 channel sampled at 200 Hz is technically possible but leaves almost no margin and is a common source of "why does my HIC differ from the reference lab" disputes.

Implementing the Filter: The Standard's Difference Equation

SAE J211/1 gives an explicit recursive formulation so that different software produces the same result. For a second-order class filter, the standard defines the transfer function in terms of a normalized frequency and provides coefficients that can be applied as a direct-form II biquad. A widely used implementation (matching the standard's published coefficients) is:

# Second-order CFC low-pass, per SAE J211/1 formulation
# w = 2*pi*fc / fs   (normalized angular class frequency)
# a = tan(w/2) ... coefficient derivation per standard
# Applied as: y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2]
#                    - a1*y[n-1] - a2*y[n-2]

import math

def cfc_coeffs(fc, fs):
    w = 2.0 * math.pi * fc / fs
    # standard's damping/coefficient set for the two-pole class filter
    alpha = math.sin(w) / (2.0 * 0.7071)   # Q = 1/sqrt(2) Butterworth
    b0 = (1 - math.cos(w)) / 2.0
    b1 = 1 - math.cos(w)
    b2 = b0
    a0 = 1 + alpha
    a1 = -2 * math.cos(w)
    a2 = 1 - alpha
    return (b0/a0, b1/a0, b2/a0, a1/a0, a2/a0)

def apply_cfc(x, fc, fs):
    b0, b1, b2, a1, a2 = cfc_coeffs(fc, fs)
    y = [0.0] * len(x)
    x1 = x2 = y1 = y2 = 0.0
    for n, xn in enumerate(x):
        yn = b0*xn + b1*x1 + b2*x2 - a1*y1 - a2*y2
        y[n] = yn
        x2, x1 = x1, xn
        y2, y1 = y1, yn
    return y

Two implementation details matter more than the coefficient arithmetic. First, the filter must be initialized so that the first samples are not contaminated by a zero-state transient; the standard practice is to run the filter forward and backward (filtfilt-style) or to pre-pad with the first sample value. Second, the filter must be applied to the raw channel after offset removal and before any integration or differentiation, because differentiating a filtered signal changes the effective filter order.

Do not substitute a generic scipy.signal.butter(2, fc/(fs/2)) call and assume compliance. The bilinear-transform Butterworth you get from a generic library is close but not identical to the standard's coefficient set, and the difference shows up as a few percent in peak acceleration on sharp pulses — enough to shift a HIC value across a regulatory threshold.

Phase Correction: Why It Is Not Optional

A causal IIR filter delays the signal, and the delay is frequency-dependent. A sharp acceleration pulse contains many frequencies; after a causal CFC 60 filter, the high-frequency components lag the low-frequency ones, so the filtered pulse is both attenuated and skewed. Peak acceleration is reduced and shifted later in time. For HIC, which integrates a(t)2.5 over a window, a skewed pulse changes the integral even when the peak looks acceptable.

Phase correction means applying the filter in a zero-phase manner: filter forward, reverse the result, filter again, reverse back. The magnitude response is squared (so the effective attenuation is doubled) and the phase response cancels. The standard therefore specifies that the phase-corrected filter is the reference for injury criteria, and the magnitude tolerance is defined for the phase-corrected response. In practice:

  1. Remove the DC offset (mean of a pre-trigger quiet window).
  2. Apply the CFC filter forward and backward (zero-phase).
  3. Verify the result against the standard's tolerance mask using a swept-sine or impulse test signal.
  4. Only then compute HIC, 3 ms clip, or other criteria.
Signal chain for a CFC-filtered injury channel Raw channel accel / force Offset removal pre-trigger mean CFC low-pass forward + reverse Tolerance check swept sine / impulse Injury criteria HIC, 3 ms clip Effect of phase correction on a sharp pulse (illustrative) time (ms) a causal filter: peak reduced, delayed zero-phase: peak preserved, aligned phase-corrected (reference) causal only (not for criteria)

Verification and Common Failure Modes

Before trusting a CFC channel, verify the implementation with a known test signal. A practical check is to feed a unit-amplitude swept sine from 0.1·fc to 10·fc through the filter and compare the measured gain at fc, 2·fc, and 3·fc against the standard's tolerance table. A compliant CFC 60 phase-corrected filter should show roughly −3 dB at 60 Hz, at least −30 dB at 120 Hz, and deeper attenuation at 180 Hz. If your measured attenuation at 2·fc is only −12 dB, you have almost certainly used a first-order filter or a generic Butterworth with the wrong Q.

Three failure modes account for most real-world discrepancies. Wrong class for the channel: applying CFC 180 to a head CG channel that the test protocol specifies as CFC 60 will raise the peak and inflate HIC; the fix is to read the protocol's channel table, not to "pick the smoothest-looking" filter. Filtering after integration: integrating raw acceleration and then filtering the velocity produces a different result from filtering acceleration and then integrating; the standard order is filter first. Missing phase correction: a causal-only filter shifts the peak by several milliseconds on a 60 Hz channel, which is enough to move the HIC window and change the reported value by a few percent.

Record the filter class, the phase-correction flag, and the sampling rate in the channel metadata alongside every exported dataset. When two labs disagree on a HIC value, the first question is always whether both applied the same CFC class with zero-phase correction — and the metadata is what settles it.

The discipline is straightforward once internalized: identify the class from the test protocol, remove offset, apply the standard's second-order filter forward and backward, verify against the tolerance mask, and only then compute injury criteria. The filter class is part of the measurement definition, not a post-processing preference, and phase correction is what makes the time-domain pulse — and therefore the injury number — reproducible across laboratories and software tools.