Engee documentation
Notebook

Application of DSP library filters

To demonstrate the different types of filters from the DSP library, we have prepared brief descriptions of each filter with an application example.

Here we will look at the main filters:

  1. filters with finite impulse response,
  2. low-pass filters,
  3. high-pass filters.

More details on all the principles of filter construction can be found in this example: https://engee.com/community/ru/catalogs/projects/sravnitelnyi-analiz-filtrov

Let's start with the connection of this library. It is important to note that the DSP library distinguishes between filter coefficients and state-preserving filters.

In [ ]:
Pkg.add(["DSP"])
In [ ]:
Pkg.add("DSP")
using DSP
using FFTW
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`

Let's declare an input signal, which we will later use to test our filters.

Let's also declare an auxiliary function.

In [ ]:
Fs = 1000  # Частота дискретизации
t = 0:1/Fs:1-1/Fs  # Временной интервал
x = sin.(2π .* 0.1 .* t) .+ randn(length(t))  # Сигнал с шумом (0.1 Гц компонент и шум)
plot(x)
Out[0]:
In [ ]:
# Расчёт спектра сигнала
function compute_spectrum(signal, fs)
    n = length(signal)
    spectrum = abs.(fft(signal)) / n
    freqs = (0:n-1) .* (fs / n)
    spectrum[1:Int(n/2)], freqs[1:Int(n/2)]  # Вернуть половину спектра (для удобства)
end
Out[0]:
compute_spectrum (generic function with 2 methods)
In [ ]:
spectrum_x, freqs_x = compute_spectrum(x, Fs)
plot(freqs_x, spectrum_x, xlabel="Frequency (Hz)", ylabel="Amplitude", legend=:topright)
Out[0]:

Next, let's move on to examples of implementing various filters.

FIR filters (Finite Impulse Response)

FIR filters have a finite impulse response, which makes them stably solvable and easy to design. They have no internal feedback.

The type of filter we applied is a lowpass filter (Lowpass) with a cutoff frequency of 5 Hz. It is applied to the signal using a FIR filter designed by Hanning window method with a length of 64.

In [ ]:
responsetype = Lowpass(5; fs=Fs)
designmethod = FIRWindow(hanning(64))
y = filt(digitalfilter(responsetype, designmethod), x)

plot(x, label="Original Signal", title="Signal")
plot!(y, label="Filtered Signal", xlabel="Sample", ylabel="Amplitude")
Out[0]:
In [ ]:
spectrum_y, freqs_y = compute_spectrum(y, Fs)

plot(freqs_x, spectrum_x, label="Original Signal Spectrum", xlabel="Frequency (Hz)", ylabel="Amplitude", legend=:topright)
plot!(freqs_y, spectrum_y, label="Filtered Signal Spectrum", title="Signal Spectrum")
Out[0]:

After filtering, the signal became smoothed, suppressing noise components. The waveform now better reflects the low-frequency component.

Peak noise emissions have practically disappeared, which confirms good filtering of high-frequency components.

Frequencies above 32 Hz are completely suppressed. The main amplitudes of the spectrum are concentrated at 0 Hz (DC component) and 3 Hz.

This indicates that the filter effectively suppressed noise above the cut-off frequency.

Low-pass filters (Low-pass filters)

These filters pass signals with frequencies below a specified threshold and attenuate signals with higher frequencies.

The type of filter we use is a Lowpass filter with a cut-off frequency of 0.2 Hz. It is designed by a 4th order elliptic filter method with tolerances of 0.5 dB in the pass band and 30 dB in the obstruction band. Realised as a transfer function using polynomial representation (PolynomialRatio).

In [ ]:
responsetype = Lowpass(0.2)
designmethod = Elliptic(4, 0.5, 30)
tf = convert(PolynomialRatio, digitalfilter(responsetype, designmethod))
numerator_coefs = coefb(tf)
denominator_coefs = coefa(tf)

y = filt(tf, x)

plot(x, label="Original Signal", title="Signal")
plot!(y, label="Filtered Signal", xlabel="Sample", ylabel="Amplitude")
Out[0]:
In [ ]:
spectrum_y, freqs_y = compute_spectrum(y, Fs)

plot(freqs_x, spectrum_x, label="Original Signal Spectrum", xlabel="Frequency (Hz)", ylabel="Amplitude", legend=:topright)
plot!(freqs_y, spectrum_y, label="Filtered Signal Spectrum", title="Signal Spectrum")
Out[0]:

The filter performed worse than the previous one, as residual noise in the main signal is visible. Smoothing is present, but its quality is unsatisfactory, as noise continues to have a significant impact on the final result.

The spectrum of the processed signal shows the presence of peaks at frequencies up to 130 Hz, which indicates insufficient filtering of high-frequency components: the filter ineffectively suppresses frequencies above its cut-off frequency.

Elliptic filters have a high steepness of the transient response, but can suffer from significant ripple in the passband, which is observed in this case.

The cutoff frequency (0.2 Hz) and the chosen filter parameters may not be optimal for this signal. In addition, the filter order (4th) may not be sufficient to achieve the required noise suppression.

High-pass filters (High-pass filters)

These filters allow signals with frequencies above a specified threshold to pass through and attenuate signals with lower frequencies.

The type of filter we have used here is a High-pass filter with a cut-off frequency of 40 Hz, implemented using a 4th order Butterworth filter.

In [ ]:
responsetype = Highpass(40; fs=Fs)  # Высокочастотный фильтр, отсечка на 40 Гц, fs = 1000 Гц
designmethod = Butterworth(4)         # Баттерворт, порядок 4
highpass_filter = digitalfilter(responsetype, designmethod)

y = filt(highpass_filter, x)  # Применяем фильтр к сигналу x

plot(x, label="Original Signal", title="Signal")
plot!(y, label="Filtered Signal", xlabel="Sample", ylabel="Amplitude")
Out[0]:
In [ ]:
spectrum_y, freqs_y = compute_spectrum(y, Fs)

plot(freqs_x, spectrum_x, label="Original Signal Spectrum", xlabel="Frequency (Hz)", ylabel="Amplitude", legend=:topright)
plot!(freqs_y, spectrum_y, label="Filtered Signal Spectrum", title="Signal Spectrum")
Out[0]:

After filtering, the signal is almost indistinguishable from the noisy original signal, indicating that the low-frequency information that defines the main fluctuations of the signal has been completely removed.

The spectrum shows that all frequencies up to 40 Hz (including significant low frequency components up to 24 Hz) have been completely suppressed. This resulted in the loss of the main signal information, leaving only high frequency noise.

A high-pass filter with a 40 Hz cut-off is completely inappropriate for analysing this signal, as the significant frequency of the signal (0.1 Hz) lies in the low frequency range, which the filter removes.

Band-pass filters (Band-pass filters)

These filters pass signals within a given frequency band while attenuating signals outside that band. The type of filter we use here is a band-pass filter with a bandwidth of 10 to 40 Hz, implemented using a 4th order Butterworth filter.

The sampling frequency: 1000 Hz.

In [ ]:
responsetype = Bandpass(10, 40; fs=Fs)
designmethod = Butterworth(4)
y = filt(digitalfilter(responsetype, designmethod), x)

plot(x, label="Original Signal", title="Signal")
plot!(y, label="Filtered Signal", xlabel="Sample", ylabel="Amplitude")
Out[0]:
In [ ]:
spectrum_y, freqs_y = compute_spectrum(y, Fs)

plot(freqs_x, spectrum_x, label="Original Signal Spectrum", xlabel="Frequency (Hz)", ylabel="Amplitude", legend=:topright)
plot!(freqs_y, spectrum_y, label="Filtered Signal Spectrum", title="Signal Spectrum")
Out[0]:

The filter smoothed out the noise, which is noticeable when comparing the processed signal with the original noisy one. However, useful information about the low-frequency fluctuations of the signal was lost. Only a "fragment" of the high-frequency part of the signal remained, which does not carry significant information.

The spectrum of the processed signal shows that the filter effectively suppressed frequencies below 10 Hz and above 70 Hz, but retained the range from 10 to 40 Hz, which in this case does not contain useful information. This resulted in the signal being represented by noise components in this band, losing its original low-frequency character.

Band-stop filters (Band-stop filters)

These filters attenuate signals in a specified frequency range, allowing all other frequencies to pass through.

In this case we implement a band-stop filter that suppresses frequencies in the 10-40 Hz range and is implemented using a 4th order Butterworth filter.

In [ ]:
responsetype = Bandstop(10, 40; fs=Fs)  # Полосо-заградительный фильтр, подавляет частоты от 10 до 40 Гц, fs = 1000 Гц
designmethod = Butterworth(4)            # Баттерворт, порядок 4

y = filt(digitalfilter(responsetype, designmethod), x)  # Применяем фильтр к сигналу x (определите x заранее)


plot(x, label="Original Signal", title="Signal")
plot!(y, label="Filtered Signal", xlabel="Sample", ylabel="Amplitude")
Out[0]:
In [ ]:
spectrum_y, freqs_y = compute_spectrum(y, Fs)

plot(freqs_x, spectrum_x, label="Original Signal Spectrum", xlabel="Frequency (Hz)", ylabel="Amplitude", legend=:topright)
plot!(freqs_y, spectrum_y, label="Filtered Signal Spectrum", title="Signal Spectrum")
Out[0]:

After filtering the signal looks almost the same as the original noisy signal, which indicates that the filter has a negligible effect on the apparent structure of the signal.

The spectrum shows suppression of frequencies in the range from 12 to 32 Hz. Other frequency components, including noise, remained almost unchanged.

This explains the preservation of the noisy character of the signal.

Conclusion

We looked at various filters to solve this problem and found that the Hanning window FIR filter was the best choice. Its ability to smoothly and efficiently remove noise above a given cutoff frequency allowed us to isolate useful low frequency information (0.1 Hz), which was the primary objective.

Summarising the above comparisons, the following conclusion can be made: for such tasks it is worth using low-pass filters with a cut-off frequency that optimally matches the range of useful information.