A higher level interface to FFTW3 library is available in ISCE3 through isce3::signal::Signal. This templated Signal class allows to compute 1D fft in range or azimuth direction or 2D fft. Signal supports both real and complex data and can be applied on block of data.
The following header file is required:
Signal can be isntatiated for a multi-threaded FFT computation or for a signle thread computation.
For computing forward and inverse FFT with signle thread on real or complex float data, one can instatiate Signal as follows:
Similarly for double precision real or complex data, one can instantiate an object of Signal as:
For instantiating Signal to use the multi-threaded FFTW library, one can simply add the number of threads as follows:
For a forward transofrmation of a block of data, one needs to create the forward FFT plan which can be re-used many times for the actual transformation. To set up the FFT plans one need to have buffers defined for a block of data. For our applications we usually work on a two dimensional array of data. Given a block of data with number of lines of "length" and number of samples of "width" the required buffer can be defined as a std::valarray or as a raw pointer array:
Assuming the range (fast time) direction to be over the columns of an array, the forward FFT plan in range direction can be created as:
Assuming the azimuth (slow time) direction to be over the rows of an array, the forward FFT plan in azimuth direction can be created as:
Similarly to create forward 2D FFT plan one can call the
Once the required FFT plan is created for 1D transform in range or azimuth direction or for 2D transform, then the actual transformation can be done by calling isce3::signal::Signal::forward as:
Note that regardless of the created plan (range, azimuth or 2D), the transformation is computed using the same function.
Similar to Forward transformation, equivalent interfaces exist for inverse FFT transformation of a block of the spectrum.
Assuming the range (fast time) direction to be over the columns of an array, the inverse FFT plan in range direction can be created as:
The inverse FFT plan in azimuth direction can be created as:
Similarly, to create inverse 2D FFT plan, one can create an inverse FFT plan as follows:
Once the required FFT plan is created for 1D transformation in range or azimuth direction or for 2D transformation, then the actual transformation can be done by calling isce3::signal::Signal::inverse as:
Signal, follows FFTW3 convention and keeps the un-normalized FFT transformations as computed by FFTW3. This means that a forward FFT followed by an inverse FFT or vise versa results in the original signal scaled by length of fft. Depending on 1D transformation in range, azimuth or 2D transformation one may normalize the final results by dividing by length of FFT.
Assuming the data and spectrum blocks with a shape of (length x width) as introduced above, normalizing the results of forwrd and backward FFT computations in range, azimuth or 2D the final results should be divided by width, length or (widthxlength) respectively.
As described in FFTW3 documentation, FFTW is best at handling sizes of the form \(2^a\) \(3^b\) \(5^c\) \(7^d\) \(11^e\) \(13^f\), where \(e+f\) is either 0 or 1, and the other exponents are arbitrary. Other sizes are computed by means of a slow algorithm. Transforms whose sizes are powers of 2 are especially fast. Therefore a user of Signal may use isce3::signal::Signal::nextPowerOfTwo to compute the efficient length of signal and zero pad the signal accordingly before setting FFT plans.
Signal provides a function isce3::signal::Signal::upsample to upsample a block of data in range direction by a given oversampling factor. After creating the forward range FFT plan based on the original signal and the inverse range FFT plan based on the upsampled signal, then upsampling can be done by calling the upsample function. For example for a block of signal with shape of (nrows*width) zero padded to (nrows*nfft) where nfft is the next power of 2 for width, then the oversampling of the signal can be done as:
In case if shifting the upsampled signal in time-domain by a constant is desired, one can calculate the liner phase ramp in frequency domain introduced by the constant shift and pass this shift imapct as an extra argument to upsample function directly
For more examples see isce3::signal::Crossmul and also multiple unit tests in isce/tests/lib/isce/signal.