📄 fftw.texi
字号:
@ifhtml<p align=center>r<sub>0</sub>, r<sub>1</sub>, r<sub>2</sub>, ..., r<sub>n/2</sub>, i<sub>(n+1)/2-1</sub>, ..., i<sub>2</sub>, i<sub>1</sub></p>@end ifhtmlHere,@ifinfork@end ifinfo@tex$r_k$@end tex@ifhtmlr<sub>k</sub>@end ifhtmlis the real part of the @math{k}th output, and@ifinfoik@end ifinfo@tex$i_k$@end tex@ifhtmli<sub>k</sub>@end ifhtmlis the imaginary part. (We follow here the C convention that integerdivision is rounded down, e.g. @math{7 / 2 = 3}.) For a halfcomplexarray @code{hc[]}, the @math{k}th component has its real part in@code{hc[k]} and its imaginary part in @code{hc[n-k]}, with theexception of @code{k} @code{==} @code{0} or @code{n/2} (the latter onlyif n is even)---in these two cases, the imaginary part is zero due tosymmetries of the real-complex transform, and is not stored. Thus, thetransform of @code{n} real values is a halfcomplex array of length@code{n}, and vice versa. @footnote{The output for themulti-dimensional rfftw is a more-conventional array of@code{fftw_complex} values, but the format here permitted us greaterefficiency in one dimension.} This is actually only half of the DFTspectrum of the data. Although the other half can be obtained bycomplex conjugation, it is not required by many applications such asconvolution and filtering.Like the complex transforms, the RFFTW transforms are unnormalized, so aforward followed by a backward transform (or vice-versa) yields theoriginal data scaled by the length of the array, @code{n}.@cindex normalizationLet us reiterate here our warning that an @code{FFTW_COMPLEX_TO_REAL}transform has the side-effect of destroying its (halfcomplex) input.The @code{FFTW_REAL_TO_COMPLEX} transform, however, leaves its (real)input untouched, just as you would hope.As an example, here is an outline of how you might use RFFTW to computethe power spectrum of a real array (i.e. the squares of the absolutevalues of the DFT amplitudes):@cindex power spectrum@example#include <rfftw.h>...@{ fftw_real in[N], out[N], power_spectrum[N/2+1]; rfftw_plan p; int k; ... p = rfftw_create_plan(N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE); ... rfftw_one(p, in, out); power_spectrum[0] = out[0]*out[0]; /* DC component */ for (k = 1; k < (N+1)/2; ++k) /* (k < N/2 rounded up) */ power_spectrum[k] = out[k]*out[k] + out[N-k]*out[N-k]; if (N % 2 == 0) /* N is even */ power_spectrum[N/2] = out[N/2]*out[N/2]; /* Nyquist freq. */ ... rfftw_destroy_plan(p);@}@end examplePrograms using RFFTW should link with @code{-lrfftw -lfftw -lm} on Unix,or with the FFTW, RFFTW, and math libraries in general.@cindex linking on Unix@node Real Multi-dimensional Transforms Tutorial, Multi-dimensional Array Format, Real One-dimensional Transforms Tutorial, Tutorial@section Real Multi-dimensional Transforms Tutorial@cindex real multi-dimensional transformFFTW includes multi-dimensional transforms for real data of any rank.As with the one-dimensional real transforms, they save roughly a factorof two in time and storage over complex transforms of the same size.Also as in one dimension, these gains come at the expense of someincrease in complexity---the output format is different from theone-dimensional RFFTW (and is more similar to that of the complex FFTW)and the inverse (complex to real) transforms have the side-effect ofoverwriting their input data. To use the real multi-dimensional transforms, you first @code{#include<rfftw.h>} and then create a plan for the size and direction oftransform that you are interested in:@examplerfftwnd_plan rfftwnd_create_plan(int rank, const int *n, fftw_direction dir, int flags);@end example@tindex rfftwnd_plan@findex rfftwnd_create_planThe first two parameters describe the size of the real data (not thehalfcomplex data, which will have different dimensions). The last twoparameters are the same as those for @code{rfftw_create_plan}. Just asfor fftwnd, there are two alternate versions of this routine,@code{rfftw2d_create_plan} and @code{rfftw3d_create_plan}, that aresometimes more convenient for two- and three-dimensional transforms.@findex rfftw2d_create_plan@findex rfftw3d_create_planAlso as in fftwnd, rfftwnd supports true in-place transforms, specifiedby including @code{FFTW_IN_PLACE} in the flags.Once created, a plan can be used for any number of transforms, and isdeallocated by calling @code{rfftwnd_destroy_plan(plan)}.Given a plan, the transform is computed by calling one of the followingtwo routines:@examplevoid rfftwnd_one_real_to_complex(rfftwnd_plan plan, fftw_real *in, fftw_complex *out);void rfftwnd_one_complex_to_real(rfftwnd_plan plan, fftw_complex *in, fftw_real *out);@end example@findex rfftwnd_one_real_to_complex@findex rfftwnd_one_complex_to_realAs is clear from their names and parameter types, the former function isfor @code{FFTW_REAL_TO_COMPLEX} transforms and the latter is for@code{FFTW_COMPLEX_TO_REAL} transforms. (We could have used only asingle routine, since the direction of the transform is encoded in theplan, but we wanted to correctly express the datatypes of theparameters.) The latter routine, as we discuss elsewhere, has theside-effect of overwriting its input (except when the rank of the arrayis one). In both cases, the @code{out} parameter is ignored forin-place transforms.The format of the complex arrays deserves careful attention.@cindex rfftwnd array formatSuppose that the real data has dimensions@tex$n_1 \times n_2 \times \cdots \times n_d$@end tex@ifinfon1 x n2 x ... x nd@end ifinfo@ifhtmln<sub>1</sub> x n<sub>2</sub> x ... x n<sub>d</sub>@end ifhtml(in row-major order). Then, after a real-to-complex transform, theoutput is an@tex$n_1 \times n_2 \times \cdots \times (n_d/2+1)$@end tex@ifinfon1 x n2 x ... x (nd/2+1)@end ifinfo@ifhtmln<sub>1</sub> x n<sub>2</sub> x ... x (n<sub>d</sub>/2+1)@end ifhtmlarray of @code{fftw_complex} values in row-major order, corresponding toslightly over half of the output of the corresponding complex transform.(Note that the division is rounded down.) The ordering of the data isotherwise exactly the same as in the complex case. (In principle, theoutput could be exactly half the size of the complex transform output,but in more than one dimension this requires too complicated a format tobe practical.) Note that, unlike the one-dimensional RFFTW, the realand imaginary parts of the DFT amplitudes are here stored together inthe natural way.Since the complex data is slightly larger than the real data, somecomplications arise for in-place transforms. In this case, the finaldimension of the real data must be padded with extra values toaccommodate the size of the complex data---two extra if the lastdimension is even and one if it is odd.@cindex paddingThat is, the last dimension of the real data must physically contain@tex$2 (n_d/2+1)$@end tex@ifinfo2 * (nd/2+1)@end ifinfo@ifhtml2 * (n<sub>d</sub>/2+1)@end ifhtml@code{fftw_real} values (exactly enough to hold the complex data).This physical array size does not, however, change the @emph{logical}array size---only@tex$n_d$@end tex@ifinfond@end ifinfo@ifhtmln<sub>d</sub>@end ifhtmlvalues are actually stored in the last dimension, and@tex$n_d$@end tex@ifinfond@end ifinfo@ifhtmln<sub>d</sub>@end ifhtmlis the last dimension passed to @code{rfftwnd_create_plan}.For example, consider the transform of a two-dimensional real array ofsize @code{nx} by @code{ny}. The output of the @code{rfftwnd} transformis a two-dimensional complex array of size @code{nx} by @code{ny/2+1},where the @code{y} dimension has been cut nearly in half because ofredundancies in the output. Because @code{fftw_complex} is twice thesize of @code{fftw_real}, the output array is slightly bigger than theinput array. Thus, if we want to compute the transform in place, wemust @emph{pad} the input array so that it is of size @code{nx} by@code{2*(ny/2+1)}. If @code{ny} is even, then there are two paddingelements at the end of each row (which need not be initialized, as theyare only used for output).@ifhtmlThe following illustration depicts the input and output arrays justdescribed, for both the out-of-place and in-place transforms (with thearrows indicating consecutive memory locations):<p align=center><img src="rfftwnd.gif" width=389 height=583>@end ifhtml@texFigure 1 depicts the input and output arrays justdescribed, for both the out-of-place and in-place transforms (with thearrows indicating consecutive memory locations).{\pageinsert\vfill\vskip405pt\hskip40pt\special{psfile="rfftwnd.eps" }\vskip 24ptFigure 1: Illustration of the data layout for real to complextransforms. \vfill\endinsert}@end texThe RFFTWND transforms are unnormalized, so a forward followed by abackward transform will result in the original data scaled by the numberof real data elements---that is, the product of the (logical) dimensionsof the real data.@cindex normalizationBelow, we illustrate the use of RFFTWND by showing how you might use itto compute the (cyclic) convolution of two-dimensional real arrays@code{a} and @code{b} (using the identity that a convolution correspondsto a pointwise product of the Fourier transforms). For variety,in-place transforms are used for the forward FFTs and an out-of-placetransform is used for the inverse transform.@cindex convolution@cindex cyclic convolution@example#include <rfftw.h>...@{ fftw_real a[M][2*(N/2+1)], b[M][2*(N/2+1)], c[M][N]; fftw_complex *A, *B, C[M][N/2+1]; rfftwnd_plan p, pinv; fftw_real scale = 1.0 / (M * N); int i, j; ... p = rfftw2d_create_plan(M, N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE | FFTW_IN_PLACE); pinv = rfftw2d_create_plan(M, N, FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE); /* aliases for accessing complex transform outputs: */ A = (fftw_complex*) &a[0][0]; B = (fftw_complex*) &b[0][0]; ... for (i = 0; i < M; ++i) for (j = 0; j < N; ++j) @{ a[i][j] = ... ; b[i][j] = ... ; @} ... rfftwnd_one_real_to_complex(p, &a[0][0], NULL); rfftwnd_one_real_to_complex(p, &b[0][0], NULL); for (i = 0; i < M; ++i) for (j = 0; j < N/2+1; ++j) @{ int ij = i*(N/2+1) + j; C[i][j].re = (A[ij].re * B[ij].re - A[ij].im * B[ij].im) * scale; C[i][j].im = (A[ij].re * B[ij].im + A[ij].im * B[ij].re) * scale; @} /* inverse transform to get c, the convolution of a and b; this has the side effect of overwriting C */ rfftwnd_one_complex_to_real(pinv, &C[0][0], &c[0][0]); ... rfftwnd_destroy_plan(p); rfftwnd_destroy_plan(pinv);@}@end exampleWe access the complex outputs of the in-place transforms by castingeach real array to a @code{fftw_complex} pointer. Because this is a``flat'' pointer, we have to compute the row-major index @code{ij}explicitly in the convolution product loop.@cindex row-majorIn order to normalize the convolution, we must multiply by a scalefactor---we can do so either before or after the inverse transform, andchoose the former because it obviates the necessity of an additionalloop.@cindex normalizationNotice the limits of the loops and the dimensions of the various arrays.As with the one-dimensional RFFTW, an out-of-place@code{FFTW_COMPLEX_TO_REAL} transform has the side-effect of overwriting
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -