GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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()) ? '\'' :'"'))