Posted on 26/04/2018

Given that one has some electronic signal added with noise, how do we select the filter cut-off frequency such that we can eliminate most of the noise while retaining most of the signal? In other words, we intend to enhance the signal to noise ratio. This can be very useful in arduino and electronics projects in general. Long story short, it is shown that the filter cutoff (3 dB point) should be chosen at the signal frequency under quite general circumstances, both for high-pass and low-pass filters.

We will consider the following scenario:

  • There is a signal whose frequency is \(f_s=1000\) Hz
  • The noise is mostly at smaller frequencies. Ex.: \(f_n=100\) Hz would be an upper bound to the noise due to the power lines.
  • The filter cut-off frequency is \(f_c\) and we want to determine “the best”

For simplicity we will consider a first-order RC filter (1 Resistor, 1 Capacitor). Given that the signal has a higher frequency than the noise, it seems more interesting to use a high-pass filter, which transmits better signals at higher frequencies. A schematic of such filter is shown below:

A first-order high-pass RC filter

The signal comes in as \(V_i\), and \(V_o\) is the filter output.

High-pass filter analysis

How much of a signal at a frequency \(f\) passes through a high-pass filter whose cut-off frequency is \(f_c\)? The fraction of the signal that is allowed to pass through the filter is informed by the transfer function \(T\). For a first-order high-pass filter, \[T(f,f_c)=\frac{f}{f-jf_c},\] where \(j\) is the imaginary unit, \(j^2=-1\).

We want the most of the a signal whose frequency is \(f_s\), while blocking most of the noise at \(f_n\). In other words, we’re interested in the amplitude of both signal and noise after the filter. The amplitude of a filtered signal at a frequency \(f\) is given by \[|T(f,f_c)|=\frac{f}{\sqrt{f^2+f_c^2}}.\]

Now we know the fraction of the signal and noise which are allowed to pass through the filter. Let us consider which value of \(f_c\) must be chosen. If \(f_c\) is too small, then both signal and noise have a “high frequency” and are allowed to pass. On the other hand, if \(f_c\) becomes too large, then both signal and noise have a “low frequency” and thus the filter removes the information of interest. There must be some optimal value for \(f_c\) under some appropriate constraints.

In the plot below there are considered the relative amounts of signal at 1 kHz (blue) and noise at 100 Hz (orange) after the filter, as a function of the filter cutoff frequency \(f_c\). The high-pass filter is useful only between \(10^1 \leq f_c \leq 10^5\). For frequencies outside this range, the filter does not discriminate signal and noise from each other.

Transfer curves for signal (blue) and noise (orange). Signal to noise transfer ratio (green)

We want that the output does not affect the signal by much, while it attenuates the noise. To achieve this we may consider a figure-of-merit \(S/N\) which is proportional to the signal transfer and inversely proportional to the noise transfer. More signal and less noise should increase this figure. A simple calculation shows that \[S/N = \frac{|T(f_s,f_c)|}{|T(f_n,f_c)|} = \frac{f_s}{f_n} \frac{\sqrt{f_n^2+f_c^2}}{\sqrt{f_s^2+f_c^2}}\]

\(S/N\) is shown in the plot above as the green curve. Notice that if \(f_c\approx f_s\) then the signal attenuation is relatively small, but the \(S/N\) ratio is appreciable. Indeed this makes sense, given that to get rid of low frequency noise it’s necessary to have a filter with the highest available cutoff. Meanwhile, the highest cutoff which does not affect the signal by much is precisely when \(f_c=f_s\).

Figure-of-merit (Edit)

Another approach to characterize the effectiveness of the filter is through the definition of a figure of merit, that increases when the signal increases at the output, while it also increases for an enhanced \(S/N\) ratio. This quantity would be \(FOM=(S/N) |T(S)| = \frac{|T(f_s,f_c)|^2}{|T(f_n,f_c)|}\). Below we show how the FOM depends on frequency for the above filter. The proposed FOM makes it clearer that the filter must be at the signal frequency.

Figure-of-merit(FOM) of a high-pass filter

Summary

The above analysis is simplified but valid under various circumstances. When selecting the cutoff frequency of a given filter one must first consider to put this frequency as close as possible from the signal frequency, but not larger. However, if the total noise signal becomes negligible at smaller \(f_c\) values, then such values are preferred given that less signal will be lost. Also, a higher order filter can do a much better job at filtering than this simple RC filter. Finally, it is quite straightforward to achieve a similar conclusion for a low-pass RC filter to select a signal which has a frequency smaller than that of the relevant noise source.

Python code to produce the above plot:

%pylab inline

f = logspace(1,6,100)
fn = 100   # Noise freq.
fs = 1000  # Signal freq.
signal_transfer = fs/sqrt((fs**2+f**2))
noise_transfer  = fn/sqrt((fn**2+f**2))
sn_ratio = sqrt((fn**2+f**2)/(fs**2+f**2))
psig = semilogx(f, signal_transfer, label=r"$|T_{Signal}(f_c)|$")
pnoi = semilogx(f, noise_transfer , label=r"$|T_{Noise}(f_c)|$")
psnr = semilogx(f, sn_ratio       , label=r"(S/N ratio)$\cdot\frac{f_n}{f_s}$")
vlines(fs, 0, 1.0, color=vars(psig[0])['_color'], linestyle="dashed", label=r"$f_s=%d$ Hz"%fs)
vlines(fn, 0, 1.0, color=vars(pnoi[0])['_color'], linestyle="dashed", label=r"$f_n=%d$ Hz"%fn)
legend()
xlabel('$f_c$ (Hz)')
grid()
tight_layout()
savefig(r'assets\sn_ratio_hpf.svg')
%pylab inline

f = logspace(1,6,100)
fn = 100   # Noise freq.
fs = 1000  # Signal freq.
signal_transfer = fs/sqrt((fs**2+f**2))
noise_transfer  = fn/sqrt((fn**2+f**2))
sn_ratio = sqrt((fn**2+f**2)/(fs**2+f**2))
psig = semilogx(f, signal_transfer, label=r"$|T_{Signal}(f_c)|$")
pnoi = semilogx(f, noise_transfer , label=r"$|T_{Noise}(f_c)|$")
FOM = semilogx(f, sn_ratio * signal_transfer    , label=r"FOM")
vlines(fs, 0, 1.0, color=vars(psig[0])['_color'], linestyle="dashed", label=r"$f_s=%d$ Hz"%fs)
vlines(fn, 0, 1.0, color=vars(pnoi[0])['_color'], linestyle="dashed", label=r"$f_n=%d$ Hz"%fn)
legend()
xlabel('$f_c$ (Hz)')
grid()
tight_layout()
savefig(r'assets\sn_ratio_fom.svg')