Numeric Filter Synthesis : CutOff Frequency 50Hz (Or 60Hz)

ThomasESP32
Posts: 232
Joined: Thu Jul 14, 2022 5:15 am

Numeric Filter Synthesis : CutOff Frequency 50Hz (Or 60Hz)

Postby ThomasESP32 » Wed Feb 26, 2025 9:16 am

Good morning,

I encounter the following problem (In my job) :

Using a microcontroller, I sample a signal comming from a microphone at the sampling frequency of 16KHz. This signal goes through a hardware preampli. I get a buffer of 250 samples at the output.

An algorithm computes statistics on this buffer, but this one is disturbed by the presence of a 50Hz signal mixed with the noise recorded by the microphone.

I would like to realize a numeric filter on the buffer in order to remove the 50Hz (Or 60Hz depending on the country). I studied numeric filtering 15 years ago, I remember that we managed to synthetize RIF filter using Matlab (Choosing a window, the filter order an so on...) and that we managed to obtain coefficients that. I also remeber that we managed to implement this filter on a DSP.

Now, I do not remember the method, I do not rememeber how to obtain the coefficients and I do not rememebr how to implement this kind of filter practically...

Does anyone knows how to do it please ? And does anyone could explain me the method in detail and how to get the coefficients of the filter ? Moreover, could you please explain me how to implement this filter practically ?

If anyone has good knowledges on numeric filtering, thank you by advance for your help on this subject.

I wish you a good day, best regards.

Thomas TRUILHE

teletypeguy
Posts: 10
Joined: Sat Feb 22, 2025 7:21 pm

Re: Numeric Filter Synthesis : CutOff Frequency 50Hz (Or 60Hz)

Postby teletypeguy » Wed Feb 26, 2025 5:24 pm

I am also interested in doing this on an esp, and have been looking at the esp-dsp component. I have not done any more than look at esp-dsp so far, but I have been playing with filtering in python as a precursor. You could also use matlab if you pay for it, or the free clone octave, but I prefer python. Using the jupyter notebook extension in vscode makes it really easy to paste code snippets and run quickly.

As a quick example from chatgpt (I find that chatgpt and copilot both generate pretty good python code snippets to play quickly):
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from scipy import signal
  4.  
  5. # Sampling rate (Hz)
  6. fs = 1000
  7.  
  8. # Notch filter frequency (60 Hz)
  9. f_notch = 60
  10.  
  11. # Quality factor (controls the width of the notch)
  12. Q = 30.0
  13.  
  14. # Design the notch filter
  15. b, a = signal.iirnotch(f_notch, Q, fs)
  16.  
  17. # Create a signal that contains 60 Hz noise
  18. t = np.linspace(0, 1, fs, endpoint=False)  # 1 second
  19. signal_with_noise = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * f_notch * t)  # 5 Hz signal + 60 Hz noise
  20.  
  21. # Apply the notch filter to the noisy signal
  22. filtered_signal = signal.filtfilt(b, a, signal_with_noise)
  23.  
  24. # Plot the original and filtered signals
  25. plt.figure(figsize=(10, 6))
  26.  
  27. # Plot the original signal
  28. plt.subplot(2, 1, 1)
  29. plt.plot(t, signal_with_noise)
  30. plt.title('Original Signal with 60 Hz Noise')
  31. plt.xlabel('Time [s]')
  32. plt.ylabel('Amplitude')
  33.  
  34. # Plot the filtered signal
  35. plt.subplot(2, 1, 2)
  36. plt.plot(t, filtered_signal)
  37. plt.title('Filtered Signal (60 Hz Notch Filter Applied)')
  38. plt.xlabel('Time [s]')
  39. plt.ylabel('Amplitude')
  40.  
  41. plt.tight_layout()
  42. plt.show()
1.png
1.png (201.26 KiB) Viewed 404 times
You can get the coefficients from the returned b,a transfer function polynomials. This example applies the filter with filtfilt, which does a forward/backward "zero-phase" application, as opposed to the lfilter standard application. You can try it both ways.

Actually, for a notch, you probably want a pretty high order, and the previous approach can lead to numerical instability (especially when ported to an embedded controller using single-precision float or integer dsp code). I have not gone further with the iir code, but using scipy.butter I have been moving away from the standard transfer-function (b,a) approach to their "sos" (second-order-sections) options. This is a cascade of biquads which are numerically happy, and high orders are just a chain.

Anyway, I have no concrete example for you but I am on a similar path and interested in this discussion.

BTW, at fs=16kHz, 250 samples is only 15.6 ms of signal, not close to even one cycle of 50 Hz (20ms). Perhaps you want bigger buffers.

Who is online

Users browsing this forum: sysprogs and 84 guests