Electronic: The purpose of an oversampling filter

A few months ago, I’ve posted a note on an overdrive. The main issue of this kind of non-linear filter is aliasing, a process that adds digital acoustic content. The best way to solve the issue is to oversample the input before processing the signal.

Symptom of non-linear processing

Let’s try to check how the overdrive impacts the spectral content of the original signal. Let’s take the overdrive code of my last note. For a pure sinusoid, an analog filter adds frequencies proportional to the sinusoid’s frequency. As the next picture shows it in the numerical world, the spectral content aliases when frequency increases. It is thus mandatory to oversample the original signal, apply the non-linear process, filter it to remove the high frequencies and then undersample it.

Overdriven sin sweep

Let’s start with the oversampling.

Oversampling filter

When a signal is digitized at a sampling frequency of 48kHz (for instance), its content from -24khZ to 24kHz is reproduced from -infinity to infinity. When oversampling it, you can observe the content that will be reproduced.

Oversampling by copy padding

The goal of the oversampling filter is to remove the new spectrum from 24kHz to 48kHz. One solution may be to pad the original signal with zeros, but as can be seen in the next image, it doesn’t change a thing.

Oversampling by zero padding

So I’ve decided to use the optimal filter described in http://www.student.oulu.fi/~oniemita/dsp/deip.pdf for an oversample of 2. As can be seen, it’s a good compromise in term of performance.

Oversampling with a 6 points 5th order filter

The code in Python is the following one:

def oversample2_6point_5_order(signal):
  signal_ex = np.hstack((np.zeros((signal.shape[0], 2)), signal, np.zeros((signal.shape[0], 3))))[:,:,None]
 
  even1 = signal_ex[:,2:-3] + signal_ex[:,3:-2]
  even2 = signal_ex[:,1:-4] + signal_ex[:,4:-1]
  even3 = signal_ex[:,0:-5] + signal_ex[:,5:]
  odd1 = signal_ex[:,3:-2] - signal_ex[:,2:-3]
  odd2 = signal_ex[:,4:-1] - signal_ex[:,1:-4]
  odd3 = signal_ex[:,5:] - signal_ex[:,0:-5]
 
  c0 = even1 * 0.40513396007145713 + even2 * 0.09251794438424393 + even3 * 0.00234806603570670
  c1 = odd1 * 0.28342806338906690 + odd2 * 0.21703277024054901 + odd3 * 0.01309294748731515
  c2 = -even1 * 0.191337682540351941 + even2 * 0.16187844487943592 + even3 * 0.02946017143111912
  c3 = -odd1 * 0.16471626390554542 - odd2 * 0.00154547203542499 + odd3 * 0.03399271444851909
  c4 = even1 * 0.03845798729588149 - even2 * 0.05712936104242644 + even3 * 0.01866750929921070
  c5 = odd1 * 0.04317950185225609 - odd2 * 0.01802814255926417 + odd3 * 0.00152170021558204
 
  z = np.array((-1./2, 0), dtype = np.float32)[None,None,:]
 
  return (((((c5 * z + c4) * z + c3) * z + c2) * z + c1) * z + c0).reshape(2, -1)

Overdrive

Let’s overdrive this oversampled signal, which gives the following solution (I came back to a 48kHz-sampled signal).

Overdrive an oversampled signal

If this signal is directly undersampled, an aliasing occurs (lower than before, but it is still important):

Undersampling the overdriven signal

It is thus mandatory to filter the signal. Let’s try a 8th order Bessel:

Filtering the overdriven signal

Now, the signal can be undersampled:

Undersampling the filtered signal

Let’s face it, it is far from perfect. This is due to several facts:

  • The original signal should have a higher sampling frequency.
  • The oversample factor should be higher.
  • Of course, I’ve used an extreme overdrive.

Just to give an example, here is the same signal with a sampling frequency of 88.2kHz (the most efficient/accessible sampling frequency for a CD/44.1kHz production IMHO).

Overdrive of a 88.2kHz sampled signal

Undersampling a filtered overdriven signal with an original frequency of 88.2kHz

Conclusion

Some digital filters are not linear, and they can’t be applied as is in digital audio processing. The same even happens for a linear filter like a low-pass with a high cut frequency, near the Nyquist frequency. Oversampling the signal will help designing a correct filter that will mimic an analog filter.

Now, I still have to implement this process in C++, because in Python the Newton optimization takes too much time.

The code of this experiment is available on github.

Buy Me a Coffee!
Other Amount:
Your Email Address:

Leave a Reply