public RealFourierTransform(int length) { _numberOfData = length; if(length<1) throw new ArgumentException("length smaller than 1 is not appropriate here."); else if(length<3) { _method = Method.Trivial; } else if(Calc.BinaryMath.IsPowerOfTwo(length)) { // use Hartley transform _method = Method.Hartley; } else if(Pfa235FFT.CanFactorized(length)) { // use Pfa235 transform _method = Method.Pfa235; _pfa235 = new Pfa235FFT(_numberOfData); } else { // use chirp transform _method = Method.Chirp; } }
/// <summary> /// Copy-Constructor /// </summary> /// <remarks> /// Setup fast Fourier transform / back-transform for one, two or three /// dimensions. The dimensions n1,n2,and n3 must be of the form /// n = (2**p) * (3**q) * (5**r) /// otherwise an error will be generated and the error handler function /// Matpack.Error() is called. On instantiation some trigonometric tables /// will be allocated and calculated. This approach avoids multiple /// twiddle factor recalculations if several FFTs are calculated for data /// with the same dimensions. Sometimes it is convenient to define an /// "empty" setup (first constructor) and assign a setup later (see /// copying and assignment). As default the multi-dimensional data /// are expected in row order (C convention). If you want to transform /// data stored in column order (Fortran convention) use the member /// function SetOrder() to change the order - see below. For optimizations /// on vector machines with separate memory banks an extra leading dimension /// can be defined to avoid bank conflicts - also see SetOrder(). /// </remarks> public Pfa235FFT(Pfa235FFT fft) { // copy all elements id = fft.id; ndim = fft.ndim; trisize = fft.trisize; row_order = fft.row_order; for (int i = 0; i < 3; i++) { dim[i] = fft.dim[i]; trindex[i] = fft.trindex[i]; } // allocate and copy trigs trigs = new double[trisize]; Array.Copy(fft.trigs, 0, this.trigs, 0, fft.trigs.Length); }
protected static string TwoDimFFT(Altaxo.AltaxoDocument mainDocument, GUI.WorksheetController dg, out double[] rePart, out double[] imPart) { int rows = dg.Doc.DataColumns.RowCount; int cols = dg.Doc.DataColumns.ColumnCount; // reserve two arrays (one for real part, which is filled with the table contents) // and the imaginary part - which is left zero here) rePart = new double[rows*cols]; imPart = new double[rows*cols]; // fill the real part with the table contents for(int i=0;i<cols;i++) { Altaxo.Data.INumericColumn col = dg.Doc[i] as Altaxo.Data.INumericColumn; if(null==col) { return string.Format("Can't apply fourier transform, since column number {0}, name:{1} is not numeric",i,dg.Doc[i].FullName); } for(int j=0;j<rows;j++) { rePart[i*rows+j] = col[j]; } } // test it can be done if(!Pfa235FFT.CanFactorized(cols)) return string.Format("Can't apply fourier transform, since the number of cols ({0}) are not appropriate for this kind of fourier transform.",cols); if(!Pfa235FFT.CanFactorized(rows)) return string.Format("Can't apply fourier transform, since the number of rows ({0}) are not appropriate for this kind of fourier transform.",rows); // fourier transform Pfa235FFT fft = new Pfa235FFT(cols,rows); fft.FFT(rePart,imPart,FourierDirection.Forward); // replace the real part by the amplitude for(int i=0;i<rePart.Length;i++) { rePart[i] = Math.Sqrt(rePart[i]*rePart[i]+imPart[i]*imPart[i]); } return null; }
/// <summary> /// Executes the fourier transformation itself (without data pretreatment). /// </summary> /// <exception cref="System.InvalidOperationException">The Fourier transformation was already executed.</exception> protected virtual void ExecuteFourierTransformation() { if (_arraysContainTransformation) throw new InvalidOperationException("The Fourier transformation was already executed."); var numColumns = NumberOfColumns; var numRows = NumberOfRows; var rePart = ((IMatrixInArray1DRowMajorRepresentation<double>)_realMatrix).GetArray1DRowMajor(); _imagMatrix = new DoubleMatrixInArray1DRowMajorRepresentation(numRows, numColumns); var imPart = ((IMatrixInArray1DRowMajorRepresentation<double>)_imagMatrix).GetArray1DRowMajor(); // fourier transform either with Pfa (faster) or with the Chirp-z-transform if (Pfa235FFT.CanFactorized(numRows) && Pfa235FFT.CanFactorized(numColumns)) { Pfa235FFT fft = new Pfa235FFT(numRows, numColumns); fft.FFT(rePart, imPart, FourierDirection.Forward); } else { var matrixRe = new DoubleMatrixInArray1DRowMajorRepresentation(rePart, numRows, numColumns); ChirpFFT.FourierTransformation2D(matrixRe, _imagMatrix, FourierDirection.Forward); } _arraysContainTransformation = true; }
private void MyFFT(double[] real, double[] imag, FourierDirection direction) { Pfa235FFT fft = new Pfa235FFT(real.Length); fft.FFT(real, imag, direction); }
private void MyRoutine2(double[] real1, FourierDirection dir) { int n = real1.Length; System.Random rnd = new System.Random(); double[] real2 = new double[n]; for (int i = 0; i < n; i++) real2[i] = rnd.NextDouble() / n; Pfa235FFT fft = new Pfa235FFT(n); fft.RealFFT(real2, real1, dir); }
private static void zzTestImOne_ArbPosBothDim(int u, int v) { int upos = rnd.Next(u); int vpos = rnd.Next(v); int n = u * v; double[] re = new double[n]; double[] im = new double[n]; im[upos * v + vpos] = 1; Pfa235FFT fft = new Pfa235FFT(u, v); fft.FFT(re, im, FourierDirection.Inverse); for (int i = 0; i < u; i++) { for (int j = 0; j < v; j++) { Assert.AreEqual(Math.Sin(2 * Math.PI * (((double)i) * upos / u + ((double)j) * vpos / v)), re[i * v + j], n * 1E-15, string.Format("FFT({0},{1}) of re 1 at pos 1 re[{2},{3}]", u, v, i, j)); Assert.AreEqual(Math.Cos(2 * Math.PI * (((double)i) * upos / u + ((double)j) * vpos / v)), im[i * v + j], n * 1E-15, string.Format("FFT({0},{1}) of re 1 at pos 1 im[{2},{3}]", u, v, i, j)); } } }
private static void zzTestReOne_OnePos2ndDim(int u, int v) { int n = u * v; double[] re = new double[n]; double[] im = new double[n]; re[1 * v] = 1; Pfa235FFT fft = new Pfa235FFT(u, v); fft.FFT(re, im, FourierDirection.Inverse); for (int i = 0; i < u; i++) { for (int j = 0; j < v; j++) { Assert.AreEqual(Math.Cos((2 * Math.PI * i) / u), re[i * v + j], n * 1E-15, string.Format("FFT({0},{1}) of re 1 at pos 1 re[{2},{3}]", u, v, i, j)); Assert.AreEqual(-Math.Sin((2 * Math.PI * i) / u), im[i * v + j], n * 1E-15, string.Format("FFT({0},{1}) of re 1 at pos 1 im[{2},{3}]", u, v, i, j)); } } }
private static void zzTestZero(int u, int v) { int n = u * v; double[] re = new double[n]; double[] im = new double[n]; Pfa235FFT fft = new Pfa235FFT(u, v); fft.FFT(re, im, FourierDirection.Inverse); for (int i = 0; i < n; i++) { Assert.AreEqual(0, re[i], 0, "FFT of zero should give re=0"); Assert.AreEqual(0, im[i], 0, "FFT of zero should give im=0"); } }