Oversampling

One common technique in Digital Signal Processing is Oversampling. Oversampling is often necessary when modeling filters that come from electric circuits or that present nonlinearities or that can become unstable for certain parameters.

In order to oversample a filter we need for every sample perform N steps. I a language like Vult, that hides the internal memory of a function, oversampling may seem not very obvious.

In order to perform oversampling, we are gonna use a feature of Vult that allow us to name and reuse the memory created by a function.

In the previous tutorial Easy DSP with Vult we coded the following low pass filter.

fun lowpass(x,w0,q) { mem b0,b1,b2,a1,a2; if(change(w0) || change(q)) { val cos_w = cos(w0); val alpha = sin(w0)/(2.0q); val den = 1.0 + alpha; a1 = (-2.0cos_w)/den; a2 = (1.0-alpha)/den; b0 = (1.0-cos_w)/(2.0den); b1 = (1.0-cos_w)/den; b2 = (1.0-cos_w)/(2.0den); } return biquad(x,b0,b1,b2,a1,a2); }

This filter becomes unstable when the parameter q is high and the frequency w0 approaching 2Pi for that reason we cannot completely open the filter.

The following code shows the low pass filter with 2x of oversampling:

First we need to fix the frequency w0. From Audio-EQ-Cookbook we have the formula w0 = 2*pi*f0/Fs, since we have double the sampling rate, it is enough to divide the original w0 by two. Then we use the feature of Vult that allow us to name the context of a function and reuse them. By preceding a call of a function with memory with an identifier and colon we can assign a name to the context e.g. inst:lowpass(...). If we want to call again the function and not creating a new context we have to use the same name.

if we want to create modify the filter above and make it stereo we can do it as follows:

Notice that we have named the contexts of the functions left and right. In a similar way, we can easily make this filter with 4x of oversampling.

In the next tutorial we are gonna learn how to export code to C/C++.