Implement High Pass Filter Using NumPy
In this tutorial, you’ll learn about different methods to create high-pass filters, including Finite Impulse Response (FIR), Infinite Impulse Response (IIR), and the Fast Fourier Transform (FFT) using NumPy.
We’ll start by designing a FIR high-pass filter using a windowed sinc function.
Then, we’ll focus on IIR high-pass filters, using popular design techniques like the Butterworth and Chebyshev filters.
These filters are known for their smooth frequency response and sharp cutoff characteristics, respectively.
Finally, we explore the use of FFT to create a high-pass filter.
FIR High Pass Filter
The concept involves creating a low-pass filter first and then transforming it into a high-pass filter.
This transformation is done by subtracting the low-pass response from an appropriately scaled delta function.
First, ensure you have NumPy installed in your Python environment.
If you don’t have it installed, you can install it via pip:
!pip install numpy
Now, let’s import NumPy:
import numpy as np
Here, we define the parameters for our filter. This includes the filter length, cutoff frequency, and the sampling rate.
filter_length = 101 # Length of the filter (number of coefficients) cutoff_frequency = 0.3 # Normalized cutoff frequency (0 to 0.5) sampling_rate = 1000 # Sampling rate in Hz
We’ll design the low-pass filter using a windowed sinc function. The sinc function is the ideal response of a low-pass filter, and we window it to truncate the infinite series.
# Time vector for filter t = np.arange(-filter_length // 2 + 1, filter_length // 2 + 1) # Sinc function h_low_pass = np.sinc(2 * cutoff_frequency * (t / sampling_rate)) # Apply a window function (e.g., Hamming window) window = np.hamming(filter_length) h_low_pass_windowed = h_low_pass * window print(h_low_pass_windowed)
Output:
[0.07988162 0.08079272 0.08351319 0.0880326 0.09433344 0.10239112 0.11217411 0.12364407 0.13675597 0.15145828 0.16769319 0.18539682 0.20449946 0.22492588 0.24659561 0.26942324 0.29331878 0.31818802 0.34393288 0.3704518 0.39764018 0.42539072 0.45359394 0.48213851 0.51091178 0.53980016 0.56868962 0.59746608 0.62601594 0.65422647 0.68198625 0.70918566 0.7357173 0.76147636 0.7863611 0.81027325 0.83311833 0.85480612 0.87525093 0.894372 0.9120938 0.92834631 0.94306533 0.9561927 0.96767655 0.97747153 0.98553892 0.99184685 0.9963704 0.9990917 1. 0.9990917 0.9963704 0.99184685 0.98553892 0.97747153 0.96767655 0.9561927 0.94306533 0.92834631 0.9120938 0.894372 0.87525093 0.85480612 0.83311833 0.81027325 0.7863611 0.76147636 0.7357173 0.70918566 0.68198625 0.65422647 0.62601594 0.59746608 0.56868962 0.53980016 0.51091178 0.48213851 0.45359394 0.42539072 0.39764018 0.3704518 0.34393288 0.31818802 0.29331878 0.26942324 0.24659561 0.22492588 0.20449946 0.18539682 0.16769319 0.15145828 0.13675597 0.12364407 0.11217411 0.10239112 0.09433344 0.0880326 0.08351319 0.08079272 0.07988162]
This output represents the coefficients of the windowed low-pass filter. These coefficients are applied to the input signal to achieve low-pass filtering.
To create the high-pass filter, we subtract the low-pass filter response from a delta function.
This delta function is represented by an array with a one at its center and zeros elsewhere.
delta_function = np.zeros(filter_length) delta_function[filter_length // 2] = 1 # Subtract the low-pass response from the delta function h_high_pass = delta_function - h_low_pass_windowed print(h_high_pass)
Output:
[-0.07988162 -0.08079272 -0.08351319 -0.0880326 -0.09433344 -0.10239112 -0.11217411 -0.12364407 -0.13675597 -0.15145828 -0.16769319 -0.18539682 -0.20449946 -0.22492588 -0.24659561 -0.26942324 -0.29331878 -0.31818802 -0.34393288 -0.3704518 -0.39764018 -0.42539072 -0.45359394 -0.48213851 -0.51091178 -0.53980016 -0.56868962 -0.59746608 -0.62601594 -0.65422647 -0.68198625 -0.70918566 -0.7357173 -0.76147636 -0.7863611 -0.81027325 -0.83311833 -0.85480612 -0.87525093 -0.894372 -0.9120938 -0.92834631 -0.94306533 -0.9561927 -0.96767655 -0.97747153 -0.98553892 -0.99184685 -0.9963704 -0.9990917 0. -0.9990917 -0.9963704 -0.99184685 -0.98553892 -0.97747153 -0.96767655 -0.9561927 -0.94306533 -0.92834631 -0.9120938 -0.894372 -0.87525093 -0.85480612 -0.83311833 -0.81027325 -0.7863611 -0.76147636 -0.7357173 -0.70918566 -0.68198625 -0.65422647 -0.62601594 -0.59746608 -0.56868962 -0.53980016 -0.51091178 -0.48213851 -0.45359394 -0.42539072 -0.39764018 -0.3704518 -0.34393288 -0.31818802 -0.29331878 -0.26942324 -0.24659561 -0.22492588 -0.20449946 -0.18539682 -0.16769319 -0.15145828 -0.13675597 -0.12364407 -0.11217411 -0.10239112 -0.09433344 -0.0880326 -0.08351319 -0.08079272 -0.07988162]
The resulting array is the coefficients of the high-pass filter. When applied to an input signal, it allows frequencies higher than the cutoff frequency to pass through, effectively blocking lower frequencies.
IIR High Pass Filter
First, ensure you have both NumPy and SciPy installed in your Python environment.
!pip install numpy scipy
After installing, import the required modules from NumPy and SciPy:
import numpy as np from scipy.signal import butter, cheby1, freqz
Define the specifications for your high-pass filter, including the order of the filter, the cutoff frequency, and the type of filter (Butterworth or Chebyshev).
filter_order = 5 # Order of the filter cutoff_frequency = 0.3 # Normalized cutoff frequency (0 to 0.5) ripple_db = 5 # Ripple for Chebyshev filter in decibels
For the Butterworth filter, known for its maximally flat frequency response in the passband:
b_butter, a_butter = butter(filter_order, cutoff_frequency, btype='high', analog=False)
For the Chebyshev filter, which allows for a sharper cutoff but introduces ripples in the passband:
b_cheby, a_cheby = cheby1(filter_order, ripple_db, cutoff_frequency, btype='high', analog=False)
Display the coefficients for both filters:
print("Butterworth Filter Coefficients:\n", b_butter, a_butter) print("Chebyshev Filter Coefficients:\n", b_cheby, a_cheby)
Output:
Butterworth Filter Coefficients: [ 0.20188501 -1.00942507 2.01885014 -2.01885014 1.00942507 -0.20188501] [ 1. -1.97590162 2.01347303 -1.10261798 0.32761833 -0.04070949] Chebyshev Filter Coefficients: [ 0.07522326 -0.37611631 0.75223263 -0.75223263 0.37611631 -0.07522326] [ 1. -0.76509924 1.13123641 0.13615021 0.04480816 0.39784919]
These coefficients are crucial for implementing the filters in digital signal processing systems.
Finally, analyze the frequency response of both filters to understand their performance characteristics:
w, h_butter = freqz(b_butter, a_butter) w, h_cheby = freqz(b_cheby, a_cheby)
In this step, we compare the frequency responses of the Butterworth and Chebyshev filters, focusing on their ripple and roll-off characteristics.
FFT High Pass Filter
This method involves converting a signal to the frequency domain, applying a high-pass filter, and then transforming it back to the time domain using the inverse FFT.
First, import NumPy:
import numpy as np
Create a sample signal by combining sine waves of different frequencies. This will help demonstrate the effect of the high-pass filter.
sample_rate = 1000 t = np.arange(0, 1.0, 1.0 / sample_rate) # Signal with multiple frequencies signal = np.sin(2 * np.pi * 5 * t) + np.sin(2 * np.pi * 20 * t)
Next, apply FFT to transform this signal into the frequency domain.
fft_signal = np.fft.fft(signal) frequency = np.fft.fftfreq(t.shape[-1], d=1.0/sample_rate)
Design the high-pass filter using a simple frequency domain window that blocks low frequencies and allows high frequencies to pass.
high_pass_filter = frequency > 10 # 10 Hz cutoff frequency filtered_fft_signal = fft_signal * high_pass_filter
Finally, apply the inverse FFT to convert the signal back to the time domain.
filtered_signal = np.fft.ifft(filtered_fft_signal) print(filtered_signal.real)
The output of this process is the real part of the filtered time-domain signal, demonstrating the effectiveness of FFT-based high-pass filtering.
Mokhtar is the founder of LikeGeeks.com. He is a seasoned technologist and accomplished author, with expertise in Linux system administration and Python development. Since 2010, Mokhtar has built an impressive career, transitioning from system administration to Python development in 2015. His work spans large corporations to freelance clients around the globe. Alongside his technical work, Mokhtar has authored some insightful books in his field. Known for his innovative solutions, meticulous attention to detail, and high-quality work, Mokhtar continually seeks new challenges within the dynamic field of technology.