filter — Apply IIR/FIR digital filters in MATLAB and RunMat.
filter(b, a, X) applies a causal digital filter defined by numerator coefficients b and denominator coefficients a. By default, filtering runs along the first non-singleton dimension, and coefficients are normalized internally so a(1) is 1. Optional initial conditions and explicit dimension selection follow MATLAB semantics.
Syntax
y = filter(b, a, x)
y = filter(b, a, x, zi)
y = filter(b, a, x, zi, dim)
[y, zf] = filter(b, a, x)
[y, zf] = filter(b, a, x, zi)
[y, zf] = filter(b, a, x, zi, dim)Inputs
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
b | Any | Yes | — | Numerator coefficient vector. |
a | Any | Yes | — | Denominator coefficient vector. |
x | Any | Yes | — | Signal values to filter. |
zi | Any | No | [] | Initial filter state (use [] for default zero state). |
dim | NumericScalar | No | first non-singleton dimension | Dimension to operate along. |
Returns
| Name | Type | Description |
|---|---|---|
y | NumericArray | Filtered signal output. |
zf | NumericArray | Final filter state for warm-starting a subsequent call. |
Returned values from filter depend on how many outputs the caller requests.
Errors
| Identifier | When | Message |
|---|---|---|
RunMat:filter:ArgCount | More than five input arguments are provided. | filter: expected between three and five input arguments |
RunMat:filter:InvalidDimension | dim is missing, non-numeric, non-integer, or less than one. | filter: dimension must be numeric and >= 1 |
RunMat:filter:EmptyDenominator | Denominator coefficient vector is empty. | filter: denominator coefficients cannot be empty |
RunMat:filter:EmptyNumerator | Numerator coefficient vector is empty. | filter: numerator coefficients cannot be empty |
RunMat:filter:InvalidCoefficients | Coefficient inputs are non-numeric or non-vector values. | filter: invalid coefficient input |
RunMat:filter:InvalidSignal | Signal input is non-numeric/logical. | filter: invalid signal input |
RunMat:filter:InvalidInitialState | Initial state input is invalid for current filter/order configuration. | filter: invalid initial state input |
RunMat:filter:DenominatorLeadingZero | The leading denominator coefficient a(1) is zero. | filter: denominator coefficient a(1) must be non-zero |
RunMat:filter:GatherFailed | GPU values fail to gather for host normalization/fallback. | filter: failed to gather GPU value |
RunMat:filter:ProviderUploadFailed | Provider-side upload for coefficients or initial state fails. | filter: failed to upload provider input |
RunMat:filter:Internal | Internal tensor/state/index processing fails. | filter: internal error |
How filter works
filter(b, a, X)applies the filter along the first non-singleton dimension ofX(column-wise for matrices).- The numerator
band denominatoramust be non-empty vectors.a(1)must be non-zero; the runtime divides both coefficient vectors bya(1)automatically. - Optional initial conditions
zimust have the same size as the outputzf(the dimension being filtered is replaced bymax(numel(b), numel(a)) - 1). Use[]to indicate zero initial state. filter(b, a, X, zi, dim)processesXalong dimensiondim. Dimensions beyondndims(X)are treated as length-one axes, exactly as in MATLAB.- Complex coefficients or inputs are supported; results follow MATLAB semantics for real/imaginary propagation.
- The function returns a single output
yby default. Request two outputs ([y, zf] = filter(...)) to obtain the final internal stateszf.
Does RunMat run filter on the GPU?
The input signal already resides on the GPU (for example, via gpuArray) and all operands are real-valued.
The active provider implements iir_filter (both the in-process provider and the WGPU backend do).
Under those conditions the entire evaluation—including final-state propagation—stays on the device. If the hook is absent, or if any operand is complex, RunMat transparently gathers to the host, evaluates the filter with the scalar reference implementation, and returns MATLAB-compatible results. Auto-offload and fusion residency reuse the same hook, so high-level code does not need to differentiate between CPU and GPU execution.
Examples
Smoothing a signal with an FIR moving-average filter
b = ones(1, 3) / 3;
a = 1;
x = [1 5 2 0 3];
y = filter(b, a, x)Expected output:
y =
0.3333 2.0000 2.6667 2.3333 1.6667Applying a first-order IIR low-pass filter
alpha = 0.8;
b = 1 - alpha;
a = [1 -alpha];
imp = [1 zeros(1, 4)];
y = filter(b, a, imp)Expected output:
y =
0.2000 0.1600 0.1280 0.1024 0.0819Continuing a filtered stream with explicit initial conditions
b = ones(1, 3) / 3;
a = 1;
x1 = [1 5 2];
[y1, zf] = filter(b, a, x1); % First chunk
x2 = [0 3];
[y2, zf2] = filter(b, a, x2, zf); % Resume with stored stateExpected output:
y1 = [0.3333 2.0000 2.6667]
zf = [2.3333 0.6667]
y2 = [2.3333 1.6667]
zf2 = [1.0000 1.0000]Filtering along matrix rows (dimension 2)
X = [1 2 3 4;
0 1 0 1];
b = [1 -1]; % simple differentiator
a = 1;
Y = filter(b, a, X, [], 2)Expected output:
Y =
1 1 1 1
0 1 -1 1Filtering complex-valued data
b = [1 1i];
a = 1;
t = 0:3;
x = exp(1i * pi/4 * t);
y = filter(b, a, x)Expected output:
y =
1.0000 + 0.0000i 0.7071 + 1.7071i -0.7071 + 1.7071i -1.7071 + 0.7071iExecuting a real filter on the GPU
g = gpuArray([1 5 2 0 3]);
b = ones(1, 3) / 3;
a = 1;
[y_gpu, zf_gpu] = filter(b, a, g);
y = gather(y_gpu)Expected output:
y =
0.3333 2.0000 2.6667 2.3333 1.6667Using filter with coding agents
Open a RunMat example with live inputs, then ask the agent to explain how filter changes the result.
Run a small filter example, explain the result, then change one input and compare the output.
FAQ
What happens if a(1) is not 1.0?⌄
RunMat (like MATLAB) divides every coefficient in a and b by a(1) internally so that a(1) becomes 1. You only need to ensure a(1) is non-zero.
How large should zi be?⌄
zi must have the same size as zf (the returned final state). Replace the filtered dimension with max(numel(b), numel(a)) - 1; all other dimensions match X. Use [] for a zero state.
Can I filter along a dimension greater than ndims(X)?⌄
Yes. Just like MATLAB, RunMat treats missing higher dimensions as length-one axes. filter(b, a, X, [], 5) is valid even if X is a vector.
Does filter support complex coefficients or signals?⌄
Absolutely. The host implementation handles complex arithmetic exactly. GPU acceleration is currently limited to real-valued filters; complex inputs fall back to the CPU automatically.
Do I need to initialise the GPU path manually?⌄
No. If the signal is a gpuArray value and the active provider supports iir_filter, RunMat keeps the entire computation on the device. Otherwise, the runtime gathers operands to the host, ensuring MATLAB-compatible results without extra user code.
What shape does zf have?⌄
zf matches zi (or the default zero state). The filtered dimension is replaced by max(numel(b), numel(a)) - 1; other dimensions mirror the input.
How are empty signals handled?⌄
When X is empty, y is empty and zf equals the supplied zi (or zeros). No arithmetic is performed, matching MATLAB.
Are logical and integer inputs supported?⌄
Yes. They are promoted to double precision before filtering, exactly as in MATLAB.
How do I resume filtering a long stream chunk-by-chunk?⌄
Call [y, zf] = filter(...) on each chunk and pass zf as the fourth argument for the next chunk. The example above shows the pattern.
Can I accelerate filtering with the planner’s auto-offload?⌄
The planner leverages the same provider hook under the hood. As long as the operands are real and the provider implements iir_filter, auto-offload keeps the filter on the GPU.
Related Math functions
Elementwise
abs · angle · complex · conj · double · exp · expm1 · factorial · gamma · hypot · imag · ldivide · log · log10 · log1p · log2 · minus · nextpow2 · plus · pow2 · power · rdivide · real · sign · single · sqrt · times
Trigonometry
acos · acosh · asin · asinh · atan · atan2 · atanh · cos · cosd · cosh · deg2rad · rad2deg · sin · sind · sinh · tan · tand · tanh
Reduction
all · any · cummax · cummin · cumprod · cumsum · cumtrapz · diff · gradient · max · mean · median · min · nnz · prod · std · sum · trapz · var
Structure
Open-source implementation
Unlike proprietary runtimes, every RunMat function is open-source. Read exactly how filter is executed, line by line, in Rust.
- View the source for filter in Rust on GitHub
- Learn how the RunMat runtime works
- Found a bug? Open an issue with a minimal reproduction.
About RunMat
RunMat is an open-source runtime that executes MATLAB-syntax code blazing on any GPU. It is licensed under the Apache 2.0 license.
- RunMat automatically optimizes your math for GPU execution on Apple, Nvidia, and AMD hardware. No code changes needed. Simulations that took hours now take minutes.
- Start running code in seconds. RunMat runs in the browser, on the desktop, or from the CLI. No license server, no IT ticket.