傅里叶变换 一维离散傅里叶变换

1、介绍。

        DFT:(Discrete Fourier Transform)离散傅里叶变换是傅里叶变换在时域和频域上都呈离散的形式,将信号的时域采样变换为其DTFT的频域采样。在形式上,变换两端(时域和频域上)的序列是有限长的,而实际上这两组序列都应当被认为是离散周期信号的主值序列。即使对有限长的离散信号作DFT,也应当将其看作其周期延拓的变换。实际应用的时候,都是使用快速傅里叶变换的,因为运算速度快。


1)、欧拉公式:

\LARGE \dpi{100} \LARGE e^{\theta i}=cos \theta +(sin \theta )i,其中i是虚数,即i的平方为-1。

 

2)、一维离散傅里叶变换DFT公式:

        \dpi{120} \begin{bmatrix}F(0)\\F(1)\\ F(2)\\ \vdots\\ F(N-1) \end{bmatrix} =\begin{bmatrix} 1&1&1&\cdots &1\\ 1&W_{N}^1&W_{N}^2&\cdots &W_{N}^{(N-1)}\\ 1&W_{N}^2&W_{N}^4&\cdots &W_{N}^{2(N-1)}\\ \vdots&\vdots&\vdots&\vdots &\vdots\\ 1&W_{N}^{(N-1)}&W_{N}^{2(N-1)}&\cdots &W_{N}^{(N-1)(N-1)}\\ \end{bmatrix} + \begin{bmatrix}f(0)\\f(1)\\ f(2)\\ \vdots\\ f(N-1) \end{bmatrix}

u是转换后一维数组的位置,F(u)是转换后数组中相应位置的值。x是原一维数组的位置,f(x)是原数组中相应的值。

\LARGE F(u)=\sum_{x=0}^{N-1}f(x)e^{-\frac{2\pi ux}{N}i},其中i是虚数。

一维DFT公式中的\LARGE -\frac{2\pi ux}{N}就是欧拉公式中的\LARGE \theta,而且\LARGE cos (-x) =cos x\LARGE sin (-x)=-sin x

所以一维DFT公式又可以写成:\LARGE F(u)=\sum_{x=0}^{N-1}f(x)[cos \frac{2\pi ux}{N}-sin \frac{2\pi ux}{N}i]

 

3)、一维离散傅里叶逆变换IDFT公式:

x是转换后一维数组的位置,f(x)是转换后数组中相应位置的值。u是原一维数组的位置,F(u)是原数组中相应的值。

\LARGE f(x)=\frac{1}{N}\sum_{u=0}^{N-1}F(u)e^{\frac{2\pi ux}{N}i}

又可以写成:\LARGE f(x)=\frac{1}{N}\sum_{u=0}^{N-1}F(u)[cos \frac{2\pi ux}{N}+sin \frac{2\pi ux}{N}i]

 

2、生成随机的一维数组。

    //f(x)=1+2x
    private static double[] getRandom(int length) {
        double[] array = new double[length];
        for (int x = 0; x < length; x++) {
            double value = 1 + 2 * x;
            array[x] = value;
        }
        return array;
    }

3、复数的类。参考文章高数 复数的四则运算

package com.zxj.reptile.utils.number;

public class Complex {
    private double real;//实数
    private double image;//虚数

    public Complex() {
        real = 0;
        image = 0;
    }

    public Complex(double real, double image) {
        this.real = real;
        this.image = image;
    }

    //加:(a+bi)+(c+di)=(a+c)+(b+d)i
    public Complex add(Complex complex) {
        double real = complex.getReal();
        double image = complex.getImage();
        double newReal = this.real + real;
        double newImage = this.image + image;
        return new Complex(newReal, newImage);
    }

    //减:(a+bi)-(c+di)=(a-c)+(b-d)i
    public Complex sub(Complex complex) {
        double real = complex.getReal();
        double image = complex.getImage();
        double newReal = this.real - real;
        double newImage = this.image - image;
        return new Complex(newReal, newImage);
    }

    //乘:(a+bi)(c+di)=(ac-bd)+(bc+ad)i
    public Complex mul(Complex complex) {
        double real = complex.getReal();
        double image = complex.getImage();
        double newReal = this.real * real - this.image * image;
        double newImage = this.image * real + this.real * image;
        return new Complex(newReal, newImage);
    }

    //乘:a(c+di)=ac+adi
    public Complex mul(double multiplier) {
        return mul(new Complex(multiplier, 0));
    }

