Interpolation

Interpolation

When we use phase truncation on a phasor whose frequency is low relative the tablesize and sampling rate, consecutive samples may not change. To counter this, we can use different methods of interpolation to more accurately represent the waveforms when the periods of the phasor are very small compared to the size of the table.

It is essentially the ratio between the period of the phasor and size of the table…

Linear Interpolation

Linear interpolation involves using the fractional part of the calculated phase to calculate the “distance” between the two points on which we lie. If, for instance, our calculated index is 32.76, we would need to look at both indexes 32 and 33. We would then take their respective values, `t[32]` and `t[33]`, calculate the difference between the latter index and the earlier, multiply by the fractional part, then add it to the index as we would in phase truncation:

 // calculate the fractional part
frac = index - int(index);

// get the difference and wrap the index (can also use a modulo)
while(index > tablesize)
    index = index - tablesize;

if (index == tablesize-1) 
    diff = t[0] - t[index]; // wrap
else
    diff = t[index+1] - t[index]; // no need to wrap

// get the interpolated output
out = t[index] + (diff * frac);

where `t` is the table filled with the sine wave and `index` is the calculated index with a phasor multiplied by the size of the table minus 1.

Hermite (Cubic) Interpolation

A more accurate interpolation technique is the Hermite or cubic method. What this method essentially does is to find the coefficients a, b, c, and d for the third degree polynomial f(x) and its derivative, f'(x), at x = 0 and x = 1.

\begin{aligned}& f(x) = ax^3 + bx^2 + cx + d \\ & f'(x) = 3ax^2 + 2bx + c \end{aligned}

Calculating the Coefficients

Given four points, (x0, y0), (x1, y1), (x2, y2), (x3, y3), we can calculate the coefficients with the following:

\begin{aligned} & a = -\frac{y_{0}}{2} + \frac{3y_{1}}{2} - \frac{3y_{2}}{2} + \frac{y_{3}}{2} \\ & b = y_{0} - \frac{5y_{1}}{2} + 2y_{2} - \frac{y_{3}}{2} \\ & c = -\frac{y_{0}}{2} + \frac{y_{2}}{2} \\ & d = y_{1} \end{aligned}
This is called the Catmull-Rom spline.

Calculating these coefficients and plugging them into the third degree polynomial (the first equation) gives us the cubic interpolative values between x = 0 and x = 1.

Putting it Together

Given an index i, we need to get the indices i-1, i, i+1, and i+2 to use them in our cubic interpolator.

float cubicInterpolator(float idx, float *table)
{
    long trunc = (long) idx; // truncate the index but don't overwrite
    float frac = idx - trunc; // get the fractional part

    // get the indices
    int x0 = wrap(trunc-1, tableSize-1);
    int x1 = wrap(trunc, tableSize-1);
    int x2 = wrap(trunc+1, tableSize-1);
    int x3 = wrap(trunc+2, tableSize-1);

    // calculate the coefficients
    float a = -0.5*table[x0] + 1.5*table[x1] - 1.5*table[x2] + 0.5*table[x3];
    float b = table[x0] - 2.5*table[x1] + 2.0*table[x2] - 0.5*table[x3];
    float c = -0.5*table[x0] + 0.5*table[x2];
    float d = table[x1];

    return (a*(frac*frac*frac) + b*(frac*frac) + c*frac + d);
}

Phase Truncation, Linear Interpolation, and Cubic Interpolation Compared

If we push this to an extreme to show the differences, this plot shows samples 32 to 64 of the same 100Hz sine wave lookup sampled at 8kHz using either phase truncation (purple), linear interpolation (green), or cubic interpolation (blue) from a tablesize of 16:

Listen

Listen to each of the different interpolation methods below. Be particularly aware of the differences at extremely high and low frequencies.

sine sweep with phase truncation
sine sweep with 2 point linear interpolation
sine sweep with 4 point cubic interpolation

Leave a Reply

Your email address will not be published.