File Coverage

blib/lib/PDL/FFT.pm
Criterion Covered Total %
statement 45 49 91.8
branch 16 20 80.0
condition n/a
subroutine 5 5 100.0
pod 0 2 0.0
total 66 76 86.8


line stmt bran cond sub pod time code
1             #
2             # GENERATED WITH PDL::PP from lib/PDL/FFT.pd! Don't modify!
3             #
4             package PDL::FFT;
5              
6             our @EXPORT_OK = qw(fft ifft fftnd ifftnd fftconvolve realfft realifft kernctr );
7             our %EXPORT_TAGS = (Func=>\@EXPORT_OK);
8              
9 5     5   5044 use PDL::Core;
  5         10  
  5         51  
10 5     5   41 use PDL::Exporter;
  5         14  
  5         29  
11 5     5   29 use DynaLoader;
  5         9  
  5         5902  
12              
13              
14            
15             our @ISA = ( 'PDL::Exporter','DynaLoader' );
16             push @PDL::Core::PP, __PACKAGE__;
17             bootstrap PDL::FFT ;
18              
19              
20              
21              
22              
23              
24              
25              
26             #line 12 "lib/PDL/FFT.pd"
27              
28             =head1 NAME
29              
30             PDL::FFT - FFTs for PDL
31              
32             =head1 DESCRIPTION
33              
34             !!!!!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
35             As of PDL-2.006_04, the direction of the FFT/IFFT has been
36             reversed to match the usage in the FFTW library and the convention
37             in use generally.
38             !!!!!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
39              
40             FFTs for PDL. These work for arrays of any dimension, although ones
41             with small prime factors are likely to be the quickest. The forward
42             FFT is unnormalized while the inverse FFT is normalized so that the
43             IFFT of the FFT returns the original values.
44              
45             For historical reasons, these routines work in-place and do not recognize
46             the in-place flag. That should be fixed.
47              
48             =head1 SYNOPSIS
49              
50             use PDL::FFT qw/:Func/;
51              
52             fft($real, $imag);
53             ifft($real, $imag);
54             realfft($real);
55             realifft($real);
56              
57             fftnd($real,$imag);
58             ifftnd($real,$imag);
59              
60             $kernel = kernctr($image,$smallk);
61             fftconvolve($image,$kernel);
62              
63             =head1 DATA TYPES
64              
65             The underlying C library upon which this module is based performs FFTs
66             on both single precision and double precision floating point ndarrays.
67             The PP functions are defined to only take those data types.
68             Therefore, if you pass in an ndarray of integer datatype (byte, short,
69             ushort, long) to any of the routines in PDL::FFT, your data will be
70             promoted to a double-precision ndarray. If you pass in a float, the
71             single-precision FFT will be performed.
72              
73             =head1 FREQUENCIES
74              
75             For even-sized input arrays, the frequencies are packed like normal
76             for FFTs (where N is the size of the array and D is the physical step
77             size between elements):
78              
79             0, 1/ND, 2/ND, ..., (N/2-1)/ND, 1/2D, -(N/2-1)/ND, ..., -1/ND.
80              
81             which can easily be obtained (taking the Nyquist frequency to be
82             positive) using
83              
84             C<< $kx = $real->xlinvals(-($N/2-1)/$N/$D,1/2/$D)->rotate(-($N/2 -1)); >>
85              
86             For odd-sized input arrays the Nyquist frequency is not directly
87             acessible, and the frequencies are
88              
89             0, 1/ND, 2/ND, ..., (N/2-0.5)/ND, -(N/2-0.5)/ND, ..., -1/ND.
90              
91             which can easily be obtained using
92              
93             C<< $kx = $real->xlinvals(-($N/2-0.5)/$N/$D,($N/2-0.5)/$N/$D)->rotate(-($N-1)/2); >>
94              
95             =head1 ALTERNATIVE FFT PACKAGES
96              
97             Various other modules - such as L and L -
98             contain FFT routines.
99             However, unlike PDL::FFT, these modules are optional,
100             and so may not be installed.
101              
102             =cut
103             #line 104 "lib/PDL/FFT.pm"
104              
105              
106             =head1 FUNCTIONS
107              
108             =cut
109              
110              
111              
112              
113              
114              
115             =head2 fft
116              
117             =for sig
118              
119             Signature: ([io]real(n); [io]imag(n))
120             Types: (float double ldouble)
121              
122             =for usage
123              
124             fft($real, $imag); # all arguments given
125             $real->fft($imag); # method call
126              
127             =for ref
128              
129             Complex 1-D FFT of the "real" and "imag" arrays [inplace]. A single
130             cfloat/cdouble input ndarray can also be used.
131              
132             =pod
133              
134             Broadcasts over its inputs.
135              
136             =for bad
137              
138             C does not process bad values.
139             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
140              
141             =cut
142              
143              
144              
145              
146             sub PDL::fft {
147             # Convert the first argument to decimal and check for trouble.
148 42     42 0 3689 my ($re, $im) = @_;
149 42 100       154 if (!$re->type->real) {
150 3         130 $im=$re->im;
151 3         47 $re=$re->re;
152             }
153 42         78 eval { todecimal($re); };
  42         161  
154 42 50       129 if ($@) {
155 0         0 $@ =~ s/ at .*//s;
156 0         0 barf("Error in FFT with first argument: $@");
157             }
158             # Convert the second argument to decimal and check for trouble.
159 42         55 eval { todecimal($im); };
  42         120  
160 42 100       120 if ($@) {
161 1         11 $@ =~ s/ at .*//s;
162 1         3 my $message = "Error in FFT with second argument: $@";
163 1 50       8 $message .= '. Did you forget to supply the second (imaginary) ndarray?'
164             if ($message =~ /undefined value/);
165 1         5 barf($message);
166             }
167 41         791548 PDL::_fft_int($re,$im);
168 41 100       437 if (!$_[0]->type->real) {
169 3         4532 $_[0]= czip($re, $im);
170             } else {
171 38         406 $_[0]=$re,$_[1]=$im;
172             }
173             }
174              
175              
176              
177             *fft = \&PDL::fft;
178              
179              
180              
181              
182              
183              
184             =head2 ifft
185              
186             =for sig
187              
188             Signature: ([io]real(n); [io]imag(n))
189             Types: (float double ldouble)
190              
191             =for usage
192              
193             ifft($real, $imag); # all arguments given
194             $real->ifft($imag); # method call
195              
196             =for ref
197              
198             Complex inverse 1-D FFT of the "real" and "imag" arrays [inplace]. A single
199             cfloat/cdouble input ndarray can also be used.
200              
201             =pod
202              
203             Broadcasts over its inputs.
204              
205             =for bad
206              
207             C does not process bad values.
208             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
209              
210             =cut
211              
212              
213              
214              
215             sub PDL::ifft {
216             # Convert the first argument to decimal and check for trouble.
217 24     24 0 83 my ($re, $im) = @_;
218 24 100       103 if (!$re->type->real) {
219 3         42 $im=$re->im;
220 3         23 $re=$re->re;
221             }
222 24         64 eval { todecimal($re); };
  24         85  
223 24 50       77 if ($@) {
224 0         0 $@ =~ s/ at .*//s;
225 0         0 barf("Error in FFT with first argument: $@");
226             }
227             # Convert the second argument to decimal and check for trouble.
228 24         51 eval { todecimal($im); };
  24         52  
229 24 100       62 if ($@) {
230 1         9 $@ =~ s/ at .*//s;
231 1         3 my $message = "Error in FFT with second argument: $@";
232 1 50       8 $message .= '. Did you forget to supply the second (imaginary) ndarray?'
233             if ($message =~ /undefined value/);
234 1         5 barf($message);
235             }
236 23         620072 PDL::_ifft_int($re,$im);
237 23 100       256 if (!$_[0]->type->real) {
238 3         4394 $_[0]= czip($re, $im);
239             } else {
240 20         95 $_[0]=$re,$_[1]=$im;
241             }
242             }
243              
244              
245              
246             *ifft = \&PDL::ifft;
247              
248              
249              
250              
251              
252             #line 180 "lib/PDL/FFT.pd"
253              
254             use Carp;
255             use PDL::Core qw/:Func/;
256             use PDL::Basic qw/:Func/;
257             use PDL::Types;
258             use PDL::ImageND qw/kernctr/; # moved to ImageND since FFTW uses it too
259             use PDL::Ops qw/czip/;
260              
261             sub todecimal {
262             my ($arg) = @_;
263             $arg = $arg->double if $arg->type->integer;
264             $_[0] = $arg;
265             1;}
266              
267             =head2 realfft()
268              
269             =for ref
270              
271             One-dimensional FFT of real function [inplace].
272              
273             The real part of the transform ends up in the first half of the array
274             and the imaginary part of the transform ends up in the second half of
275             the array.
276              
277             =for usage
278              
279             realfft($real);
280              
281             =cut
282              
283             *realfft = \&PDL::realfft;
284              
285             sub PDL::realfft {
286             barf("Usage: realfft(real(*)") if $#_ != 0;
287             my ($x) = @_;
288             todecimal($x);
289             # FIX: could eliminate $y
290             my ($y) = 0*$x;
291             fft($x,$y);
292             my ($n) = int((($x->dims)[0]-1)/2); my($t);
293             ($t=$x->slice("-$n:-1")) .= $y->slice("1:$n");
294             undef;
295             }
296              
297             =head2 realifft()
298              
299             =for ref
300              
301             Inverse of one-dimensional realfft routine [inplace].
302              
303             =for usage
304              
305             realifft($real);
306              
307             =cut
308              
309             *realifft = \&PDL::realifft;
310              
311             sub PDL::realifft {
312             use PDL::Ufunc 'max';
313             barf("Usage: realifft(xfm(*)") if $#_ != 0;
314             my ($x) = @_;
315             todecimal($x);
316             my ($n) = int((($x->dims)[0]-1)/2); my($t);
317             # FIX: could eliminate $y
318             my ($y) = 0*$x;
319             ($t=$y->slice("1:$n")) .= $x->slice("-$n:-1");
320             ($t=$x->slice("-$n:-1")) .= $x->slice("$n:1");
321             ($t=$y->slice("-$n:-1")) .= -$y->slice("$n:1");
322             ifft($x,$y);
323             # Sanity check -- shouldn't happen
324             carp "Bad inverse transform in realifft" if max(abs($y)) > 1e-6*max(abs($x));
325             undef;
326             }
327              
328             =head2 fftnd()
329              
330             =for ref
331              
332             N-dimensional FFT over all pdl dims of input (inplace)
333              
334             =for example
335              
336             fftnd($real,$imag);
337              
338             =cut
339              
340             *fftnd = \&PDL::fftnd;
341              
342             sub PDL::fftnd {
343             my ($r,$i) = @_;
344             barf "Must have real and imaginary parts or complex for fftnd"
345             if $r->type->real and @_ != 2;
346             if (!$r->type->real) {
347             $i=$r->im;
348             $r=$r->re;
349             }
350             my ($n) = $r->getndims;
351             barf "Dimensions of real and imag must be the same for fft"
352             if ($n != $i->getndims);
353             $n--;
354             todecimal($r);
355             todecimal($i);
356             # need the copy in case $r and $i point to same memory
357             $i = $i->copy;
358             foreach (0..$n) {
359             fft($r,$i);
360             $r = $r->mv(0,$n) if 0 != $n;
361             $i = $i->mv(0,$n) if 0 != $n;
362             }
363             if (!$_[0]->type->real) {
364             $_[0]= czip($r, $i);
365             } else {
366             $_[0] = $r; $_[1] = $i;
367             }
368             undef;
369             }
370              
371             =head2 ifftnd()
372              
373             =for ref
374              
375             N-dimensional inverse FFT over all pdl dims of input (inplace)
376              
377             =for example
378              
379             ifftnd($real,$imag);
380              
381             =cut
382              
383             *ifftnd = \&PDL::ifftnd;
384              
385             sub PDL::ifftnd {
386             my ($r,$i) = @_;
387             barf "Must have real and imaginary parts or complex for ifftnd"
388             if $r->type->real and @_ != 2;
389             if (!$r->type->real) {
390             $i=$r->im;
391             $r=$r->re;
392             }
393             my ($n) = $r->getndims;
394             barf "Dimensions of real and imag must be the same for ifft"
395             if ($n != $i->getndims);
396             todecimal($r);
397             todecimal($i);
398             # need the copy in case $r and $i point to same memory
399             $i = $i->copy;
400             $n--;
401             foreach (0..$n) {
402             ifft($r,$i);
403             $r = $r->mv(0,$n) if 0 != $n;
404             $i = $i->mv(0,$n) if 0 != $n;
405             }
406             if (!$_[0]->type->real) {
407             $_[0]= czip($r, $i);
408             } else {
409             $_[0] = $r; $_[1] = $i;
410             }
411             undef;
412             }
413              
414             =head2 fftconvolve()
415              
416             =for ref
417              
418             N-dimensional convolution with periodic boundaries (FFT method)
419              
420             =for usage
421              
422             $kernel = kernctr($image,$smallk);
423             fftconvolve($image,$kernel);
424              
425             fftconvolve works inplace, and returns an error array in kernel as an
426             accuracy check -- all the values in it should be negligible.
427              
428             See also L, which
429             performs speed-optimized convolution with a variety of boundary conditions.
430              
431             The sizes of the image and the kernel must be the same.
432             L centres a small kernel to emulate the
433             behaviour of the direct convolution routines.
434              
435             The speed cross-over between using straight convolution
436             (L) and
437             these fft routines is for kernel sizes roughly 7x7.
438              
439             =cut
440              
441             *fftconvolve = \&PDL::fftconvolve;
442              
443             sub PDL::fftconvolve {
444             barf "Must have image & kernel for fftconvolve" if $#_ != 1;
445             my ($im, $k) = map $_->r2C, @_;
446             fftnd($im);
447             fftnd($k);
448             my $c = $im * $k;
449             ifftnd($c);
450             $_[0] = $c->re->sever;
451             $_[1] = $c->im->sever;
452             @_;
453             }
454              
455             #line 383 "lib/PDL/FFT.pd"
456              
457             =head1 BUGS
458              
459             Where the source is marked `FIX', could re-implement using phase-shift
460             factors on the transforms and some real-space bookkeeping, to save
461             some temporary space and redundant transforms.
462              
463             =head1 AUTHOR
464              
465             This file copyright (C) 1997, 1998 R.J.R. Williams
466             (rjrw@ast.leeds.ac.uk), Karl Glazebrook (kgb@aaoepp.aao.gov.au),
467             Tuomas J. Lukka, (lukka@husc.harvard.edu). All rights reserved. There
468             is no warranty. You are allowed to redistribute this software /
469             documentation under certain conditions. For details, see the file
470             COPYING in the PDL distribution. If this file is separated from the
471             PDL distribution, the copyright notice should be included in the file.
472              
473             =cut
474             #line 475 "lib/PDL/FFT.pm"
475              
476             # Exit with OK status
477              
478             1;