Upsampling

From Hamsterworks Wiki!

Jump to: navigation, search

This is a little program I wrote to test optimizing upsampling.

It is equivalent to two processes.

  • Inserting seven zeros between samples
  • Passing that through a f/16 low-pass filter with 8x gain, giving overall unity gain. The filter uses a 63 term kernel (with an extra zero term to make it easy to code)

Because most of the convolution is with the inserted zeros it can be optimised to avoid 7/8ths of the multiplications.

/***************************************************************/
/* upsampling.c - a test 8x upsample and DSP filter program    */
/*                                                             */
/* Works by inserting seven zeros between each sample and then */
/* passes it through a low pass filter. Because of all the     */
/* zeros it can be simplified.                                 */
/***************************************************************/
#include <stdio.h>
#include <assert.h>
#include <math.h>

double lowpass_fir[64] = {
-0.000244141, -0.000488281, -0.000854492, -0.00146484, -0.002014160, -0.002319340, -0.001770020, 0.0000000,
 0.003417970,  0.008483890,  0.014587400,  0.02050780,  0.024231000,  0.023498500,  0.015930200, 0.0000000,
-0.024353000, -0.055114700, -0.087585400, -0.11474600, -0.127930000, -0.118042000, -0.077026400, 0.0000000,
 0.113464000,  0.258362000,  0.424133000,  0.59576400,  0.755554000,  0.885559000,  0.970459000, 1.0000000,
 0.970459000,  0.885559000,  0.755554000,  0.59576400,  0.424133000,  0.258362000,  0.113464000, 0.0000000,
-0.077026400, -0.118042000, -0.127930000, -0.11474600, -0.087585400, -0.055114700, -0.024353000, 0.0000000,
 0.015930200,  0.023498500,  0.024231000,  0.02050780,  0.014587400,  0.008483890,  0.003417970, 0.0000000,
-0.001770020, -0.002319340, -0.002014160, -0.00146484, -0.000854492, -0.000488281, -0.000244141, 0.0000000
};
#define TEST_SIGNAL_SIZE 32


double resample(double *signal, int fraction)
{
  int i;
  double total = 0;
  assert(fraction < 8);
  for(i = 0; i < 8;i++)
  {
    total = total + signal[i] * lowpass_fir[i*8+fraction];
  }
  return total;
}

int main(int argc, char *argv[])
{
  int i,j;
  double test_signal[TEST_SIGNAL_SIZE];
  for(i = 0; i < TEST_SIGNAL_SIZE; i++)
  {
     test_signal[i] = sin(i*(2*3.141592) / 6.0+0.001);

#if 1
     /* Convert to a square wave */
     if(test_signal[i] > 0.0) test_signal[i] = 1.0;
     else if(test_signal[i] < 0.0) test_signal[i] = -1.0;
#endif

  }
  for(i = 0; i < TEST_SIGNAL_SIZE; i++)
    printf("in  %3i  %13.10f\r\n",i, test_signal[i]);

  for(i = 0; i < TEST_SIGNAL_SIZE - 8; i++) {
    for(j=0; j < 8; j++) {
      double r = resample(test_signal+i,7-j);
      //printf("%2i+%i/8 %12.10f\r\n", i, j, r);
      printf("%12.10f\r\n", r);
    }
  }
 return 0;
}

And here is the result of sending in a square wave at f/6:

upsampled.jpg

Personal tools