I have some general observations but I am asking if anyone can summarize more conclusively:
(1) Filter settles slower if the ratio between signal frequency and filter cutoff frequency is smaller;
(2) Filter settles slower if bandwidth of a band-pass filter is narrower:
(3) Filter settles instantly when applying on an unit-impulse signal.
Anyone can add more or give a better one?
Update on 7.19.2022:
Some answers claimed the 3rd statement is incorrect. So I did an experiment, here is the procedure (code provided below):
(1) Create an unit-impulse signal.
(2) Perform FFT.
(3) Create a [20, 30]Hz bandpass Butterworth filter.
(4) Apply the filter on unit-impulse signal and perform FFT again.
(5) Use the result of (4) and divide by the result of (2) to get measured attenuation at all frequencies.
(6) Compare measured attenuation with the magnitude frequency response obtained by sosfreqz.
I observed that the difference is 1.5543122344752192e-15. This is too good to be true. I am a bit surprised by this outcome because I did not truncate the filtered time domain signal to get the completely settled signal before any downstream calculation. This is what I usually do for other types of signals, like single tone, etc. So I suspect that filter settled instantly when applying on an unit-impulse signal.
Can anyone please help me understand why I did not have to truncate the filtered time domain signal to get the completely settled signal, but still got good result?
import numpy as np
import matplotlib.pyplot as plt
%matplotlib notebook
from scipy.signal import butter, sosfilt, sosfreqz
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
normalized_low = lowcut / nyq
normalized_high = highcut / nyq
sos = butter(order, [normalized_low, normalized_high], btype='bandpass', output='sos')
return sos
def filter_implementation(sos, data):
y = sosfilt(sos, data)
return y
#------------------------------------------------------------------------
Create a signal
from scipy import signal
How many time points are needed i,e., Sampling Frequency
sampling_frequency = 100;
At what intervals time points are sampled
sampling_interval = 1 / sampling_frequency;
Begin time period of the signals
begin_time = 0;
End time period of the signals
end_time = 10;
Define signal frequency
signal_frequency = 1
Time points
time = np.arange(begin_time, end_time, sampling_interval);
data = signal.unit_impulse(len(time))
data = signal.sawtooth(2 * np.pi * signal_frequency * time)
data = np.sin(2 * np.pi * signal_frequency * time)
plt.figure(figsize = (8, 4))
plt.plot(time, data)
plt.scatter(time, data, alpha=1, color = 'black', s = 20, marker = '.')
plt.xlabel("Time(s)")
plt.ylabel("Amplitude")
plt.title("Unit-impulse Signal")
plt.grid()
plt.show()
#------------------------------------------------------------------------
Perform fft
from scipy.fft import fft, fftfreq
def perform_fft(y, dt):
yf_temp = fft(y)
xf = fftfreq(len(y), dt)[:len(y)//2]
yf = 2.0/len(y) * np.abs(yf_temp[0:len(y)//2])
return xf, yf
xf, yf = perform_fft(data, 1/sampling_frequency)
plt.figure(figsize = (8, 4))
plt.plot(xf, yf)
plt.scatter(xf, yf, alpha=1, color = 'black', s = 20, marker = '.')
plt.xlabel("Frequency(Hz)")
plt.ylabel("Amplitude")
plt.title("Frequency Domain Signal")
plt.grid()
plt.show()
#------------------------------------------------------------------------
Apply bandpass filter
#Low Frequency
low_cut = 20
#high Frequency
high_cut = 30
print(xf[200])
print(yf[200])
ref_low = yf[200]
print(xf[300])
print(yf[300])
ref_high = yf[300]
Apply bandpass filter
sos = butter_bandpass(low_cut, high_cut, sampling_frequency, order=5)
filtered_data = filter_implementation(sos, data)
Plot time domain filtered_data
plt.figure(figsize = (8, 4))
plt.plot(time, filtered_data)
plt.xlabel("Time(s)")
plt.ylabel("Amplitude")
plt.title("Filtered Data in Time Domain")
plt.grid()
plt.show()
Plot frequency domain filtered_data
xf_filtered, yf_filtered = perform_fft(filtered_data, 1/sampling_frequency)
plt.figure(figsize = (8, 4))
plt.plot(xf_filtered, yf_filtered)
plt.xlabel("Frequency(Hz)")
plt.ylabel("Amplitude")
plt.title("Filtered Data in Frequency Domain")
plt.grid()
plt.show()
Plot frequency domain attenuation
plt.figure(figsize = (8, 4))
plt.plot(xf_filtered, yf_filtered/yf)
plt.scatter(xf_filtered, yf_filtered/yf, alpha=1, color = 'black', s = 20, marker = '.')
plt.xlabel("Frequency(Hz)")
plt.ylabel("Amplitude")
plt.title("Attenuation in Frequency Domain")
plt.grid()
plt.show()
Plot frequency magnitude response
w, h = sosfreqz(sos, worN=len(xf), fs=sampling_frequency)
plt.figure(figsize = (8, 4))
plt.plot(w, abs(h))
plt.scatter(w, abs(h), alpha=1, color = 'black', s = 20, marker = '.')
plt.xlabel("Frequency(Hz)")
plt.ylabel("Amplitude")
plt.title("Frequency Magnitude Response")
plt.grid()
plt.show()
Calculate the difference between magnitude frequency response and meansured attenuation
max(abs(abs(h) - yf_filtered/yf))




