FIRFilter Icon
FIRFilter
Finite impulse response (FIR) filter with the input-output relation
\[y(k) = \sum_{i=1}^{n} c_i u(k-i+1)\]
corresponding to the transfer function
\[H(z) = \sum_{i=1}^{n} c_i z^{-(i-1)}\]
where $c$ is coeffs. The filter has no feedback, so it is stable for any coefficients and its impulse response is coeffs, of length n. The sample period is that of the connected clock.
MovingAverageFilter is the special case in which all coefficients equal $1/n$, which is also the default here.
The initial condition is selected through the initialization enum. The state of the filter is the input history, so every variant describes the $n-1$ input samples that precede the first one:
InitialState(x0)sets all of them tox0. This is the default, with $x_0 = 0$, which is the usual convention for FIR filtering: the output is the convolution of the input withcoeffs, the input being extended by zeros before its first sample.InitialOutput(y0)sets them to the common level that makes the first output equaly0. This requires the coefficients other than the first to have a nonzero sum, $\sum_{i=2}^{n} c_i \neq 0$.SteadyStatesets them to the first input sample, as if the input had been constant up to that point, so the first output is the DC response $u(1) \sum_{i=1}^{n} c_i$.InitialStateArray(x0)sets the sample delayed by $i$ samples tox0[i], which is the only variant that admits an input history that is not constant.
The single-tap case $n = 1$ has no input history and ignores initialization.
Usage
DiscreteComponents.FIRFilter(coeffs=fill(1.0 / n, n), u_init=_ic_state_level(initialization))
Parameters:
| Name | Description | Units | Default value |
|---|---|---|---|
n | Number of filter taps | – | 2 |
initialization | Initial-condition specification | – | DiscreteCom...e(; x0=0.0) |
nd | Number of delayed taps, one less than the number of coefficients | – | n - 1 |
coeffs | Filter coefficients; coeffs[i] multiplies the input delayed by i-1 samples | – | fill(1.0 / n, n) |
Connectors
u- This connector represents a real signal as an input to a component (RealInput)y- This connector represents a real signal as an output from a component (RealOutput)
Variables
| Name | Description | Units |
|---|---|---|
cu | Products coeffs[i]*u(k-i+1) | – |
Behavior
using DiscreteComponents #hide
using ModelingToolkit #hide
@variables coeffs #hide
@named sys = DiscreteComponents.FIRFilter(coeffs=coeffs) #hide
full_equations(sys) #hideSource
"""
Finite impulse response (FIR) filter with the input-output relation
```math
y(k) = \sum_{i=1}^{n} c_i u(k-i+1)
```
corresponding to the transfer function
```math
H(z) = \sum_{i=1}^{n} c_i z^{-(i-1)}
```
where ``c`` is `coeffs`. The filter has no feedback, so it is stable for any coefficients
and its impulse response is `coeffs`, of length `n`. The sample period is that of the
connected clock.
`MovingAverageFilter` is the special case in which all coefficients equal ``1/n``, which
is also the default here.
The initial condition is selected through the `initialization` enum. The state of the
filter is the input history, so every variant describes the ``n-1`` input samples that
precede the first one:
- `InitialState(x0)` sets all of them to `x0`. This is the default, with ``x_0 = 0``,
which is the usual convention for FIR filtering: the output is the convolution of the
input with `coeffs`, the input being extended by zeros before its first sample.
- `InitialOutput(y0)` sets them to the common level that makes the first output equal
`y0`. This requires the coefficients other than the first to have a nonzero sum,
``\sum_{i=2}^{n} c_i \neq 0``.
- `SteadyState` sets them to the first input sample, as if the input had been constant up
to that point, so the first output is the DC response ``u(1) \sum_{i=1}^{n} c_i``.
- `InitialStateArray(x0)` sets the sample delayed by ``i`` samples to `x0[i]`, which is
the only variant that admits an input history that is not constant.
The single-tap case ``n = 1`` has no input history and ignores `initialization`.
"""
component FIRFilter@[input clk extends Discrete]
"Input signal"
u = RealInput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 450, "x2": 0, "y2": 550, "rot": 0}
},
"tags": []
}
}
"Output signal"
y = RealOutput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
},
"tags": []
}
}
"Number of filter taps"
structural parameter n::Integer = 2
"Filter coefficients; coeffs[i] multiplies the input delayed by i-1 samples"
parameter coeffs::Real[n] = fill(1.0 / n, n)
"Initial-condition specification"
structural parameter initialization::InitialCondition = DiscreteComponents.InitialCondition.InitialState(x0 = 0.0)
"Number of delayed taps, one less than the number of coefficients"
final structural parameter nd::Integer = n - 1
"Common level of the input samples preceding the first one (only used by the InitialState variant)"
final parameter u_init::Real = _ic_state_level(initialization)
"Products coeffs[i]*u(k-i+1)"
variable cu::Real[n]
relations
# Dyad has no sum over a generator, so the dot product against the delayed inputs is
# materialized as an array of products and reduced with `sum`.
cu[1] = coeffs[1] * u@clk
for i in 1:nd
cu[i + 1] = coeffs[i + 1] * u@(clk-i)
end
y@clk = sum(cu)
switch initialization
case InitialState
for i in 1:nd
initial u@(clk-i) = u_init
end
case InitialOutput
for i in 1:nd
initial u@(clk-i) = (initialization.y0 - coeffs[1] * u@clk) / (sum(coeffs) - coeffs[1])
end
case SteadyState
for i in 1:nd
initial u@(clk-i) = u@clk
end
case InitialStateArray
for i in 1:nd
initial u@(clk-i) = initialization.x0[i]
end
case InitialOutputArray
for i in 1:nd
initial u@(clk-i) = error("InitialOutputArray is not supported for FIRFilter; use InitialOutput, InitialState, InitialStateArray, or SteadyState")
end
end
metadata {"Dyad": {"icons": {"default": "dyad://DiscreteComponents/FIRFilter.svg"}}}
end
Flattened Source
"""
Finite impulse response (FIR) filter with the input-output relation
```math
y(k) = \sum_{i=1}^{n} c_i u(k-i+1)
```
corresponding to the transfer function
```math
H(z) = \sum_{i=1}^{n} c_i z^{-(i-1)}
```
where ``c`` is `coeffs`. The filter has no feedback, so it is stable for any coefficients
and its impulse response is `coeffs`, of length `n`. The sample period is that of the
connected clock.
`MovingAverageFilter` is the special case in which all coefficients equal ``1/n``, which
is also the default here.
The initial condition is selected through the `initialization` enum. The state of the
filter is the input history, so every variant describes the ``n-1`` input samples that
precede the first one:
- `InitialState(x0)` sets all of them to `x0`. This is the default, with ``x_0 = 0``,
which is the usual convention for FIR filtering: the output is the convolution of the
input with `coeffs`, the input being extended by zeros before its first sample.
- `InitialOutput(y0)` sets them to the common level that makes the first output equal
`y0`. This requires the coefficients other than the first to have a nonzero sum,
``\sum_{i=2}^{n} c_i \neq 0``.
- `SteadyState` sets them to the first input sample, as if the input had been constant up
to that point, so the first output is the DC response ``u(1) \sum_{i=1}^{n} c_i``.
- `InitialStateArray(x0)` sets the sample delayed by ``i`` samples to `x0[i]`, which is
the only variant that admits an input history that is not constant.
The single-tap case ``n = 1`` has no input history and ignores `initialization`.
"""
component FIRFilter
"Input signal"
u = RealInput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": -100, "y1": 450, "x2": 0, "y2": 550, "rot": 0}
},
"tags": []
}
}
"Output signal"
y = RealOutput@[clk]() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 1000, "y1": 450, "x2": 1100, "y2": 550, "rot": 0}
},
"tags": []
}
}
"Number of filter taps"
structural parameter n::Integer = 2
"Filter coefficients; coeffs[i] multiplies the input delayed by i-1 samples"
parameter coeffs::Real[n] = fill(1.0 / n, n)
"Initial-condition specification"
structural parameter initialization::InitialCondition = DiscreteComponents.InitialCondition.InitialState(x0 = 0.0)
"Number of delayed taps, one less than the number of coefficients"
final structural parameter nd::Integer = n - 1
"Common level of the input samples preceding the first one (only used by the InitialState variant)"
final parameter u_init::Real = _ic_state_level(initialization)
"Products coeffs[i]*u(k-i+1)"
variable cu::Real[n]
relations
# Dyad has no sum over a generator, so the dot product against the delayed inputs is
# materialized as an array of products and reduced with `sum`.
cu[1] = coeffs[1] * u@clk
for i in 1:nd
cu[i + 1] = coeffs[i + 1] * u@(clk-i)
end
y@clk = sum(cu)
switch initialization
case InitialState
for i in 1:nd
initial u@(clk-i) = u_init
end
case InitialOutput
for i in 1:nd
initial u@(clk-i) = (initialization.y0 - coeffs[1] * u@clk) / (sum(coeffs) - coeffs[1])
end
case SteadyState
for i in 1:nd
initial u@(clk-i) = u@clk
end
case InitialStateArray
for i in 1:nd
initial u@(clk-i) = initialization.x0[i]
end
case InitialOutputArray
for i in 1:nd
initial u@(clk-i) = error("InitialOutputArray is not supported for FIRFilter; use InitialOutput, InitialState, InitialStateArray, or SteadyState")
end
end
metadata {"Dyad": {"icons": {"default": "dyad://DiscreteComponents/FIRFilter.svg"}}}
endTest Cases
No test cases defined.
Related
- Examples
- Experiments
- Analyses