Java 实现 FFT,拿来吧你!

前言:

FFT 相关知识,强烈推荐看这篇博文:深入浅出的讲解傅里叶变换(真正的通俗易懂)

程序参考文章:

  • java实现快速傅里叶变换(FFT)

  • Java实现算法导论中快速傅里叶变换FFT递归算法

话不多说,直接上代码,。

代码:

class Complex {
    private double re = 0; // the real part
    private double im = 0; // the imaginary part
    private int index = 0; // the index ! to find 5 max

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public double getRe() {
        return re;
    }

    public void setRe(double re) {
        this.re = re;
    }

    public double getIm() {
        return im;
    }

    public void setIm(double im) {
        this.im = im;
    }

    // create a new object with the given real and imaginary parts  构造函数。
    public Complex(double real, double imag) {
        re = real;
        im = imag;
    }

    // return a string representation of the invoking Complex object
    public String toString() {
        if (im == 0)
            return re + "";
        if (re == 0)
            return im + "i";
        if (im < 0)
            return re + " - " + (-im) + "i";
        return re + " + " + im + "i";
    }

    // return abs/modulus/magnitude
    public double abs() {
        return Math.hypot(re, im);
    }

    // return angle/phase/argument, normalized to be between -pi and pi
    public double phase() {
        return Math.atan2(im, re);
    }

    // return a new Complex object whose value is (this + b)
    public Complex plus(Complex b) {
        Complex a = this; // invoking object
        double real = a.re + b.re;
        double imag = a.im + b.im;
        return new Complex(real, imag);
    }

    // return a new Complex object whose value is (this - b)
    public Complex minus(Complex b) {
        Complex a = this;
        double real = a.re - b.re;
        double imag = a.im - b.im;
        return new Complex(real, imag);
    }

    // return a new Complex object whose value is (this * b)
    public Complex multiple(Complex b) {
        Complex a = this;
        double real = a.re * b.re - a.im * b.im;
        double imag = a.re * b.im + a.im * b.re;
        return new Complex(real, imag);
    }

    // scalar multiplication
    // return a new object whose value is (this * alpha)
    public Complex multiple(double alpha) {
        return new Complex(alpha * re, alpha * im);
    }

    // return a new object whose value is (this * alpha)
    public Complex scale(double alpha) {
        return new Complex(alpha * re, alpha * im);
    }

    // return a new Complex object whose value is the conjugate of this
    public Complex conjugate() {
        return new Complex(re, -im);
    }

    // return a new Complex object whose value is the reciprocal of this
    public Complex reciprocal() {
        double scale = re * re + im * im;
        return new Complex(re / scale, -im / scale);
    }

    // return the real or imaginary part
    public double re() {
        return re;
    }

    public double im() {
        return im;
    }

    // return a / b
    public Complex divides(Complex b) {
        Complex a = this;
        return a.multiple(b.reciprocal());
    }

    // return a new Complex object whose value is the complex exponential of
    // this
    public Complex exp() {
        return new Complex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im));
    }

    // return a new Complex object whose value is the complex sine of this
    public Complex sin() {
        return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));
    }

    // return a new Complex object whose value is the complex cosine of this
    public Complex cos() {
        return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im));
    }

    // return a new Complex object whose value is the complex tangent of this
    public Complex tan() {
        return sin().divides(cos());
    }

    // a static version of plus
    public static Complex plus(Complex a, Complex b) {
        double real = a.re + b.re;
        double imag = a.im + b.im;
        return new Complex(real, imag);
    }

    public boolean equals(Object x) {
        if (x == null)
            return false;
        if (this.getClass() != x.getClass())
            return false;
        Complex that = (Complex) x;
        return (this.re == that.re) && (this.im == that.im);
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    public int hashCode() {
        return Objects.hash(re, im);
    }
}

代码调用:

Complex 类有其构造函数,初始化时候需要你传入 实部和虚部。

比如这里我将一个存放在 List<> 中需要做 fft 变换的数据,转换成 Complex 类型的数据。尤其是注意,Complex 类中的 fft 方法 传入和返回的类型都是 Complex 类数组,而类数组都需要二次初始化,就像下面我写的那样。

/**
 * List<> 数据转换 Complex[] 类型数据,以供其做 fft
 * @param Data 传入的数据,将其传入 实部
 * @return result 返回经傅里叶变换后的数据,类型为 Complex[]
 */
public static Complex[] list2complex(List<Float> Data) {
    Complex[] complex = new Complex[Data.size()];
    //类数组需要二次初始化,切记,不然会造成空指针情况
    for (int index = 0; index < complex.length; index++) {
        complex[index] = new Complex(0, 0);
    }
    for (int index = 0; index < complex.length; index++) {
        //将时域的 y 传入实部即可,虚部默认为 0,注意这一步需要结合你的需要来做。
        complex[index].setRe( (double) Data.get(index) );
    }
    return complex;
}

对数据做 fft 变换这样使用即可。我这里将 Complex 类和调用它的代码放在了同一个 .java 文件内,所以可以像下面这样直接调用 fft。如果你单独将 Complex 类放在了一个 .java 文件下,你需要这样 Complex.fft(),也很简单不是嘛?

Complex[] dataFFT =  fft( list2complex(data2T) );

另外如果熟悉 python ,推荐看这篇博文来加深使用 fft 的理解:使用python(scipy和numpy)实现快速傅里叶变换(FFT)最详细教程

效果图

这里我用 MPAndroidChart 画了两个图验证算法正确性:

这是时域图:直接用上面Python 文章中的那个了(偷懒~)
y=7 * np.sin(2 * np.pi * 200 * t) + 5 * np.sin(2 * np.pi * 400 * t)+3 * np.sin(2 * np.pi * 600 * t)
原始信号的三个正弦波的频率分别为,200Hz、400Hz、600Hz,最大频率为600赫兹。根据采样定理,fs至少是600赫兹的2倍,这里选择1400赫兹,即在一秒内选择1400个点。
Java 实现 FFT,拿来吧你!_第1张图片

这是频域图
Java 实现 FFT,拿来吧你!_第2张图片
学过信号系统都知道,明显很对嘛~(我没学过我也知道很对)

哦了,fft 就这,打完收工

你可能感兴趣的:(Python,Java,java,算法,fft)