/* Copyright (C) 2003 Motorola Inc Copyright (C) 2003 Laurent Mazet Copyright (C) 2003 David Bateman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. In addition to the terms of the GPL, you are permitted to link this program with any Open Source program, as defined by the Open Source Initiative (www.opensource.org) */ #include #include #include #include "ffft.h" /* *---------------------------------------------------------------------------* | Module: FFT Radix4 | | | | Description: contains five radix4 - butterfly functions, and a function | | performing the radix4 FFT. | | All the butterflies have the following structure: | | | | u ____ ____ u <-- [(u+y)+(x+z)]W0 | | \ / | | \ / | | x _______\ /_______ x <-- [(u-y)-j(x-z)]Wk | | \/ | | /\ | | y ______ / \ ______ y <-- [(u+y)-(x+z)]W2k | | / \ | | / \ | | z ___ / \ ___ z <-- [(u-y)+j(x-z)]W3k | | | *---------------------------------------------------------------------------* */ template inline void Fft::corebutterfly (C &u, C &x, C &y, C &z) { apc = reshape(u) + reshape(y); amc = reshape(u) - reshape(y); bpd = reshape(x) + reshape(z); bmd = reshape(x) - reshape(z); } template void Fft::r4butterfly0 (C &u, C &x, C &y, C &z) { // W0, W0, W0, W0 corebutterfly(u, x, y, z); // first branch u = reshape(apc) + reshape(bpd); // third branch y = reshape(apc) - reshape(bpd); // second branch x = C (reshape(real(amc)) + reshape(imag(bmd)), reshape(imag(amc)) - reshape(real(bmd))); // last branch z = C (reshape(real(amc)) - reshape(imag(bmd)), reshape(imag(amc)) + reshape(real(bmd))); } template void Fft::r4butterfly1 (C &u, C &x, C &y, C &z, int n) { // W0, W1/16, W1/8, W3/16 corebutterfly(u, x, y, z); // first branch u = reshape(apc) + reshape(bpd); // third branch C t(reshape(apc) - reshape(bpd)); y = C (real(t)*inv_sqrt_2 + imag(t)*inv_sqrt_2, imag(t)*inv_sqrt_2 - real(t)*inv_sqrt_2); // Respect ASIC // second branch x = C (reshape(real(amc)) + reshape(imag(bmd)), reshape(imag(amc)) - reshape(real(bmd)))*twiddle(n); // last branch z = C (reshape(real(amc)) - reshape(imag(bmd)), reshape(imag(amc)) + reshape(real(bmd)))*twiddle(3*n); } template void Fft::r4butterfly2 (C &u, C &x, C &y, C &z) { //* W0, W1/8, W1/4, W3/8 corebutterfly(u, x, y, z); // first branch u = reshape(apc) + reshape(bpd); // third branch y = C (reshape(imag(apc)) - reshape(imag(bpd)), reshape(real(bpd)) - reshape(real(apc))); // second branch C t(reshape(real(amc)) + reshape(imag(bmd)), reshape(imag(amc)) - reshape(real(bmd))); x = C (real(t)*inv_sqrt_2 + imag(t)*inv_sqrt_2, imag(t)*inv_sqrt_2 - real(t)*inv_sqrt_2); // Respect ASIC // last branch t = C (reshape(real(amc)) - reshape(imag(bmd)), reshape(imag(amc)) + reshape(real(bmd))); z = C (real(t)*(-inv_sqrt_2) - imag(t)*(-inv_sqrt_2), real(t)*(-inv_sqrt_2) + imag(t)*(-inv_sqrt_2)); // Respect ASIC } template void Fft::r4butterfly3 (C &u, C &x, C &y, C &z, int n) { // W0, W3/16, W3/8, W9/16 corebutterfly(u, x, y, z); // first branch u = reshape(apc) + reshape(bpd); // third branch C t(reshape(apc) - reshape(bpd)); y = C (real(t)*(-inv_sqrt_2) - imag(t)*(-inv_sqrt_2), real(t)*(-inv_sqrt_2) + imag(t)*(-inv_sqrt_2)); // Respect ASIC // second branch x = C (reshape(real(amc)) + reshape(imag(bmd)), reshape(imag(amc)) - reshape(real(bmd)))*twiddle(3*n); // last branch z = C (reshape(real(amc)) - reshape(imag(bmd)), reshape(imag(amc)) + reshape(real(bmd)))*twiddle(9*n); } template void Fft::r4butterfly4 (C &u, C &x, C &y, C &z, int n) { // others corebutterfly(u, x, y, z); // first branch u = reshape(apc) + reshape(bpd); // third branch y = (reshape(apc) - reshape(bpd))*twiddle(2*n); // second branch x = C (reshape(real(amc)) + reshape(imag(bmd)), reshape(imag(amc)) - reshape(real(bmd)))*twiddle(n); // last branch z = C (reshape(real(amc)) - reshape(imag(bmd)), reshape(imag(amc)) + reshape(real(bmd)))*twiddle(3*n); } /* *---------------------------------------------------------------------------* | Function: Radix4FFT | | | | Description: performs a Radix4 FFT for size 256 or 1024 | | | | Inputs: fft_public FFT_PARAM_PUBLIC | | Input/Output: realpart CARRIERTYPE* real part of the input data/FFT | | imagpart CARRIERTYPE* imag part of the input data/FFT | *---------------------------------------------------------------------------* */ template void Fft::radix4fft (CV &x) { // code for radix4FFT function int p1, p2, p3, p4, pfirst; int size_16 = size/16; for (int nb=0, nb_nb = x.length()/size; nb>=2, n_block<<=2) for (int block =0; block CV Fft::sortingfft (CV &x) { CV y(x); // outputs sorting for (int n=0, l=y.length()/size; n void Fft::generatetwiddle (const unsigned int &is, const unsigned int &ds) { const double Pi2 = 2 * 3.14159265358979; // 2*pi twiddle.resize (size); for (int i=0; i void Fft::generatetwiddle (const unsigned int &is, const unsigned int &ds) { const double Pi2 = 2 * 3.14159265358979; // 2*pi ComplexRowVector twiddle_double (size); for (int i=0; i void Fft::generatesort () { // Resize and fill sort with zeros.. sort.resize (0); #if HAVE_RESIZE_AND_FILL sort.resize_and_fill (size, 0); #else sort.resize (size, 0); #endif for (int i=0; i>=2) sort(i) += j*((i/k)%4); } template<> inline void Fft::normalize (FixedComplexRowVector &x) { /* We reshape data before each butterfly, so we have to multiply by sqrt(size). */ for (int i=0, l=x.length(); i inline void Fft::normalize (ComplexRowVector &x) { for (int i=0, l=x.length(); i inline FixedPoint Fft:: reshape (FixedPoint t) { return (t>>1); } template <> inline FixedPointComplex Fft::reshape (FixedPointComplex t) { return (FixedPointComplex (real(t)>>1, imag(t)>>1)); } template <> inline Complex Fft::reshape (Complex t) { return (t); } template <> inline double Fft::reshape (double t) { return (t); } template <> void Fft:: computetemplatevalues (const unsigned int &FftInputI, const unsigned int &FftInputD) { j_complex = Complex(0, 1.); output_gain_fp = 0; long int i = size; while (i >>=1) output_gain_fp++; output_gain_fp = output_gain_fp / 2; inv_sqrt_2 = FixedPoint(FftInputI, FftInputD, 1 / sqrt(2.0)); } template <> void Fft::computetemplatevalues ( const unsigned int &FftInputI, const unsigned int &FftInputD) { j_complex = Complex(0, 1.); output_gain = sqrt(double(size)); inv_sqrt_2 = 1 / sqrt(2.0); } template <> Fft::Fft (const int &n, const unsigned int &is, const unsigned int &ds) { size = n; int quot = n / 4; int rem = n % 4; while ((rem == 0) && (quot != 1)) { rem = quot % 4; quot = quot / 4; } if (rem) { error("fft: invalid radix 4 fft\n"); return; } computetemplatevalues(is, ds); generatetwiddle(is, ds); generatesort(); } template <> Fft::Fft (const int &n, const unsigned int &is, const unsigned int &ds) { size = n; int quot = n / 4; int rem = n % 4; while ((rem == 0) && (quot != 1)) { rem = quot % 4; quot = quot / 4; } if (rem) { error("fft: invalid radix 4 fft\n"); return; } computetemplatevalues(); generatetwiddle(); generatesort(); } template CV Fft::process (CV &x) { CV y(x); if (y.length()%size != 0) { error("fft: incorrect length of fft\n"); return y; } radix4fft(y); return (sortingfft(y)); } template CV Ifft::process (CV &x) { CV y(x); for (int i=0, l=y.length(); i::process (y); for (int i=0, l=y.length(); i; template class Fft; template class Ifft; template class Ifft; DEFUN_DLD (ffft, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{y} =} ffft (@var{x})\n\ Radix-4 fft in floating and fixed point for vectors of length 4^@var{n},\n\ where @var{n} is an integer. The variable @var{x} can be a either a row of\n\ column vector, in which case a single fft is carried out over the vector\n\ of length 4^@var{n}. If @var{x} is a matrix, the fft is carried on each\n\ column of @var{x} and the matrix must contain 4^@var{n} rows.\n\ \n\ The radix-4 fft is implemented in a manner that attempts to approximate\n\ how it will be implemented in hardware, rather than use a generic butterfly.\n\ The radix-4 algorithm is faster and more precise than the equivalent radix-2\n\ algorithm, and thus is preferred for hardware implementation.\n\ @seealso{fifft}\n\ @end deftypefn") { octave_value retval; if (args.length() != 1) print_usage("ffft"); else { if ((args(0).type_id () == octave_fixed_matrix::static_type_id ()) || (args(0).type_id () == octave_fixed_complex_matrix::static_type_id ())) { FixedComplexMatrix f; if (args(0).type_id () == octave_fixed_matrix::static_type_id ()) f = ((const octave_fixed_matrix&) args(0).get_rep()). fixed_complex_matrix_value(); else if (args(0).type_id () == octave_fixed_complex_matrix::static_type_id ()) f = ((const octave_fixed_complex_matrix&) args(0).get_rep()).fixed_complex_matrix_value(); if (!error_state) { bool rowvect = false; int is = (int)std::max(real(f.getintsize()).row_max().max(), imag(f.getintsize()).row_max().max()); int ds = (int)std::max(real(f.getdecsize()).row_max().max(), imag(f.getdecsize()).row_max().max()); if (f.rows() == 1) { f = f.transpose(); rowvect = true; } Fft fft_radix4(f.rows(), is, ds); if (!error_state) { for (int i=0; i < f.cols(); i++) { FixedComplexRowVector x(f.rows()); for (int j=0; j < f.rows(); j++) x(j) = f(j,i); x = fft_radix4.process(x); for (int j=0; j < f.rows(); j++) f(j,i) = x(j); } if (rowvect) f = f.transpose(); retval = new octave_fixed_complex_matrix (f); retval.maybe_mutate(); } } } else { ComplexMatrix f; if (args(0).is_matrix_type()) f = args(0).complex_matrix_value(); else error("ffft: must be called with a floating or fixed point vector\n"); if (!error_state) { bool rowvect = false; if (f.rows() == 1) { f = f.transpose(); rowvect = true; } Fft fft_radix4(f.rows()); if (!error_state) { for (int i=0; i < f.cols(); i++) { ComplexRowVector x(f.rows()); for (int j=0; j < f.rows(); j++) x(j) = f(j,i); x = fft_radix4.process(x); for (int j=0; j < f.rows(); j++) f(j,i) = x(j); } if (rowvect) f = f.transpose(); retval = octave_value(f); } } } } return retval; } DEFUN_DLD (fifft, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{y} =} fifft (@var{x})\n\ Radix-4 ifft in fixed point for vectors of length 4^@var{n}, where.\n\ @var{n} is an integer. The variable @var{x} can be a either a row of\n\ column vector, in which case a single ifft is carried out over the vector\n\ of length 4^@var{n}. If @var{x} is a matrix, the ifft is carried on each\n\ column of @var{x} and the matrix must contain 4^@var{n} rows.\n\ \n\ The radix-4 ifft is implemented in a manner that attempts to approximate\n\ how it will be implemented in hardware, rather than use a generic butterfly.\n\ The radix-4 algorithm is faster and more precise than the equivalent radix-2\n\ algorithm, and thus is preferred for hardware implementation.\n\ @seealso{ffft}\n\ @end deftypefn") { octave_value retval; if (args.length() != 1) print_usage("fifft"); else { if ((args(0).type_id () == octave_fixed_matrix::static_type_id ()) || (args(0).type_id () == octave_fixed_complex_matrix::static_type_id ())) { FixedComplexMatrix f; if (args(0).type_id () == octave_fixed_matrix::static_type_id ()) f = ((const octave_fixed_matrix&) args(0).get_rep()). fixed_complex_matrix_value(); else if (args(0).type_id () == octave_fixed_complex_matrix::static_type_id ()) f = ((const octave_fixed_complex_matrix&) args(0).get_rep()).fixed_complex_matrix_value(); if (!error_state) { bool rowvect = false; int is = (int)std::max(real(f.getintsize()).row_max().max(), imag(f.getintsize()).row_max().max()); int ds = (int)std::max(real(f.getdecsize()).row_max().max(), imag(f.getdecsize()).row_max().max()); if (f.rows() == 1) { f = f.transpose(); rowvect = true; } Ifft ifft_radix4(f.rows(), is, ds); if (!error_state) { for (int i=0; i < f.cols(); i++) { FixedComplexRowVector x(f.rows()); for (int j=0; j < f.rows(); j++) x(j) = f(j,i); x = ifft_radix4.process(x); for (int j=0; j < f.rows(); j++) f(j,i) = x(j); } if (rowvect) f = f.transpose(); retval = new octave_fixed_complex_matrix (f); retval.maybe_mutate(); } } } else { ComplexMatrix f; if (args(0).is_matrix_type()) f = args(0).complex_matrix_value(); else error("fifft: must be called with a floating or fixed point vector\n"); if (!error_state) { bool rowvect = false; if (f.rows() == 1) { f = f.transpose(); rowvect = true; } Ifft ifft_radix4(f.rows()); if (!error_state) { for (int i=0; i < f.cols(); i++) { ComplexRowVector x(f.rows()); for (int j=0; j < f.rows(); j++) x(j) = f(j,i); x = ifft_radix4.process(x); for (int j=0; j < f.rows(); j++) f(j,i) = x(j); } if (rowvect) f = f.transpose(); retval = octave_value(f); } } } } return retval; } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */