GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
fft.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "lo-mappers.h"
31 
32 #include "defun.h"
33 #include "error.h"
34 #include "errwarn.h"
35 #include "ovl.h"
36 #include "utils.h"
37 
39 
40 static octave_value
41 do_fft (const octave_value_list& args, const char *fcn, int type)
42 {
43  int nargin = args.length ();
44 
45  if (nargin < 1 || nargin > 3)
46  print_usage ();
47 
48  octave_value retval;
49  octave_value arg = args(0);
50  octave_idx_type n_points = -1;
51  dim_vector dims = arg.dims ();
52  int ndims = dims.ndims ();
53  int dim = -1;
54 
55  if (nargin > 1)
56  {
57  if (! args(1).isempty ())
58  {
59  double dval = args(1).double_value ();
60  if (math::isnan (dval))
61  error ("%s: number of points (N) cannot be NaN", fcn);
62 
63  n_points = math::nint_big (dval);
64  if (n_points < 0)
65  error ("%s: number of points (N) must be greater than zero", fcn);
66  }
67  }
68 
69  if (nargin > 2)
70  {
71  double dval = args(2).double_value ();
72  if (math::isnan (dval))
73  error ("%s: DIM cannot be NaN", fcn);
74  else if (dval < 1 || dval > ndims)
75  error ("%s: DIM must be a valid dimension along which to perform FFT",
76  fcn);
77  else
78  // to be safe, cast it back to int since dim is an int
79  dim = math::nint (dval) - 1;
80  }
81 
82  // FIXME: This seems strange and unnecessary (10/21/16).
83  // How would you ever arrive at an octave_value object without correct dims?
84  // We certainly don't make this check every other place in Octave.
85  for (octave_idx_type i = 0; i < ndims; i++)
86  if (dims(i) < 0)
87  return retval;
88 
89  if (dim < 0)
90  {
91  dim = dims.first_non_singleton ();
92 
93  // And if the first argument is scalar?
94  if (dim == ndims)
95  dim = 1;
96  }
97 
98  if (n_points < 0)
99  n_points = dims(dim);
100  else
101  dims(dim) = n_points;
102 
103  if (n_points == 0 || dims.any_zero ())
104  {
105  if (arg.is_single_type ())
106  return octave_value (FloatNDArray (dims));
107  else
108  return octave_value (NDArray (dims));
109  }
110 
111  if (n_points == 1)
112  {
113  octave_value_list idx (ndims);
114  for (octave_idx_type i = 0; i < ndims; i++)
115  idx(i) = idx_vector::colon;
116  idx(dim) = idx_vector (0);
117 
118  return arg.index_op (idx);
119  }
120 
121  if (arg.is_single_type ())
122  {
123  if (arg.isreal ())
124  {
125  FloatNDArray nda = arg.float_array_value ();
126 
127  nda.resize (dims, 0.0);
128  retval = (type != 0 ? nda.ifourier (dim) : nda.fourier (dim));
129  }
130  else
131  {
133 
134  cnda.resize (dims, 0.0);
135  retval = (type != 0 ? cnda.ifourier (dim) : cnda.fourier (dim));
136  }
137  }
138  else
139  {
140  if (arg.isreal ())
141  {
142  NDArray nda = arg.array_value ();
143 
144  nda.resize (dims, 0.0);
145  retval = (type != 0 ? nda.ifourier (dim) : nda.fourier (dim));
146  }
147  else if (arg.iscomplex ())
148  {
149  ComplexNDArray cnda = arg.complex_array_value ();
150 
151  cnda.resize (dims, 0.0);
152  retval = (type != 0 ? cnda.ifourier (dim) : cnda.fourier (dim));
153  }
154  else
155  err_wrong_type_arg (fcn, arg);
156  }
157 
158  return retval;
159 }
160 
161 /*
162 %!testif HAVE_FFTW
163 %! assert (fft ([]), [])
164 %!testif HAVE_FFTW
165 %! assert (fft (zeros (10,0)), zeros (10,0))
166 %!testif HAVE_FFTW
167 %! assert (fft (zeros (0,10)), zeros (0,10))
168 %!testif HAVE_FFTW
169 %! assert (fft (0), 0)
170 %!testif HAVE_FFTW
171 %! assert (fft (1), 1)
172 %!testif HAVE_FFTW
173 %! assert (fft (ones (2,2)), [2,2; 0,0])
174 %!testif HAVE_FFTW
175 %! assert (fft (eye (2,2)), [1,1; 1,-1])
176 
177 %!testif HAVE_FFTW
178 %! assert (fft (single ([])), single ([]))
179 %!testif HAVE_FFTW
180 %! assert (fft (zeros (10,0,"single")), zeros (10,0,"single"))
181 %!testif HAVE_FFTW
182 %! assert (fft (zeros (0,10,"single")), zeros (0,10,"single"))
183 %!testif HAVE_FFTW
184 %! assert (fft (single (0)), single (0))
185 %!testif HAVE_FFTW
186 %! assert (fft (single (1)), single (1))
187 %!testif HAVE_FFTW
188 %! assert (fft (ones (2,2,"single")), single ([2,2; 0,0]))
189 %!testif HAVE_FFTW
190 %! assert (fft (eye (2,2,"single")), single ([1,1; 1,-1]))
191 
192 %!error fft ()
193 */
194 
195 
196 DEFUN (fft, args, ,
197  doc: /* -*- texinfo -*-
198 @deftypefn {} {@var{y} =} fft (@var{x})
199 @deftypefnx {} {@var{y} =} fft (@var{x}, @var{n})
200 @deftypefnx {} {@var{y} =} fft (@var{x}, @var{n}, @var{dim})
201 Compute the discrete Fourier transform of @var{x} using
202 a Fast Fourier Transform (FFT) algorithm.
203 
204 The FFT is calculated along the first non-singleton dimension of the
205 array. Thus if @var{x} is a matrix, @code{fft (@var{x})} computes the
206 FFT for each column of @var{x}.
207 
208 If called with two arguments, @var{n} is expected to be an integer
209 specifying the number of elements of @var{x} to use, or an empty
210 matrix to specify that its value should be ignored. If @var{n} is
211 larger than the dimension along which the FFT is calculated, then
212 @var{x} is resized and padded with zeros. Otherwise, if @var{n} is
213 smaller than the dimension along which the FFT is calculated, then
214 @var{x} is truncated.
215 
216 If called with three arguments, @var{dim} is an integer specifying the
217 dimension of the matrix along which the FFT is performed.
218 @seealso{ifft, fft2, fftn, fftw}
219 @end deftypefn */)
220 {
221  return do_fft (args, "fft", 0);
222 }
223 
224 
225 DEFUN (ifft, args, ,
226  doc: /* -*- texinfo -*-
227 @deftypefn {} {@var{x} =} ifft (@var{y})
228 @deftypefnx {} {@var{x} =} ifft (@var{y}, @var{n})
229 @deftypefnx {} {@var{x} =} ifft (@var{y}, @var{n}, @var{dim})
230 Compute the inverse discrete Fourier transform of @var{y}
231 using a Fast Fourier Transform (FFT) algorithm.
232 
233 The inverse FFT is calculated along the first non-singleton dimension
234 of the array. Thus if @var{y} is a matrix, @code{ifft (@var{y})} computes
235 the inverse FFT for each column of @var{y}.
236 
237 If called with two arguments, @var{n} is expected to be an integer
238 specifying the number of elements of @var{y} to use, or an empty
239 matrix to specify that its value should be ignored. If @var{n} is
240 larger than the dimension along which the inverse FFT is calculated, then
241 @var{y} is resized and padded with zeros. Otherwise, if @var{n} is
242 smaller than the dimension along which the inverse FFT is calculated,
243 then @var{y} is truncated.
244 
245 If called with three arguments, @var{dim} is an integer specifying the
246 dimension of the matrix along which the inverse FFT is performed.
247 @seealso{fft, ifft2, ifftn, fftw}
248 @end deftypefn */)
249 {
250  return do_fft (args, "ifft", 1);
251 }
252 
253 /*
254 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
255 ## Comalco Research and Technology
256 ## 02 May 2000
257 %!testif HAVE_FFTW
258 %! N = 64;
259 %! n = 4;
260 %! t = 2*pi*(0:1:N-1)/N;
261 %! s = cos (n*t);
262 %! S = fft (s);
263 %!
264 %! answer = zeros (size (t));
265 %! answer(n+1) = N/2;
266 %! answer(N-n+1) = N/2;
267 %!
268 %! assert (S, answer, 4*N*eps);
269 
270 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
271 ## Comalco Research and Technology
272 ## 02 May 2000
273 %!testif HAVE_FFTW
274 %! N = 64;
275 %! n = 7;
276 %! t = 2*pi*(0:1:N-1)/N;
277 %! s = cos (n*t);
278 %!
279 %! S = zeros (size (t));
280 %! S(n+1) = N/2;
281 %! S(N-n+1) = N/2;
282 %!
283 %! assert (ifft (S), s, 4*N*eps);
284 
285 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
286 ## Comalco Research and Technology
287 ## 02 May 2000
288 %!testif HAVE_FFTW
289 %! N = 64;
290 %! n = 4;
291 %! t = single (2*pi*(0:1:N-1)/N);
292 %! s = cos (n*t);
293 %! S = fft (s);
294 %!
295 %! answer = zeros (size (t), "single");
296 %! answer(n+1) = N/2;
297 %! answer(N-n+1) = N/2;
298 %!
299 %! assert (S, answer, 4*N* eps ("single"));
300 
301 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
302 ## Comalco Research and Technology
303 ## 02 May 2000
304 %!testif HAVE_FFTW
305 %! N = 64;
306 %! n = 7;
307 %! t = 2*pi*(0:1:N-1)/N;
308 %! s = cos (n*t);
309 %!
310 %! S = zeros (size (t), "single");
311 %! S(n+1) = N/2;
312 %! S(N-n+1) = N/2;
313 %!
314 %! assert (ifft (S), s, 4*N* eps ("single"));
315 
316 %!testif HAVE_FFTW <*64729>
317 %! x = rand (5, 5, 5, 5);
318 %! old_planner = fftw ('planner', 'measure');
319 %! unwind_protect
320 %! y = fft (x);
321 %! y = fft (x); # second invocation might crash Octave
322 %! assert (size (y), [5, 5, 5, 5]);
323 %! unwind_protect_cleanup
324 %! fftw ('planner', old_planner);
325 %! end_unwind_protect
326 
327 %!testif HAVE_FFTW <*64729>
328 %! x = rand (5, 5, 5, 5, 'single');
329 %! old_planner = fftw ('planner', 'measure');
330 %! unwind_protect
331 %! y = fft (x);
332 %! y = fft (x); # second invocation might crash Octave
333 %! assert (size (y), [5, 5, 5, 5]);
334 %! unwind_protect_cleanup
335 %! fftw ('planner', old_planner);
336 %! end_unwind_protect
337 
338 %!testif HAVE_FFTW <*64733>
339 %! old_planner = fftw ('planner', 'measure');
340 %! unwind_protect
341 %! assert (ifft ([2, 4, 6, 8]), [5, -1-1i, -1, -1+1i]);
342 %! unwind_protect_cleanup
343 %! fftw ('planner', old_planner);
344 %! end_unwind_protect
345 
346 %!testif HAVE_FFTW <*64733>
347 %! old_planner = fftw ('planner', 'measure');
348 %! unwind_protect
349 %! assert (ifft (single ([2, 4, 6, 8])), single ([5, -1-1i, -1, -1+1i]));
350 %! unwind_protect_cleanup
351 %! fftw ('planner', old_planner);
352 %! end_unwind_protect
353 */
354 
355 OCTAVE_END_NAMESPACE(octave)
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1023
ComplexNDArray fourier(int dim=1) const
Definition: CNDArray.cc:58
ComplexNDArray ifourier(int dim=1) const
Definition: CNDArray.cc:89
FloatComplexNDArray ifourier(int dim=1) const
Definition: fCNDArray.cc:89
FloatComplexNDArray fourier(int dim=1) const
Definition: fCNDArray.cc:58
FloatComplexNDArray ifourier(int dim=1) const
Definition: fNDArray.cc:89
FloatComplexNDArray fourier(int dim=1) const
Definition: fNDArray.cc:58
ComplexNDArray ifourier(int dim=1) const
Definition: dNDArray.cc:131
ComplexNDArray fourier(int dim=1) const
Definition: dNDArray.cc:100
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
bool any_zero() const
Definition: dim-vector.h:316
int first_non_singleton(int def=0) const
Definition: dim-vector.h:444
static const idx_vector colon
Definition: idx-vector.h:466
octave_idx_type length() const
Definition: ovl.h:113
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:504
bool isreal() const
Definition: ov.h:738
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:878
bool is_single_type() const
Definition: ov.h:698
bool iscomplex() const
Definition: ov.h:741
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:859
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:882
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:862
dim_vector dims() const
Definition: ov.h:541
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void() error(const char *fmt,...)
Definition: error.cc:988
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
octave_idx_type nint_big(double x)
Definition: lo-mappers.cc:188
int nint(double x)
Definition: lo-mappers.cc:216
bool isnan(bool)
Definition: lo-mappers.h:178
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))