GNU Octave  6.2.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-2021 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 
38 static octave_value
39 do_fft (const octave_value_list& args, const char *fcn, int type)
40 {
41  int nargin = args.length ();
42 
43  if (nargin < 1 || nargin > 3)
44  print_usage ();
45 
47  octave_value arg = args(0);
48  octave_idx_type n_points = -1;
49  dim_vector dims = arg.dims ();
50  int ndims = dims.ndims ();
51  int dim = -1;
52 
53  if (nargin > 1)
54  {
55  if (! args(1).isempty ())
56  {
57  double dval = args(1).double_value ();
58  if (octave::math::isnan (dval))
59  error ("%s: number of points (N) cannot be NaN", fcn);
60 
61  n_points = octave::math::nint_big (dval);
62  if (n_points < 0)
63  error ("%s: number of points (N) must be greater than zero", fcn);
64  }
65  }
66 
67  if (nargin > 2)
68  {
69  double dval = args(2).double_value ();
70  if (octave::math::isnan (dval))
71  error ("%s: DIM cannot be NaN", fcn);
72  else if (dval < 1 || dval > ndims)
73  error ("%s: DIM must be a valid dimension along which to perform FFT",
74  fcn);
75  else
76  // to be safe, cast it back to int since dim is an int
77  dim = octave::math::nint (dval) - 1;
78  }
79 
80  // FIXME: This seems strange and unnecessary (10/21/16).
81  // How would you ever arrive at an octave_value object without correct dims?
82  // We certainly don't make this check every other place in Octave.
83  for (octave_idx_type i = 0; i < ndims; i++)
84  if (dims(i) < 0)
85  return retval;
86 
87  if (dim < 0)
88  {
89  dim = dims.first_non_singleton ();
90 
91  // And if the first argument is scalar?
92  if (dim == ndims)
93  dim = 1;
94  }
95 
96  if (n_points < 0)
97  n_points = dims(dim);
98  else
99  dims(dim) = n_points;
100 
101  if (n_points == 0 || dims.any_zero ())
102  {
103  if (arg.is_single_type ())
104  return octave_value (FloatNDArray (dims));
105  else
106  return octave_value (NDArray (dims));
107  }
108 
109  if (n_points == 1)
110  {
111  octave_value_list idx (ndims);
112  for (octave_idx_type i = 0; i < ndims; i++)
113  idx(i) = idx_vector::colon;
114  idx(dim) = idx_vector (static_cast<octave_idx_type> (0));
115 
116  return arg.do_index_op (idx);
117  }
118 
119  if (arg.is_single_type ())
120  {
121  if (arg.isreal ())
122  {
123  FloatNDArray nda = arg.float_array_value ();
124 
125  nda.resize (dims, 0.0);
126  retval = (type != 0 ? nda.ifourier (dim) : nda.fourier (dim));
127  }
128  else
129  {
131 
132  cnda.resize (dims, 0.0);
133  retval = (type != 0 ? cnda.ifourier (dim) : cnda.fourier (dim));
134  }
135  }
136  else
137  {
138  if (arg.isreal ())
139  {
140  NDArray nda = arg.array_value ();
141 
142  nda.resize (dims, 0.0);
143  retval = (type != 0 ? nda.ifourier (dim) : nda.fourier (dim));
144  }
145  else if (arg.iscomplex ())
146  {
147  ComplexNDArray cnda = arg.complex_array_value ();
148 
149  cnda.resize (dims, 0.0);
150  retval = (type != 0 ? cnda.ifourier (dim) : cnda.fourier (dim));
151  }
152  else
153  err_wrong_type_arg (fcn, arg);
154  }
155 
156  return retval;
157 }
158 
159 /*
160 %!testif HAVE_FFTW
161 %! assert (fft ([]), [])
162 %!testif HAVE_FFTW
163 %! assert (fft (zeros (10,0)), zeros (10,0))
164 %!testif HAVE_FFTW
165 %! assert (fft (zeros (0,10)), zeros (0,10))
166 %!testif HAVE_FFTW
167 %! assert (fft (0), 0)
168 %!testif HAVE_FFTW
169 %! assert (fft (1), 1)
170 %!testif HAVE_FFTW
171 %! assert (fft (ones (2,2)), [2,2; 0,0])
172 %!testif HAVE_FFTW
173 %! assert (fft (eye (2,2)), [1,1; 1,-1])
174 
175 %!testif HAVE_FFTW
176 %! assert (fft (single ([])), single ([]))
177 %!testif HAVE_FFTW
178 %! assert (fft (zeros (10,0,"single")), zeros (10,0,"single"))
179 %!testif HAVE_FFTW
180 %! assert (fft (zeros (0,10,"single")), zeros (0,10,"single"))
181 %!testif HAVE_FFTW
182 %! assert (fft (single (0)), single (0))
183 %!testif HAVE_FFTW
184 %! assert (fft (single (1)), single (1))
185 %!testif HAVE_FFTW
186 %! assert (fft (ones (2,2,"single")), single ([2,2; 0,0]))
187 %!testif HAVE_FFTW
188 %! assert (fft (eye (2,2,"single")), single ([1,1; 1,-1]))
189 
190 %!error (fft ())
191 */
192 
193 
194 DEFUN (fft, args, ,
195  doc: /* -*- texinfo -*-
196 @deftypefn {} {} fft (@var{x})
197 @deftypefnx {} {} fft (@var{x}, @var{n})
198 @deftypefnx {} {} fft (@var{x}, @var{n}, @var{dim})
199 Compute the discrete Fourier transform of @var{x} using
200 a Fast Fourier Transform (FFT) algorithm.
201 
202 The FFT is calculated along the first non-singleton dimension of the
203 array. Thus if @var{x} is a matrix, @code{fft (@var{x})} computes the
204 FFT for each column of @var{x}.
205 
206 If called with two arguments, @var{n} is expected to be an integer
207 specifying the number of elements of @var{x} to use, or an empty
208 matrix to specify that its value should be ignored. If @var{n} is
209 larger than the dimension along which the FFT is calculated, then
210 @var{x} is resized and padded with zeros. Otherwise, if @var{n} is
211 smaller than the dimension along which the FFT is calculated, then
212 @var{x} is truncated.
213 
214 If called with three arguments, @var{dim} is an integer specifying the
215 dimension of the matrix along which the FFT is performed.
216 @seealso{ifft, fft2, fftn, fftw}
217 @end deftypefn */)
218 {
219  return do_fft (args, "fft", 0);
220 }
221 
222 
223 DEFUN (ifft, args, ,
224  doc: /* -*- texinfo -*-
225 @deftypefn {} {} ifft (@var{x})
226 @deftypefnx {} {} ifft (@var{x}, @var{n})
227 @deftypefnx {} {} ifft (@var{x}, @var{n}, @var{dim})
228 Compute the inverse discrete Fourier transform of @var{x}
229 using a Fast Fourier Transform (FFT) algorithm.
230 
231 The inverse FFT is calculated along the first non-singleton dimension
232 of the array. Thus if @var{x} is a matrix, @code{fft (@var{x})} computes
233 the inverse FFT for each column of @var{x}.
234 
235 If called with two arguments, @var{n} is expected to be an integer
236 specifying the number of elements of @var{x} to use, or an empty
237 matrix to specify that its value should be ignored. If @var{n} is
238 larger than the dimension along which the inverse FFT is calculated, then
239 @var{x} is resized and padded with zeros. Otherwise, if @var{n} is
240 smaller than the dimension along which the inverse FFT is calculated,
241 then @var{x} is truncated.
242 
243 If called with three arguments, @var{dim} is an integer specifying the
244 dimension of the matrix along which the inverse FFT is performed.
245 @seealso{fft, ifft2, ifftn, fftw}
246 @end deftypefn */)
247 {
248  return do_fft (args, "ifft", 1);
249 }
250 
251 /*
252 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
253 ## Comalco Research and Technology
254 ## 02 May 2000
255 %!testif HAVE_FFTW
256 %! N = 64;
257 %! n = 4;
258 %! t = 2*pi*(0:1:N-1)/N;
259 %! s = cos (n*t);
260 %! S = fft (s);
261 %!
262 %! answer = zeros (size (t));
263 %! answer(n+1) = N/2;
264 %! answer(N-n+1) = N/2;
265 %!
266 %! assert (S, answer, 4*N*eps);
267 
268 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
269 ## Comalco Research and Technology
270 ## 02 May 2000
271 %!testif HAVE_FFTW
272 %! N = 64;
273 %! n = 7;
274 %! t = 2*pi*(0:1:N-1)/N;
275 %! s = cos (n*t);
276 %!
277 %! S = zeros (size (t));
278 %! S(n+1) = N/2;
279 %! S(N-n+1) = N/2;
280 %!
281 %! assert (ifft (S), s, 4*N*eps);
282 
283 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
284 ## Comalco Research and Technology
285 ## 02 May 2000
286 %!testif HAVE_FFTW
287 %! N = 64;
288 %! n = 4;
289 %! t = single (2*pi*(0:1:N-1)/N);
290 %! s = cos (n*t);
291 %! S = fft (s);
292 %!
293 %! answer = zeros (size (t), "single");
294 %! answer(n+1) = N/2;
295 %! answer(N-n+1) = N/2;
296 %!
297 %! assert (S, answer, 4*N*eps ("single"));
298 
299 ## Author: David Billinghurst (David.Billinghurst@riotinto.com.au)
300 ## Comalco Research and Technology
301 ## 02 May 2000
302 %!testif HAVE_FFTW
303 %! N = 64;
304 %! n = 7;
305 %! t = 2*pi*(0:1:N-1)/N;
306 %! s = cos (n*t);
307 %!
308 %! S = zeros (size (t), "single");
309 %! S(n+1) = N/2;
310 %! S(N-n+1) = N/2;
311 %!
312 %! assert (ifft (S), s, 4*N*eps ("single"));
313 */
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
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:95
int first_non_singleton(int def=0) const
Definition: dim-vector.h:510
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:334
bool any_zero(void) const
Definition: dim-vector.h:382
static const idx_vector colon
Definition: idx-vector.h:499
octave_idx_type length(void) const
Definition: ovl.h:113
bool isreal(void) const
Definition: ov.h:691
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:475
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:831
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:812
bool is_single_type(void) const
Definition: ov.h:651
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:835
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:815
bool iscomplex(void) const
Definition: ov.h:694
dim_vector dims(void) const
Definition: ov.h:500
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#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:968
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
static octave_value do_fft(const octave_value_list &args, const char *fcn, int type)
Definition: fft.cc:39
int nint(double x)
Definition: lo-mappers.cc:208
bool isnan(bool)
Definition: lo-mappers.h:178
octave_idx_type nint_big(double x)
Definition: lo-mappers.cc:184
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811