FIRFilter

FIRFilter filters a signal with a weighted sum of its last few samples.
3.30–3.34

FIRFilter filters a signal with a weighted sum of its last few samples. It has no feedback, which makes it unconditionally stable: no coefficient set you can write will make it run away. That is the reason to choose it over a coefficient-driven filter with feedback, and the trade is cost — matching the same roll-off takes many more taps. It is single channel: one instance filters one signal.

flowchart LR
    i1(["input — signal to filter"]) --> B["FIRFilter"]
    i2(["disable"]) --> B
    B --> o1(["output — filtered signal"])
    B --> o2(["isEnabled"])

The filter computes $y[k] = h_0,u[k] + h_1,u[k-1] + \dots + h_N,u[k-N]$, with $h$ = coefficients. DC gain is the sum of the coefficients, so an averaging filter needs $1/M$ in each of its $M$ taps. A symmetric coefficient set delays the signal by exactly half the tap count, with perfectly linear phase. A step settles completely after one tap count and never overshoots for non-negative coefficients. The coefficients are defined in samples, not seconds, so the same set on a different task rate is a different filter.

The tap count is fixed when the machine is built and cannot be changed at runtime. This block also has no reset — see Limits and errors.

Signals

Inputs

Path Unit Range Description
input signal unit unbounded The signal to filter. A single value, not an array.
disable - - True bypasses the filter: input passes straight to output. Use it for a runtime override from a supervisor; use enable for the configured intent.

Outputs

Path Unit Description
output signal unit × the DC gain The filtered signal, a single value. Equals input exactly while bypassed. Starts from zero after every controller start and reaches its true value after one tap count of samples.
isEnabled - True when enable is true and disable is false. A single value for the whole block.

Parameters

Path Unit Default Range Effect
coefficients - 1 in the first tap, 0 in the rest any The taps, most recent sample first. All of them are always used — writing zeros into the tail is the only way to shorten the filter, and it does not make it cheaper. Check the DC gain after every change.
enable - true - False bypasses the filter: input passes through unchanged.

Both parameters are persistent and survive a controller restart, which is how a filter design ships with a machine. No parameters exist below this block.

Setup

  1. Design your filter against your task period. A 1 ms task is 1000 samples per second, so a six-tap filter spans 6 ms.

  2. Read the length of the coefficients array from the parameter tree. That is your tap count, and it is fixed when the machine is built.

  3. Link the source signal into input and confirm on a trace that input follows the source.

  4. Set enable false. output equals input sample for sample and isEnabled reads false.

  5. Write the whole coefficients array, including any trailing zeros. A short write leaves the old values in the tail, and they keep filtering.

    Step 5 must cover every tap. A leftover coefficient in the tail is the most common misconfiguration of this block, and it shows up as a filter that behaves almost right.

  6. Set enable true and confirm isEnabled reads true.

  7. Feed a constant into input and read output. Divide the two: the ratio must equal the sum of your coefficients.

  8. Step the input and count the samples until output stops moving. It must be exactly the tap count; anything longer means a coefficient is in a tap you did not intend.

Tuning

There is nothing to tune here in the usual sense. The work is choosing the coefficients and verifying them on the machine.

  1. Fix the task period before you design anything. Every coefficient depends on it. If the task rate changes later, redesign the whole set — no parameter in this block rescales for you.
  2. For plain noise reduction, start with an equal-weight average: $1/M$ in each of $M$ taps. It is the simplest set that works and its DC gain is exactly 1.
  3. For less ripple at the cost of a slightly wider response, taper the weights toward the ends — triangular weights are the usual next step.
  4. Keep the coefficients symmetric if two filtered signals have to stay in step with each other. Symmetry is what buys exactly linear phase.
  5. Measure the delay you have bought: half the tap count, in samples, for a symmetric set. Keep it below a tenth of the response time of the loop consuming output.
  6. Verify the DC gain by summing the coefficients. It should be 1 for a filter that is not meant to change the signal’s size.
  7. Re-verify after any task-rate change, starting from step 1.

Step response for three coefficient sets: pass-through reaches 1 on the firstsample, a five-tap equal-weight average climbs in five equal steps, andtriangular weights climb in unequal steps to the samevalue.

Read the settling time off any curve as the sample it first reaches 1.

Symptom Cause Action
output is a constant multiple of what you expected The coefficients do not sum to 1 Divide every coefficient by their sum
The filter behaves almost right but not quite A leftover coefficient in the tail of the array Write the whole array including trailing zeros, then re-check step 8 of Setup
output settles more slowly than the tap count A non-zero coefficient sits in a tap you did not intend Write zeros over the whole array, then write your set
Writing zeros into the tail did not make the block cheaper Expected: every tap is computed regardless of its value Size the instance to the requirement when the machine is built
The filter behaves nothing like the design The design assumed a different sample rate Redesign at the controller’s actual task period
The filter changed behaviour after a task-rate change Expected: the coefficients are defined in samples, not seconds Redesign the whole set for the new rate
Two filtered signals drifted out of step The coefficient sets are not both symmetric, or not the same length Use symmetric sets of equal length on both
A short glitch on output for a few samples after re-enabling Expected: the filter still holds the samples from before the bypass Wait one tap count, or gate the consumer off isEnabled plus that long
output ramps up from zero for a few samples after every start Expected: the filter memory starts empty Gate the consumer off isEnabled plus one tap count
You cannot flush the filter’s memory There is no reset in this block Bypass and re-enable, then wait one tap count
output went to a non-numeric value A non-numeric value reached input or a coefficient Fix the source; the value clears itself after one tap count
You need more taps than the instance has The tap count is fixed when the machine is built It cannot be changed at runtime; it needs a configuration change
You need to filter several axes Not possible — this block is single channel Use one instance per axis

A five-tap equal-weight average in a six-tap instance, which smooths without changing the signal’s size:

coefficients = 0.2, 0.2, 0.2, 0.2, 0.2, 0.0
enable       = true

A pass-through, which is also what the block ships with:

coefficients = 1.0, 0.0, 0.0, 0.0, 0.0, 0.0

Limits and errors

Limit Set by What happens Reported
Filter stability Guaranteed The block has no feedback, so no coefficient set can make it diverge. This is why you would choose it Not applicable
DC gain Nothing Not normalised and not checked. Whatever the coefficients sum to is the gain you get Not reported
Tap count Machine configuration Fixed when the machine is built. A longer coefficient write has its tail dropped; a shorter one leaves the old tail in place and keeps using it Not reported
Filter memory Nothing There is no reset input. Bypassing the block and re-enabling it is the only way to flush it, and it takes one tap count to clear Not reported
output Nothing Unbounded. Limit it downstream if the consumer needs a bound Not reported
Channel count Fixed One channel per instance, always Not reported

The block raises no errors or warnings and logs nothing. Every failure above shows as a value on a trace, not as a message.


Verified against motorcortex-control3 3.30.0 (bc348fd).