zoukankan      html  css  js  c++  java
  • FFT算法的物理意义

    FFT是离散傅立叶变换的高速算法,能够将一个信号变换
    到频域。有些信号在时域上是非常难看出什么特征的,可是如
    果变换到频域之后,就非常easy看出特征了。这就是非常多信号
    分析採用FFT变换的原因。另外,FFT能够将一个信号的频谱
    提取出来,这在频谱分析方面也是经经常使用的。

        尽管非常多人都知道FFT是什么,能够用来做什么,怎么去
    做,可是却不知道FFT之后的结果是什意思、怎样决定要使用
    多少点来做FFT。

        如今圈圈就依据实际经验来说说FFT结果的详细物理意义。
    一个模拟信号,经过ADC採样之后,就变成了数字信号。採样
    定理告诉我们,採样频率要大于信号频率的两倍,这些我就
    不在此罗嗦了。

        採样得到的数字信号,就能够做FFT变换了。N个採样点,
    经过FFT之后,就能够得到N个点的FFT结果。为了方便进行FFT
    运算,通常N取2的整数次方。

        如果採样频率为Fs,信号频率F,採样点数为N。那么FFT
    之后结果就是一个为N点的复数。每一个点就相应着一个频率
    点。这个点的模值,就是该频率值下的幅度特性。详细跟原始
    信号的幅度有什么关系呢?如果原始信号的峰值为A,那么FFT
    的结果的每一个点(除了第一个点直流分量之外)的模值就是A
    的N/2倍。而第一个点就是直流分量,它的模值就是直流分量
    的N倍。而每一个点的相位呢,就是在该频率下的信号的相位。
    第一个点表示直流分量(即0Hz),而最后一个点N的再下一个
    点(实际上这个点是不存在的,这里是如果的第N+1个点,也
    能够看做是将第一个点分做两半分,还有一半移到最后)则表示
    採样频率Fs,这中间被N-1个点平均分成N等份,每一个点的频率
    依次添加�。比如某点n所表示的频率为:Fn=(n-1)*Fs/N。
    由上面的公式能够看出,Fn所能分辨到频率为为Fs/N,如果
    採样频率Fs为1024Hz,採样点数为1024点,则能够分辨到1Hz。
    1024Hz的採样率採样1024点,刚好是1秒,也就是说,採样1秒
    时间的信号并做FFT,则结果能够分析到1Hz,如果採样2秒时
    间的信号并做FFT,则结果能够分析到0.5Hz。如果要提高频率
    分辨力,则必须添加�採样点数,也即採样时间。频率分辨率和
    採样时间是倒数关系。
      如果FFT之后某点n用复数a+bi表示,那么这个复数的模就是
    An=根号a*a+b*b,相位就是Pn=atan2(b,a)。依据以上的结果,
    就能够计算出n点(n≠1,且n<=N/2)相应的信号的表达式为:
    An/(N/2)*cos(2*pi*Fn*t+Pn),即2*An/N*cos(2*pi*Fn*t+Pn)。
    对于n=1点的信号,是直流分量,幅度即为A1/N。
        因为FFT结果的对称性,通常我们仅仅使用前半部分的结果,
    即小于採样频率一半的结果。

        好了,说了半天,看着公式也晕,以下圈圈以一个实际的
    信号来做说明。

        如果我们有一个信号,它含有2V的直流分量,频率为50Hz、
    相位为-30度、幅度为3V的交流信号,以及一个频率为75Hz、
    相位为90度、幅度为1.5V的交流信号。用数学表达式就是例如以下:

    S=2+3*cos(2*pi*50*t-pi*30/180)+1.5*cos(2*pi*75*t+pi*90/180)

        式中cos參数为弧度,所以-30度和90度要分别换算成弧度。
    我们以256Hz的採样率对这个信号进行採样,总共採样256点。
    依照我们上面的分析,Fn=(n-1)*Fs/N,我们能够知道,每两个
    点之间的间距就是1Hz,第n个点的频率就是n-1。我们的信号
    有3个频率:0Hz、50Hz、75Hz,应该分别在第1个点、第51个点、
    第76个点上出现峰值,其他各点应该接近0。实际情况怎样呢?
    我们来看看FFT的结果的模值如图所看到的。

                          图1 FFT结果
        从图中我们能够看到,在第1点、第51点、和第76点附近有
    比較大的值。我们分别将这三个点附近的数据拿上来细看:
    1点: 512+0i
    2点: -2.6195E-14 - 1.4162E-13i 
    3点: -2.8586E-14 - 1.1898E-13i

    50点:-6.2076E-13 - 2.1713E-12i
    51点:332.55 - 192i
    52点:-1.6707E-12 - 1.5241E-12i

    75点:-2.2199E-13 -1.0076E-12i
    76点:3.4315E-12 + 192i
    77点:-3.0263E-14 +7.5609E-13i
      
        非常明显,1点、51点、76点的值都比較大,它附近的点值
    都非常小,能够觉得是0,即在那些频率点上的信号幅度为0。
    接着,我们来计算各点的幅度值。分别计算这三个点的模值,
    结果例如以下:
    1点: 512
    51点:384
    76点:192
        依照公式,能够计算出直流分量为:512/N=512/256=2;
    50Hz信号的幅度为:384/(N/2)=384/(256/2)=3;75Hz信号的
    幅度为192/(N/2)=192/(256/2)=1.5。可见,从频谱分析出来
    的幅度是正确的。
        然后再来计算相位信息。直流信号没有相位可言,不用管
    它。先计算50Hz信号的相位,atan2(-192, 332.55)=-0.5236,
    结果是弧度,换算为角度就是180*(-0.5236)/pi=-30.0001。再
    计算75Hz信号的相位,atan2(192, 3.4315E-12)=1.5708弧度,
    换算成角度就是180*1.5708/pi=90.0002。可见,相位也是对的。
    依据FFT结果以及上面的分析计算,我们就能够写出信号的表达
    式了,它就是我们開始提供的信号。

        总结:如果採样频率为Fs,採样点数为N,做FFT之后,某
    一点n(n从1開始)表示的频率为:Fn=(n-1)*Fs/N;该点的模值
    除以N/2就是相应该频率下的信号的幅度(对于直流信号是除以
    N);该点的相位即是相应该频率下的信号的相位。相位的计算
    可用函数atan2(b,a)计算。atan2(b,a)是求坐标为(a,b)点的角
    度值,范围从-pi到pi。要精确到xHz,则须要採样长度为1/x秒
    的信号,并做FFT。要提高频率分辨率,就须要添加�採样点数,
    这在一些实际的应用中是不现实的,须要在较短的时间内完毕
    分析。解决问题的方法有频率细分法,比較简单的方法是
    採样比較短时间的信号,然后在后面补充一定数量的0,使其长度
    达到须要的点数,再做FFT,这在一定程度上可以提高频率分辨力。
    详细的频率细分法可參考相关文献。

    [附录:本測试数据使用的matlab程序]
    close all; %先关闭全部图片
    Adc=2;  %直流分量幅度
    A1=3;   %频率F1信号的幅度
    A2=1.5; %频率F2信号的幅度
    F1=50;  %信号1频率(Hz)
    F2=75;  %信号2频率(Hz)
    Fs=256; %採样频率(Hz)
    P1=-30; %信号1相位(度)
    P2=90;  %信号相位(度)
    N=256;  %採样点数
    t=[0:1/Fs:N/Fs]; %採样时刻

    %信号
    S=Adc+A1*cos(2*pi*F1*t+pi*P1/180)+A2*cos(2*pi*F2*t+pi*P2/180);
    %显示原始信号
    plot(S);
    title('原始信号');

    figure;
    Y = fft(S,N); %做FFT变换
    Ayy = (abs(Y)); %取模
    plot(Ayy(1:N)); %显示原始的FFT模值结果
    title('FFT 模值');

    figure;
    Ayy=Ayy/(N/2);   %换算成实际的幅度
    Ayy(1)=Ayy(1)/2;
    F=([1:N]-1)*Fs/N; %换算成实际的频率值
    plot(F(1:N/2),Ayy(1:N/2));   %显示换算后的FFT模值结果
    title('幅度-频率曲线图');

    figure;
    Pyy=[1:N/2];
    for i=1:N/2
     Pyy(i)=phase(Y(i)); %计算相位
     Pyy(i)=Pyy(i)*180/pi; %换算为角度
    end;
    plot(F(1:N/2),Pyy(1:N/2));   %显示相位图
    title('相位-频率曲线图');

  • 相关阅读:
    yolo_to_onnx ValueError: need more tan 1 value to unpack
    yolo_to_onnx killed
    C++ 实现二维矩阵的加减乘等运算
    Leetcode 1013. Partition Array Into Three Parts With Equal Sum
    Leetcode 1014. Best Sightseeing Pair
    Leetcode 121. Best Time to Buy and Sell Stock
    Leetcode 219. Contains Duplicate II
    Leetcode 890. Find and Replace Pattern
    Leetcode 965. Univalued Binary Tree
    Leetcode 700. Search in a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4033032.html
Copyright © 2011-2022 走看看