Guest User

convsinc (DPreview)

a guest
Sep 20th, 2014
259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.55 KB | None | 0 0
  1. /*
  2.  convsinc.c
  3.  
  4.  Simple demo of a sinc-based convolution used to downsample a data vector to
  5.  demonstrate the absence of "ringing" when using sinc filtering to downsample data.
  6.  See e.g. http://en.wikipedia.org/wiki/Sinc_filter for some info on sinc convolution.
  7.  
  8.  Written, and put in the public domain by Antisthenes@[DPreview forums] 2014/09/21
  9.  Related link: http://www.dpreview.com/forums/post/54423989
  10.  
  11.  On a Unix-like system, compile with:
  12.    cc -lm -o convsinc convsinc.c
  13.  
  14.  Run:
  15.    ./convsinc
  16.  
  17.  Output:
  18.    The program will then blurp out the numerical values of the downsampled data.
  19.    I'm lazy, so there are no fancy graphs or anything.
  20.  */
  21.  
  22.  
  23. #define ORIGINAL_WIDTH      55
  24. #define DOWNSAMPLED_WIDTH   29
  25.  
  26. // Number of "half-periods" of the sin(x)/x function we'll use in the convolution.
  27. // Increasing this number increases the computation time.  7 already provides a
  28. // good accuracy.
  29. #define CONVOLUTION_SPAN    7
  30.  
  31. // Define this symbol as "step", "pulse" or "squarewave" to specify the type
  32. // of function with which the original data should be initialized with.
  33. #define INITIALIZE_WITH     step
  34.  
  35.  
  36. // In principle, nothing needs to be changed / configured in the source code
  37. // from below this comment to run this trivial demo...
  38.  
  39. // step:
  40. //       _____
  41. //      |
  42. // _____|
  43.  
  44. // pulse:
  45. //
  46. //      |
  47. //______|______
  48.  
  49. // square:
  50. //       _____       _____       _____
  51. //      |     |     |     |     |     |
  52. // _____|     |_____|     |_____|     |
  53.  
  54. // sine:
  55. //   _       _       _
  56. //  / \     / \     / \
  57. // /   \   /   \   /   \   /
  58. //      \_/     \_/     \_/
  59.  
  60. enum F_TYPE {
  61.     step,
  62.     pulse,
  63.     square,
  64.     sine
  65. };
  66.  
  67. #define _USE_MATH_DEFINES
  68.  
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <math.h>
  72.  
  73. int main(int argc, const char * argv[])
  74. {
  75.     int
  76.         i, j, s, originalWidth, downsampledWidth;
  77.     double
  78.          *originalData, *downsampledData, *ptr1, *ptr2, accumulator, scaleFactor, x, d;
  79.     enum F_TYPE
  80.         initializationType = INITIALIZE_WITH;
  81.  
  82.     originalWidth = ORIGINAL_WIDTH;
  83.     downsampledWidth = DOWNSAMPLED_WIDTH;
  84.     if( argc > 1 ) {
  85.         originalWidth = atoi( argv[1] );
  86.         if( argc > 2 )
  87.             downsampledWidth = atoi( argv[2] );
  88.     }
  89.  
  90.     downsampledData = (double *) malloc( downsampledWidth * sizeof(double) );
  91.  
  92.     /*
  93.      In addition to space to hold the original data to be downsampled, we also allocate
  94.      some buffer space "left" and "right" of the original data and fill it with dummy data.
  95.      This buffer space / dummy data on the side makes the convolution algorithm cleaner as
  96.      we don't have to worry about the "edges" of the convolution window.
  97.     */
  98.     originalData = (double *) malloc( (CONVOLUTION_SPAN * 2 + originalWidth) * sizeof(double) );
  99.  
  100.     // Initialize the original data
  101.     ptr1 = originalData;
  102.     switch ( initializationType ) {
  103.         case step:
  104.             // Fill everything, including the left and right buffer zones, with initial data
  105.             for ( i = 0; i < (CONVOLUTION_SPAN * 2 + originalWidth) / 2; i++ )
  106.                 *ptr1++ = 1;
  107.             for (  ; i < (CONVOLUTION_SPAN * 2 + originalWidth); i++ )
  108.                 *ptr1++ = 2;
  109.             break;
  110.  
  111.         case pulse:
  112.             for ( i = 0; i < (CONVOLUTION_SPAN * 2 + originalWidth); i++ )
  113.                 *ptr1++ = 1;
  114.             originalData[ (CONVOLUTION_SPAN * 2 + originalWidth) / 2 ] = 2;
  115.             break;
  116.            
  117.         case square:
  118.             s = originalWidth / 6;
  119.             for ( i = 0; i < (CONVOLUTION_SPAN * 2 + originalWidth); i++ )
  120.                 *ptr1++ = 1;
  121.             ptr1 = originalData + CONVOLUTION_SPAN + s;
  122.             for ( i = 0; i < 3; i++ ) {
  123.                 for ( j = 0; j < s; j++ )
  124.                     *ptr1++ = 2;
  125.                 ptr1 += s;
  126.             }
  127.             break;
  128.            
  129.         case sine:
  130.             scaleFactor = 6 * M_PI / originalWidth;
  131.             for ( i = -CONVOLUTION_SPAN; i < (CONVOLUTION_SPAN + originalWidth); i++ )
  132.                 *ptr1++ = sin( i * scaleFactor );
  133.             break;
  134.            
  135.         default:
  136.             fprintf(stderr, "Unsupported initialization function type" );
  137.             exit( -1 );
  138.     }
  139.  
  140.     // Convolve and downsample the original data into a new, smaller vector
  141.     scaleFactor = (M_PI * originalWidth) / downsampledWidth;
  142.     ptr2 = downsampledData;
  143.     for ( d = 0; d < downsampledWidth; d++) {
  144.         accumulator = 0;
  145.         i = (.5 + originalWidth * d / downsampledWidth );
  146.         ptr1 = originalData + i;
  147.         for ( i = -CONVOLUTION_SPAN; i <= CONVOLUTION_SPAN; i++) {
  148.             x = i * M_PI;
  149.             if ( fabs(x) < 1e-6 )
  150.                 accumulator += *ptr1++;
  151.             else
  152.                 accumulator += *ptr1++ * sin( x ) / x;
  153.         }
  154.         *ptr2++ = accumulator;
  155.     }
  156.  
  157.     // Output the results
  158.     ptr2 = downsampledData;
  159.     for ( i = 0; i < downsampledWidth; i++)
  160.         printf( "%.9lf\n", *ptr2++ );
  161.  
  162.     return 0;
  163. }
Advertisement
Add Comment
Please, Sign In to add comment