# How to apply a butterworth filter in a loop?

**URL:** <https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818>\
**Category:** Signal and Image Processing\
**Tags:** question, package, dsp\
**Created:** [November 19, 2024, 4:49pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818 "2024-11-19T16:49:49Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [November 19, 2024, 4:49pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/1 "2024-11-19T16:49:49Z")

</div>

I constructed a Butterworth filter, which works fine:

```julia
using ControlPlots, DSP

# Define the cut-off frequency in Hz
cut_off_freq = 2.0
Wn = cut_off_freq

# Define the sampling time in seconds
dt = 0.05
fs = 1/dt
sim_time = 4.0
N = Int(sim_time / dt)

# Design the filter
butter = Filters.digitalfilter(Filters.Lowpass(Wn; fs), Filters.Butterworth(4))

# Create an array of measurements
measurements = zeros(N)
for i in Int(N/2):N
    measurements[i] = 1.0
end

results = filt(butter, measurements)

# Plot the results
plot((1:N)*dt, [measurements, results]; xlabel="Time (s)", ylabel="Amplitude", 
     fig="Forth order Butterworth Filter")

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/9/6/965c3b494dd7d4d81352d1d4a0dbc4b27cf3e53d.png)

But now I want to apply it online in a loop, similar to the way I am applying a first order filter in the following example:

```julia
results = zeros(N)

# Apply the EMA filter
last_measurement::Float64 = 0.0
for i in 1:N
    global last_measurement
    results[i] = ema_filter(measurements[i], last_measurement, cut_off_freq, dt)
    last_measurement = results[i]
end

function ema_filter(measurement, last_measurement, cut_off_freq, dt)
    if cut_off_freq > 0.0
        alpha = dt / (dt + one(measurement) / (2π * cut_off_freq))
        filtered_value = alpha * measurement + (one(measurement) - alpha) * last_measurement
    else
        filtered_value = measurement
    end
    return filtered_value
end

```

The point is, the filter will become part of a larger control system.

How can I apply the Butterworth filter sample-by-sample?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 19, 2024, 5:42pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/2 "2024-11-19T17:42:54Z")

</div>

Can’t you just call `DSP.filt!` on one sample (or, more efficiently, on a batch of a few samples) at a time, passing the `si` array to track the cumulative effect of the previous samples?

More simply, you can use a [stateful filter wrapper object](https://docs.juliadsp.org/latest/filters/#stateful-filter-objects) with something like:

```julia
butterF = DSP.Filters.DF2TFilter(butter)

```

and then call `filt!(out, butterF, x)` to perform the filtering on a chunk of inputs `x` to get a chunk of outputs `out`.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [November 19, 2024, 6:28pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/3 "2024-11-19T18:28:34Z")

</div>

This works, but is very inefficient:

```julia
using ControlPlots, DSP

# Define the cut-off frequency in Hz
cut_off_freq = 2.0

# Define the sampling time in seconds
dt = 0.05
fs = 1/dt
sim_time = 4.0
N = Int(sim_time / dt)

# Design the filter
butter = Filters.digitalfilter(Filters.Lowpass(cut_off_freq; fs), Filters.Butterworth(2))

# Create an array of measurements
measurements = zeros(N)
for i in Int(N/2):N
    measurements[i] = 1.0
end

function butter_filter(butter, measurement, buffer, index)
    buffer[index] = measurement
    res = filt(butter, buffer[1:index])
    return res[index]
end

buffer = zeros(N)
results = zeros(N)
for i in 1:N
    results[i] = butter_filter(butter, measurements[i], buffer, i)
end

# Plot the results
plot((1:N)*dt, [measurements, results]; xlabel="Time (s)", ylabel="Amplitude", 
     fig="Forth order Butterworth Filter")

```

I was reading I should convert the ZPG notation to transfer function coefficients and use those to create a difference equation which would be short and efficient. No idea how to do that, though.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 19, 2024, 6:39pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/4 "2024-11-19T18:39:03Z")

</div>

> [@ufechner7](#):
>
> This works, but is very inefficient:

Of course it’s inefficient — you are re-doing the entire filter from the beginning for every new measurement.

Using the filter state (see my suggestion) allows you to avoid this — each batch of new measurements requires only the new filter terms to be applied.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [November 19, 2024, 6:42pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/5 "2024-11-19T18:42:48Z")

</div>

NIce, but I do not know how to put your suggestion into practice. A big issue with the DSP package is that there are no examples provided.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 19, 2024, 6:51pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/6 "2024-11-19T18:51:15Z")

</div>

> [@ufechner7](#):
>
> NIce, but I do not know how to put your suggestion into practice.

What did you try? The documentation may lack examples written out for you, but it documents the relevant functions.

For example, this code applies your filter 1 element at a time:

```julia
butterF = DSP.Filters.DF2TFilter(butter)
results2 = zeros(N)
for i = 1:N
    @views filt!(results2[i:i], butterF, measurements[i:i])
end

```

(Bigger batches should be more efficient, but the complexity should still be linear in N.)

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [December 4, 2024, 7:16pm UTC](https://discourse.julialang.org/t/how-to-apply-a-butterworth-filter-in-a-loop/122818/7 "2024-12-04T19:16:08Z")

</div>

I am using now this function:

```julia
"""
    apply_filter(tfilter::DF2TFilter, measurement)

Apply the filter to the measurement.

# Arguments
- `tfilter`: The filter, created with `create_filter` and converted to a DF2TFilter
- `measurement`: The measurement value
"""
function apply_filter(tfilter::DF2TFilter, measurement)
    results = zeros(1)
    measurements = ones(1) * measurement
    @views filt!(results[1:1], tfilter, measurements)
    return results[1]
end

```

While it is fast enough for my purposes, I think it is ugly and a function that does not require to allocate one element arrays should be added to DSP.jl.

I created an issue: [Improve online filter functions · Issue #605 · JuliaDSP/DSP.jl · GitHub](https://github.com/JuliaDSP/DSP.jl/issues/605)
