FSM in C

The full Fast Sinc Magnification (FSM) [1] procedure consists of modified forward and inverse FFT algorithms. The forward part uses decimation-in-frequency (DIF) type FFT without the bit-reversal reordering. No other alterations are needed for the forward FFT and thus the C code listing is not provided here. The reader can take any such implementation as long as the reordering section is removed.

The inverse algorithm uses modified decimation-in-time (DIT) type FFT and incorporates the array extension, zero padding, multiplication with a transfer function, and short-cuts to avoid unnecessary multiplications and additions by zero. This is the novel part and the full C code listing is provided here. The code is based on [2], but the arrays start from index zero as is common to C language style and the sign of the exponent in Fourier formulas is opposite using the definitions of the paper [1].

For 2D or 3D data interpolation, the one-dimensional FSM is repeated many times for the same array size and interpolation factor. Thus, it is best to have a data structure for keeping together some frequently used information. Tables of pre-calculated cosines and sines are also used.

Data structure and initialization

#define REAL float

typedef struct _fsm {
  unsigned int  n;       /* Original array size  (must be power of two) */
  unsigned int  interp;  /* Interpolation factor (must be power of two) */
  double       *cosines; /* Table of cosines                            */
  double       *sines;   /* Table of sines                              */
  REAL         *imuls_r; /* Real multipliers, n floats   OR             */
  REAL         *imuls_c; /* Complex multipliers, 2*n floats             */
} FSMRec, *FSM;

The structure above is used for keeping together the information needed for the sinc interpolation. Member n is the size of the original array to be interpolated and member interp is the interpolation factor. Both of these values must be powers of two. Arrays cosines and sines hold the pre-calculated cosines and sines for angles 2π/(j+1), where j is the index to the arrays. The index starts from value 0 (C language) and the size of these arrays must be log2(n)+log2(interp)+2 entries both.

Either one of the last two arrays can be used for specifying a desired transfer function on top of the sinc interpolation. One of these must be NULL and the other one non-NULL. They contain either the real valued multipliers (imuls_r) or complex multipliers (imuls_c) for the Fourier transform of the transfer function. These arrays hold n multipliers both in bit-reversal order as they are used in the scrambled frequency domain. Values for the complex multipliers are encoded in the C language array imuls_c so that entries 0 and 1 contain the real and imaginary parts for multiplier 0, respectively. Entries 2 and 3 contain the real and imaginary parts for the next multiplier (array position 1 after bit reversal, position n/2 in the original order), and so on. The total lengths of these C language arrays are n for imuls_r and 2*n for imuls_c. The entries of the arrays must be scaled down by a factor of 1/n to incorporate the corresponding scaling for the inverse Fourier transform.

Typically, array imuls_r is used and set to value 1/n for all entries. This means simple sinc interpolation without any extra transfer function applied. If the interpolated values need to be translated, array imuls_c is used with appropriate entries.

Inverse transform

Here is the C code listing for the inverse Fourier transform part of the FSM. Argument fsm is a pointer to a structure explained above and data is a pointer to an array of floating point numbers. The array must be of length 2*n*interp where n and interp are the corresponding members of the fsm structure. When calling the function, data holds Fourier transform of the input signal in bit-reversal order. Entries data[0] and data[1] hold the real and imaginary part, respectively, for the first data point. Entries data[2] and data[3] hold the real and imaginary part for the next data point and so on. The function reads the first 2*n entries (n data points) and writes the corresponding sinc interpolated signal back to data. The initialization of the array from position 2*n to the end of array (position 2*n*interp-1) is not necessary as those values are not read from and are overwritten in the interpolation process.
void fsmi(const FSMRec *fsm, REAL *data) ...

[1] M. Seppä, "High-quality two-stage resampling for 3-D volumes in medical imaging", Medical Image Analysis, vol. 11, no. 4, pp. 346-360, 2007.
[2] W. H. Press, B. P. Flannery, S. A. Teukolsky, and W. T. Vetterling, Numerical Recipes in C. Cambridge: Cambridge University Press, 1988.