fastfouriertransform.java

来自「一个很好的LIBSVM的JAVA源码。对于要研究和改进SVM算法的学者。可以参考」· Java 代码 · 共 185 行

JAVA
185
字号
/*
 *  YALE - Yet Another Learning Environment
 *  Copyright (C) 2001-2004
 *      Simon Fischer, Ralf Klinkenberg, Ingo Mierswa, 
 *          Katharina Morik, Oliver Ritthoff
 *      Artificial Intelligence Unit
 *      Computer Science Department
 *      University of Dortmund
 *      44221 Dortmund,  Germany
 *  email: yale-team@lists.sourceforge.net
 *  web:   http://yale.cs.uni-dortmund.de/
 *
 *  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 of the
 *  License, 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; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 *  USA.
 */
package edu.udo.cs.yale.tools.math;

import edu.udo.cs.yale.example.Example;
import edu.udo.cs.yale.example.ExampleSet;
import edu.udo.cs.yale.example.ExampleReader;
import edu.udo.cs.yale.example.Attribute;
import edu.udo.cs.yale.operator.OperatorException;

import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Iterator;
import java.util.List;
import java.util.Collections;

/** <p>
 *  Performs a FastFourierTransform on an array of complex values. The runtime is {@yale.math O(n log n)}.
 *  </p>
 *  <p>
 *  The used direction simply defines used norm factors, it can be omitted but the resulting values may be 
 *  quantitative wrong. 
 *  </p>
 *
 *  @version $Id: FastFourierTransform.java,v 1.2 2004/08/27 11:57:46 ingomierswa Exp $
 */
public class FastFourierTransform {

    /** Specifies the transformation from time into frequency domain. */
    public static final int TIME2FREQUENCY = 0;
    /** Specifies the transformation from frequency into time domain. */
    public static final int FREQUENCY2TIME = 1;

    /** The window function which should be applied before calculating the FT. */
    private int windowFunctionType = WindowFunction.HANNING;

    public FastFourierTransform(int windowFunctionType) {
	this.windowFunctionType = windowFunctionType;
    }

    /** Builds the fourier transform from the values of the first attribute onto the second. */
    public Complex[] getFourierTransform(ExampleSet exampleSet, Attribute source, Attribute target) 
	throws OperatorException {
	SortedMap pairs = new TreeMap();
	ExampleReader reader = exampleSet.getExampleReader();
	while (reader.hasNext()) {
	    Example example = reader.next();
	    pairs.put(new Double(example.getValue(target)), new Double(example.getValue(source)));
	}
	Complex[] complex = new Complex[pairs.size()];
	Iterator p = pairs.values().iterator();
	int k = 0;
	while (p.hasNext()) {
	    complex[k++] = new Complex(((Double)p.next()).doubleValue(), 0.0d);
	}
	Complex[] result = null;
	try {
	    result = getFourierTransform(complex, TIME2FREQUENCY, windowFunctionType);
	} catch (Exception e) {
	    throw new OperatorException("Exception occured during FFT!", e);
	}
	return result;
    }

    /** Normalizes the frequency to the correct value. */
    public static double convertFrequency(double frequency, int nyquist, int totalLength) {
	return (double)frequency / (2.0d * Math.PI) * ((double)totalLength / (double)nyquist);
    }

    /** Performs a fourier transformation in the specified direction. The window function type defines 
     *  one of the possible window functions. */
    public Complex[] getFourierTransform(Complex[] series, int direction, int functionType) throws Exception {
	int n = getGreatestPowerOf2LessThan(series.length);
	WindowFunction filter = new WindowFunction(functionType, n);
	if (n < 2) {
	    throw new Exception("Cannot transform series: not enough attributes!");
	}
        int nu = (int)(Math.log(n)/Math.log(2));
        int n2 = n/2;
        int nu1 = nu - 1;
        double[] xre = new double[n];
        double[] xim = new double[n];
        double tr, ti, p, arg, c, s;
        for (int i = 0; i < n; i++) {
            xre[i] = filter.getFactor(i) * series[i].getReal();
            xim[i] = filter.getFactor(i) * series[i].getImaginary();
        }
        int k = 0;

        for (int l = 1; l <= nu; l++) {
            while (k < n) {
                for (int i = 1; i <= n2; i++) {
                    p = bitrev (k >> nu1, nu);
                    arg = 2 * (double) Math.PI * p / n;
                    c = (double) Math.cos (arg);
                    s = (double) Math.sin (arg);
                    tr = xre[k+n2]*c + xim[k+n2]*s;
                    ti = xim[k+n2]*c - xre[k+n2]*s;
                    xre[k+n2] = xre[k] - tr;
                    xim[k+n2] = xim[k] - ti;
                    xre[k] += tr;
                    xim[k] += ti;
                    k++;
                }
                k += n2;
            }
            k = 0;
            nu1--;
            n2 = n2/2;
        }
        k = 0;
        int r;
        while (k < n) {
            r = bitrev (k, nu);
            if (r > k) {
                tr = xre[k];
                ti = xim[k];
                xre[k] = xre[r];
                xim[k] = xim[r];
                xre[r] = tr;
                xim[r] = ti;
            }
            k++;
        }

	int nyquist = n / 2;
	Complex[] result = new Complex[nyquist];
	switch (direction) {
	    case TIME2FREQUENCY:
		for (int i = 0; i < nyquist; i++)
		    result[i] = new Complex(- xre[i], xim[i]);
		break;
	    case FREQUENCY2TIME:
		for (int i = 0; i < nyquist; i++)
		    result[i] = new Complex(- xre[i], xim[i]);
		break;
	}
	return result;
    }

    /** Calculates the greatest power of 2 which is smaller than the given number. */
    public static int getGreatestPowerOf2LessThan(int n) {
	int power = (int)(Math.log(n)/Math.log(2));
	return (int)Math.pow(2, power);
    }

    /** Calculates ... */
    private int bitrev(int j, double nu) {
        int j2;
        int j1 = j;
        int k = 0;
        for (int i = 1; i <= nu; i++) {
            j2 = j1/2;
            k  = 2*k + j1 - 2*j2;
            j1 = j2;
        }
        return k;
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?