# Simple Finite Impulse Response Notch Filter

*Pieter P*

This is an example on how to design a very simple FIR notch filter in the digital domain,
that can be used to filter out 50/60 Hz mains noise, for example.

It is a very simple filter, so the frequency response is not great, but it might be all you need.
It's only second order, finite impulse response, so very fast and always stable, and has linear phase.

### Zero Placement

To achieve notch characteristics, we'll just place a single complex pair of zeros on the unit circle.
Let's say we have a sample frequency of and we want to filter out noise.

We'll first calculate the normalized frequency :
We know that the frequency response of a digital filter is just the transfer function
evaluated along the unit circle . In other words, we just need a transfer function that is zero
when the frequency equals , or when . Because the transer function must have
real coefficients, the complex conjugate will be a zero as well: .
We can further simplify this function by expanding it, and using the identity
:

### Normalization

If we want a filter with a unit DC gain (), we can just normalize the transfer function:

### Numerical Result

Finally, we can just plug in the value of :

### Bode Plot & Zero Map

Let's take a quick look at the bode plot and the locations of the zeros. The Python code to generate the Bode plot can be found below. You can clearly see the expected linear phase of a FIR filter, with a 180 phase jump when the frequency crosses the zero. The notch itself is not at all narrow. If you want a narrower notch, you could a higher FIR order, or place some poles close to the unit circle to cancel the effect of the zero.

`from scipy.signal import butter, freqz`

`import matplotlib.pyplot as plt`

`from math import pi, cos`

`import numpy as np`

`f_s = 360 # Sample frequency in Hz`

`f_c = 50 # Notch frequency in Hz`

`omega_c = 2 * pi * f_c # Notch angular frequency`

`omega_c_d = omega_c / f_s # Normalized notch frequency (digital)`

`h_0 = 2 - 2 * cos(omega_c_d)`

`b = np.array((1, -2 * cos(omega_c_d), 1)) # Calculate coefficients`

`b /= h_0 # Normalize`

`a = 1`

`print("a =", a) # Print the coefficients`

`print("b =", b)`

`w, h = freqz(b, a) # Calculate the frequency response`

`w *= f_s / (2 * pi) # Convert from rad/sample to Hz`

`plt.subplot(2, 1, 1) # Plot the amplitude response`

`plt.suptitle('Bode Plot')`

`plt.plot(w, 20 * np.log10(abs(h))) # Convert to dB`

`plt.ylabel('Magnitude [dB]')`

`plt.xlim(0, f_s / 2)`

`plt.ylim(-60, 20)`

`plt.axvline(f_c, color='red')`

`plt.subplot(2, 1, 2) # Plot the phase response`

`plt.plot(w, 180 * np.angle(h) / pi) # Convert argument to degrees`

`plt.xlabel('Frequency [Hz]')`

`plt.ylabel('Phase [°]')`

`plt.xlim(0, f_s / 2)`

`plt.ylim(-90, 135)`

`plt.yticks([-90, -45, 0, 45, 90, 135])`

`plt.axvline(f_c, color='red')`

`plt.show()`