    //除:(a+bi)/(c+di)=(ac+bd)/(c^2+d^2) +((bc-ad)/(c^2+d^2))i
    public Complex div(Complex complex) {
        double real = complex.getReal();
        double image = complex.getImage();
        double denominator = real * real + image * image;
        double newReal = (this.real * real + this.image * image) / denominator;
        double newImage = (this.image * real - this.real * image) / denominator;
        return new Complex(newReal, newImage);
    }

    //欧拉公式 e^(ix)=cosx+isinx
    public static Complex euler(double x) {
        double newReal = Math.cos(x);
        double newImage = Math.sin(x);
        return new Complex(newReal, newImage);
    }

    public double getReal() {
        return real;
    }

    public void setReal(double real) {
        this.real = real;
    }

    public double getImage() {
        return image;
    }

    public void setImage(double image) {
        this.image = image;
    }

    @Override
    public String toString() {
        String str = "";
        if (real != 0) {
            str += real;
        } else {
            str += "0";
        }
        if (image < 0) {
            str += image + "i";
        } else if (image > 0) {
            str += "+" + image + "i";
        }
        return str;
    }
}

4、一维离散傅里叶变换DFT和一维逆离散傅里叶变换IDFT代码。

    /**
     * 一维离散傅里叶变换DFT
     *
     * @param array 一维数组
     */
    public static Complex[] getDft(double[] array) {
        Complex[] complexArray = Complex.getComplexArray(array);
        return dftProgress(complexArray, -1);
    }

    /**
     * 一维逆离散傅里叶变换IDFT
     *
     * @param complexArray 一维复数数组
     */
    public static double[] getInverseDft(Complex[] complexArray) {
        int length = complexArray.length;
        Complex[] resultArray = dftProgress(complexArray, 1);
        double[] array = new double[length];
        for (int i = 0; i < length; i++) {
            array[i] = NumberUtils.getRound(resultArray[i].getReal() / length, 2);
        }
        return array;
    }

    /**
     * 一维离散傅里叶变换DFT和一维逆离散傅里叶变换IDFT计算过程
     *
     * @param array 复数数组
     * @param minus 正负值,DFT=-1,IDFT=1
     */
    private static Complex[] dftProgress(Complex[] array, int minus) {
        int length = array.length;
        Complex[] complexArray = new Complex[length];
        // minus * 2 * PI / N
        double flag = minus * 2 * Math.PI / length;
        for (int i = 0; i < length; i++) {
            Complex sum = new Complex();
            for (int j = 0; j < length; j++) {
                //array[x] * e^((minus * 2 * PI * k / N)i)
                Complex complex = Complex.euler(flag * i * j).mul(array[j]);
                sum = complex.add(sum);
            }
            //累加
            complexArray[i] = sum;
        }
        return complexArray;
    }

5、流程。可以先将随机数组的大小设小点,然后将打印日志的代码开起来,这样子才会对流程有更多的了解。

    public static void main(String[] args) {
        System.out.println("------开始------");
        long time = System.currentTimeMillis();
        testDft(3000);//一维离散傅里叶变换
        System.out.println("花费时间 :" + (System.currentTimeMillis() - time));
        System.out.println("------结束------");
    }

    private static void testDft(int length) {
        //System.out.println("原数据: ");
        double[] array = getRandom(length);
        for (int i = 0; i < array.length; i++) {
            //System.out.println(array[i]);
        }
        //System.out.println("离散傅里叶变换DFT: ");
        Complex[] dtfArray = FourierUtils.getDft(array);
        for (int i = 0; i < dtfArray.length; i++) {
            //System.out.println(dtfArray[i]);
        }
        //System.out.println("逆离散傅里叶变换IDFT: ");
        double[] inverseDtfArray = FourierUtils.getInverseDft(dtfArray);
        for (int i = 0; i < inverseDtfArray.length; i++) {
            //System.out.println(inverseDtfArray[i]);
        }
        System.out.print("一维离散傅里叶变换和逆离散傅里叶变换");
        if (Arrays.equals(array, inverseDtfArray)) {
            System.out.println("成功");
        } else {
            System.out.println("失败");
        }
    }

6、结果。可以将生成随机一维数组的大小进行改变,也可以对生成随机数据的函数进行改变。会发现原数组和经过离散傅里叶变换DFT及逆离散傅里叶变换IDFT之后的数组是一模一样的,就可以验证出算法和公式是对的。

傅里叶变换 一维离散傅里叶变换_第1张图片

 

你可能感兴趣的:(高数)