傅立叶变换

 
FT:提取频率
    

任何连续周期性信号都可以由一组适当的正弦曲线组合而成

 
Fourier(1868~1830),法国数学家,物理学家;
热衷于热传递研究,1807年发表论文,使用正弦曲线描述温度分布,

并提出了在当时具有争议的观点:
任何连续周期性信号都可以由一组适当的正弦曲线组合而成

    

相关文章

 
傅里叶变换概念及公式推导

彻底理解傅里叶变换!

    

傅里叶变换(FT)

 
傅里叶变换的目的是可将时域(即时间域)上的信号转变为频域(即频率域)上的信号,
随着域的不同,对同一个事物的了解角度也就随之改变,
因此在时域中某些不好处理的地方,在频域就可以较为简单的处理。
    

 
(w代表角频率,t代表时间,e^-iwt为复变函数) 
    
傅里叶变换认为一个周期函数(信号)包含多个频率分量,
任意函数(信号)f(t)可通过多个周期函数(基函数)相加而合成。 

从物理角度理解傅里叶变换是以一组特殊的函数(三角函数)为正交基,对原函数进行线性变换,
- 以正弦函数为数轴,构成的多维空间
物理意义便是原函数在各组基函数的投影。

 
信息在时间上的积分,累积,反反复复的周期性重复变化,就可以观察出规律了,规律就是频率
- 书读百遍,体悟出规律后,其义自现 
    

个人抽象理解

 
原函数是关于时间的函数,
一系列时间步(这个时间步要充足,要能包含信号本身所有的规律,充足的周期就可以)得到采样信息
原函数本身通常是时间上的连续信号,信息量是无穷尽的,但计算机计算不了这么大的信息量...
采样的时间步得到的信息足以表示/代表原函数这些信息,同时计算机可以计算了...

原函数在时间上的变化是有规律的,是周期性的,或者说反反复复就那些变化,就那些频率的变化
如此,原函数在时间上的积分就有可能形成一个 包含原函数所有规律的 分布

这个分布是一个关于频率的函数,在原信号的频段上有能量,在其他频率段上无能量 

傅立叶变换 用公式描述了这一点 
- 用有限且充足的时间步得到一个能表描原信号规律的分布
- 这个分布是一个关于频率的函数 
- 或者说信号在时间上的变化的这类函数,其本质在于组成信号的频率段,
- 即原函数为关于频率的函数,只是这个频率段是一个常量列表
- 任何事物(在时间上)的运动都是无穷尽的,本质是它们如何运动,即它们的频率
- 傅立叶变换通过分析一段时间的信号,反解出运动的本质:频率
    

周期/非周期,连续/离散,分四类

 
信号 按是 否具有周期,是否连续 分为四类
Fourier美/ˈfʊrieɪ/ n.傅立叶(姓氏)
Series英/ˈsɪəriːz/ 美/ˈsɪriːz/ n.系列;串联;连续;
Discrete 英/dɪˈskriːt/ 美/dɪˈskriːt/ adj.离散的;分离的;各别的;互不相连的

 
非周期性连续信号  傅立叶变换(Fourier Transform)

周期性连续信号    傅立叶级数(Fourier Series)

非周期性离散信号  离散时域傅立叶变换(Discrete Time Fourier Transform)

周期性离散信号    离散傅立叶变换(Discrete Fourier Transform)

    

Fourier Series为什么叫傅立叶级数,重点是series为什么被翻译为级数,series不应该是序列的意思吗,怎么会是级数

 
Fourier Series被翻译为傅立叶级数,
是因为它是由法国数学家傅立叶发现的一种特殊的数学工具。
至于“series”被翻译为“级数”而非“序列”,这主要基于数学中的特定语境和用法。

在数学中,“级数”通常指的是按照一定顺序排列的数的和,这些数可以是有限的,也可以是无限的。
而“序列”则更多地被用来描述按照一定顺序排列的数本身,而不强调它们的和。
    

 
在傅立叶级数的情境下,我们关注的是一系列正弦和余弦函数的和,
这些函数按照一定的频率和相位进行排列,以逼近或表示一个给定的周期函数。
因此,这里更强调的是这些函数的和,而不是它们本身,
所以“series”被翻译为“级数”更为合适。

总的来说,数学术语的翻译往往需要考虑其在特定语境下的用法和含义,以确保准确传达原意。

    

 

    

 

    

 
振动有频率,振动的物体的移动不考虑,即只考虑物体的振动,原地振动,
比如,人讲话不考虑人的移动,只考虑嗓子的振动,以及振动的规律,即频率

物体振动,以一定的频率 冲击/击打 空气,
没错,就像用手 有节奏地 拍打水面一样,只不过这里击打的是空气,
赋予空气分子特定方向的能量/动能,形成疏密波,就是疏密的能量冲击波,

注意,那个物体本身没有动,传递的是疏密的能量,这就是语音信号:
能量的传递规律,即频率,在时间上的变化

从大的时间尺度上讲,这是有周期的,反反复复就那些音符,
从小的时间尺度上看,是没有周期的,对应音符的频率不同

 
x(t)是原始信号,是幅度随时间变化的原始信号,是实数,

X(f)也是幅度,只是这个值是复数,
其模大部分为0,只在原始信号的 频率f上,有非零值,
这些值归一化(除以信号采样率的二分之一)后,就是各个原始信号的振幅

 
傅立叶变换的结果是一个关于 频率的函数X(f)
- 结果不是一个数,而是一个函数,这个函数的值是幅度,是能量
- 是关于频率的函数,时间经过积分之后就消失了,没有时间这个变量了;
  - 在无穷的时间尺度上,其规律就是频率的变化引发的能量变化
  - 比如,信号灯,1分钟闪烁一次,与3分钟闪烁一次,所传递的信号是不一样的
  - 比如,用手拍击水面,同样的力度,1秒钟拍一次,与3秒拍一次,形成的波纹是不同的
  - 但观察一段时间后,就会发现反反复复就那些变化,
  - 时间维度已经不重要了,我们要找到那个引发变化的关键因素
  - 关键是频率,不同的频率组合成的信号,只要找到对应的频率,就能重现这些变化 


 
每个人都自带一个信号发射器:嗓子,说什么话就发射什么样的频率信号
每个人都自带一对信号接收器:耳膜,随时接受300~3000Hz频段的声音信号

STFT,短时傅立叶变换

 
傅立叶变换没有时间的维度,
短时傅立叶用一个短小的时间窗口取一段信号,进行傅立叶变换,这样就有了时间的维度

    

 
傅立叶变换(Fourier Transform)是一种在时域(或空域)和频域之间转换信号或数据的数学工具。这种变换在信号处理、图像处理、量子力学、工程学、经济学等众多领域都有广泛的应用。

对于连续时间信号,傅立叶变换的定义如下:

设 ( x(t) ) 是一个在 ( -\infty ) 到 ( +\infty ) 上定义的连续时间信号,其傅立叶变换 ( X(f) ) 定义为:

[ X(f) = \int_{-\infty}{\infty} x(t) e{-j2\pi ft} , dt ]

其中,( f ) 是频率(单位为Hz),( j ) 是虚数单位(满足 ( j^2 = -1 ))。

 
同样地,给定一个频域函数 ( X(f) ),其逆傅立叶变换(Inverse Fourier Transform)为:

[ x(t) = \int_{-\infty}{\infty} X(f) e{j2\pi ft} , df ]

 
傅立叶逆变换则是给出频率在时间上的变化,是一个关于时间的函数,对应于原始时间信号

 
这两个公式建立了信号在时域和频域之间的对应关系。傅立叶变换将信号分解为一系列正弦和余弦波的叠加,这些正弦和余弦波具有不同的频率、幅度和相位。

对于离散时间信号(即数字信号),我们使用离散傅立叶变换(Discrete Fourier Transform, DFT)来分析。DFT是连续傅立叶变换在离散时间域和离散频率域上的推广。

此外,还有快速傅立叶变换(Fast Fourier Transform, FFT)算法,它是DFT的一种高效实现方式,极大地减少了计算复杂度,使得实时处理大量数据成为可能。

 


 
  
  FFT-百科

由于计算机技术的快速发展,在70年代中期,美国和日本的一些电子设备企业开始设计和生产数字式傅里叶分析仪,
但是由于离散傅里叶变换的计算量较大,直到DFT的快速算法(FFT)发现之后,
有限离散傅里叶变换(DFT)才真正获得了广泛的应用 [2]。

FFT是一种DFT的高效算法,称为快速傅里叶变换(fast Fourier transform)。
FFT算法可分为按时间抽取算法和按频率抽取算法,先简要介绍FFT的基本原理。
从DFT运算开始,说明FFT的基本原理。DFT的运算为:

 


 


 

  

 


连续·离散

按连续,离散介绍一下四种傅里叶变换及其公式

 
注意:这个矩阵没有提周期还是非周期,而在连续,离散的维度上加了时域与频域 

1. 连续频域 + 连续时域:连续时间傅里叶变换 (CTFT)

 
这是最“纯粹”的一种,时域和频域都是连续的。它用于分析非周期性的连续模拟信号。
- 目的:将一个连续的非周期时域信号分解成连续频率的指数函数(正弦波)之和。
    

 
特点:

时域信号 $x(t)$ 是非周期的,频域频谱 $X(f)$ 是连续的。

可以处理能量信号(如单个脉冲),但不适用于功率信号(如周期信号)。

    

离散频域 + 连续时域:连续时间傅里叶级数 (CTFS)

 
也称为经典的傅里叶级数 (Fourier Series)。它用于分析周期性的连续模拟信号。
目的:将一个连续的周期时域信号分解成一组离散频率的、谐波相关的正弦波之和。
- 一个周期为 $T$ 的信号 $x(t) = x(t + T)$

 

    

 

    

 


 

  

 


简易示例

采样数据的周期性

 
声音信号是连续的,数字化时以离散的方式存储,便于计算,这就涉及到采样 

采样操作/行为本身的特征
- 有很多采样方法,这里指隔固定的时间采一次样
- 比如,每秒采一次,那么这样的一个行为是一个重复性行为,循环性的周期性行为
- 周期指的是时间,那么一次完整的不重复也不遗漏的运动/行为 的时间就是1秒
- 将采样行为看作周期性运动时,它的最小正周期为两次采样时间的间隔
    

采样周期 不等于 信号本身的周期,
采样 采样,其实是踩的 语音信号上 时间点 所对应的数据,通常是相等的时间间隔
但采样的确是有规律有周期的,但也要注意,这并不是信号本身的规律,是观察信号的一种方法,
通过这种方法寻找信号的规律

其中一种规律是从频率的角度描述的,频率是周期的倒数
采样频率通常是信号频率的2n倍,比如2倍,4倍,8倍等
    

 
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负-的符号

import numpy as np
import numpy.fft as fft

# 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
Fs = 1024*8;              # 采样频率=1秒内采样Fs个点,也叫8KHz
dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
t = [i*dt for i in range(L)]  #从0开始到L-1个数值,时间点,时间步 
t = np.array(t)         # 转向量,叫“时间步”的多一些 

#信号的周期,规律,信息等,前面采样的方式只是得到一系列的时间点,代入信息的公式/规律中,以便于更好的观察信号
S1 = 5*np.sin(2*np.pi*100*t-20*2*np.pi/360)+3 
S2 = np.sin(2*np.pi*200*t-80*2*np.pi/360) 
S3 = np.sin(2*np.pi*210*t-80*2*np.pi/360) 
S4 = 0.5*np.sin(2*np.pi*230*t-30*2*np.pi/360) 
S5 = 2*np.sin(2*np.pi*270*t+30*2*np.pi/360) 

#语音信号是混合波,通常有5个主峰,这里就用5个正弦波模拟
S = S1+S2+S3+S4+S5
    

 
ll = 1024 
x = [i for i in range(0, ll)]
y1 = S[:ll]

# 使用matplotlib绘制图形
plt.plot(x, y1,linestyle="--", label='原始信号')   # 绘制第一个方程的曲线

# 添加图例
plt.legend()

# 显示网格线
plt.grid(True)

# 设置标题和坐标轴标签
plt.title('语音信号')
plt.xlabel('x')
plt.ylabel('y')

# 显示图形
plt.show()
    

 
x轴是数据的索引,重在展示数据的规律
    

 

    

 
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负-的符号

import numpy as np
import numpy.fft as fft

def sample_time():
    """采样时间向量"""
    # 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
    Fs = 1024*8;              # 采样频率=1秒内采样Fs个点,也叫8KHz
    dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
    L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
    t = [i*dt for i in range(L)]  #从0开始到L-1个数值
    t = np.array(t)         # 转向量
    return t

def sample_data(t):
    """采样信号数据"""
    #信号的周期,规律,信息等,前面采样的方式只是得到一系列的时间点,代入信息的公式/规律中,以便于更好的观察信号
    S1 = 5*np.sin(2*np.pi*100*t-20*2*np.pi/360)+3 
    S2 = np.sin(2*np.pi*200*t-80*2*np.pi/360) 
    S3 = np.sin(2*np.pi*210*t-80*2*np.pi/360) 
    S4 = 0.5*np.sin(2*np.pi*230*t-30*2*np.pi/360) 
    S5 = 2*np.sin(2*np.pi*270*t+30*2*np.pi/360) 
    
    #语音信号是混合波,通常有5个主峰,这里就用5个正弦波模拟
    S = S1+S2+S3+S4+S5
    return S
    

 
S = sample_data(t=sample_time())
complex_array = fft.fft(S)    # 傅立叶变换
pows = np.abs(complex_array)  # 复数的模,可以当作信号能量大小
    
    

 
ll = len(pows)//20
x = [i for i in range(0, ll)]
y2 = pows[:ll]/1000

# 使用matplotlib绘制图形
plt.plot(x, y2, linestyle="-.",label='fft模')  # 绘制第二个方程的曲线
plt.legend()    # 添加图例
plt.grid(True)  # 显示网格线

# 设置标题和坐标轴标签
plt.title('原始信号fft的能量分布')
plt.xlabel('x')
plt.ylabel('y')

# 显示图形
plt.show()
    

 
fft的模只在5个位置有能量,而原始信号刚好也是由5个频率的波组成的

实验证明,原始信号有多少个频率的波组成,其fft的能量就只在多少个位置上有能量波动


 
$\displaystyle [ X(f) = \int_{-\infty}^{\infty} x(t) e^{-j 2\pi f t} , dt ]$

这就是傅立叶变换,fft.fft(S),S=x(t),代入的参数就是时间相关的函数,
这里实际上是一个时间的等差数列

代入的时间,得到一个关于频率的函数

总体来说,fft的结果是,只在信号本身的频率上有能量波动
- 常量是时间步,由等差数列构成的一系列时间,这个时间中包括有采样频率
- 还有一个函数,加入时间是原始信号x(t)
- 频率也是一个变量 
- 从公式的整体来看,fft是关于频率的一个函数 
- 结果是只在原始信号的频率段上有能量波动
  - 即fft的变量f1与x(t)中的常量频率f2重合时,fft的模才不为0 

波是能量传播的形态,或者说能量以波的形态传播

 
声波是一种现象,它由物体振动产生,频率是振动的物理特性
波传递能量,物体之所以振动,也是因为得到了能量,然后开始振动...

只是在能量的传递过程中,添加了自己独特的信息,就是频率信息,形成独特的能量波动

傅立叶变换描述的是,不同的频率在时间上的积分,
其模也表示了,物体只在自己的频率上发射能量 

从接收的能量上,可以分析出能量发射的频段

 


频率分析

采样频率/信号中的采样个数L(信号长度) = 每两个采样点之间的间隔 对应的频段

 
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负-的符号

import numpy as np
import numpy.fft as fft

def sample_time():
    """采样时间向量"""
    # 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
    Fs = 1024*8;              # 采样频率=1秒内采样Fs个点,也叫8KHz
    dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
    L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
    t = [i*dt for i in range(L)]  #从0开始到L-1个数值
    t = np.array(t)         # 转向量
    return t
    
    

 
t = sample_time()

# 得到分解波的频率序列
freqs = fft.fftfreq(t.size, t[1] - t[0]) #采样间隔(采样率的倒数)。默认为 1;freqs包含样本频率的长度为 n 的数组。
freqs  # array([ 0.  ,  0.01,  0.02, ..., -0.03, -0.02, -0.01])
    

 
ll = len(freqs)
x = [i for i in range(ll)]
y = freqs

# 使用matplotlib绘制图形
plt.plot(x, y, linestyle="-.",label='原始信号频率')  # 绘制第二个方程的曲线
plt.legend()    # 添加图例
plt.grid(True)  # 显示网格线

# 设置标题和坐标轴标签
plt.title('分解波的频率序列')
plt.xlabel('x')
plt.ylabel('y')

# 显示图形
plt.show()
    

 
为什么取了信号长度一半的频段,
- 个人猜测,采样频段通常是信号频率的2n倍,
- 因此取一半就足够覆盖信号频率的频段了,仅个人猜测 
    

fft.fftfreq(n, d=1.0)

 
Return the Discrete Fourier Transform sample frequencies.
    
The returned float array `f` contains the frequency bin centers in cycles
per unit of the sample spacing (with zero at the start).  
For instance, if the sample spacing is in seconds, then the frequency unit is cycles/second.
    
Given a window length `n` and a sample spacing `d`::
    f = [0, 1, ...,   n/2-1,     -n/2, ..., -1] / (d*n)   if n is even
    f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n)   if n is odd
    

f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd

 
caiyang_zhouqi = t[1] - t[0]
caiyang_zhouqi
0.0001220703125


caiyang_pinlv = 1/caiyang_zhouqi 
caiyang_pinlv
8192.0

L = 1024*8*100;
caiyang_xinhao_interval = 1/L
caiyang_xinhao_interval
1.220703125e-06

采样频率/信号中的采样个数L(信号长度) = 每两个采样点之间的间隔 对应的频段

 
#由采样信号划分的原始信号频率间隔
yuanshi_pinlv_interval = caiyang_xinhao_interval*caiyang_pinlv
yuanshi_pinlv_interval
0.01


n=len(t)
index=(n-1)/2
index*0.01
4095.995


n
819200


len(freqs)
819200


# 由于采样频率至少是原始信号频率的2倍,因此由采样的二分之一得到的频率段必能包含原始信号的频率段
index=int(index)
freqs[index:index+3]
array([ 4095.99, -4096.  , -4095.99])

    

 
到此为止,还没有涉及原始信号的数据,只是在说采样频率,
意在指只要采样频率满足原始信号的2倍以上这个规律,
那么经由采样数据得到的频率段必能覆盖原始信号的频率段

 


 

    

 

    

 
plt.title('FFT变换·频谱图')
plt.xlabel('Frequency 频率')
plt.ylabel('fft模 幅度')
plt.tick_params(labelsize=10)   #坐标轴标签文字大小
plt.grid(linestyle=':')
plt.plot(freqs[freqs > 0], pows[freqs > 0], c='orangered', label='Frequency')  #画正频率的图像
plt.legend()
plt.tight_layout() #避免标签重叠
plt.show()
    

 
ll = int(len(freqs)/20)

plt.title('FFT变换·频谱图')
plt.xlabel('Frequency 频率')
plt.ylabel('fft模 幅度')
plt.tick_params(labelsize=10)   #坐标轴标签文字大小
plt.grid(linestyle=':')
plt.plot(freqs[:ll], pows[:ll], c='orangered', label='Frequency')  #画正频率的图像
plt.legend()
plt.tight_layout() #避免标签重叠
plt.show()
    

 
100,200刚好是原始信号的频率 
采样率是原始信号的2n倍,那么原始信号的周期是采样周期的2n倍 
而每个间隔就是采样的周期,以采样周期为步长,去分频,是可以包含原始信号的频率的 

这里分频的间隔是0.01,逐步增加,到一半时再逐步降低
freqs  # array([ 0.  ,  0.01,  0.02, ..., -0.03, -0.02, -0.01])
    
即使原始信号的频率不是整数,以0.01的步长增加,
也必定能逼近原始信号的频率,使之误差低于0.01 

 

    

 

    

 
import numpy as np
import numpy.fft as fft

def sample_time():
    """采样时间向量"""
    # 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
    Fs = 1024*8;              # 采样频率=1秒内采样Fs个点,也叫8KHz
    dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
    L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
    t = [i*dt for i in range(L)]  #从0开始到L-1个数值
    t = np.array(t)         # 转向量
    return t


t = sample_time()

# 得到分解波的频率序列
freqs = fft.fftfreq(t.size, t[1] - t[0]) #采样间隔(采样率的倒数)。默认为 1;freqs包含样本频率的长度为 n 的数组。

def sample_data(t):
    """采样信号数据"""
    #信号的周期,规律,信息等,前面采样的方式只是得到一系列的时间点,代入信息的公式/规律中,以便于更好的观察信号
    S1 = 5*np.sin(2*np.pi*100*t-20*2*np.pi/360)+3 
    S2 = np.sin(2*np.pi*200*t-80*2*np.pi/360) 
    S3 = np.sin(2*np.pi*210*t-80*2*np.pi/360) 
    S4 = 0.5*np.sin(2*np.pi*230*t-30*2*np.pi/360) 
    S5 = 2*np.sin(2*np.pi*270*t+30*2*np.pi/360) 
    
    #语音信号是混合波,通常有5个主峰,这里就用5个正弦波模拟
    S = S1+S2+S3+S4+S5
    return S

S = sample_data(t=sample_time())
complex_array = fft.fft(S)    # 傅立叶变换
pows = np.abs(complex_array)  # 复数的模,可以当作信号能量大小
    
    

 
x=freqs[freqs > 0]
y=pows[freqs > 0]
x[y>1]
array([100., 200., 210., 230., 270.])
    

 

    

 
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负-的符号

plt.figure(figsize=(16,8))
arr=complex_array[freqs > 0][y>1]
angle_y = np.arctan2(arr.imag,arr.real) 
freq=x[y>1]
# plt.plot(freqs[freqs > 0], angle_y[freqs > 0], c='orangered', label='Frequency')
# plt.plot(freq, angle_y, c='orangered', label='Frequency')
plt.scatter(freq, angle_y,c='orangered', label='Frequency') 
plt.grid(True)  # 显示网格

plt.legend()
plt.xlabel('Frequency 频率')
plt.ylabel('相位')
  

 
由complex_array = fft.fft(S) 得到的复数,
然后将复数a+bj看作复平面的点(a,b)
直接b/a求得反正切,作为斜率,对应角弧度

这样得到的角弧度与真实的初始相位有较大的差异,个人感觉几乎不能用 

 

  

 
import matplotlib.pyplot as plt
import numpy as np
import numpy.fft as fft
from matplotlib.pylab import mpl

mpl.rcParams['font.sans-serif'] = ['SimHei']   #显示中文
mpl.rcParams['axes.unicode_minus']=False       #显示负号

 
amplitude
英 [ˈæmplɪtjuːd]美 [ˈæmplɪtuːd]
n.(声音、无线电波等的)振幅

positive 英/ˈpɒzətɪv/ 美/ˈpɑːzətɪv/
adj.积极乐观的;完全的;良好的;正数的;建设性的;正电的;自信的;阳性的;拥护的;表示赞同的;有绝对把握;证据确凿的;朝着成功的
n.优势;优点;阳性结果(或反应);正片

 
fft.fftfreq(n, d=1.0)
f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd 

一个完整的正周期,一半正一半负,只考虑正的这一半就可以解决问题,或许这就是fftfreq如此设计的原因
一次完整的振动,偏移平衡位置的运动轨迹也是对称的,

考虑一个完整的半部分,不仅能研究其规律,并且比同时研究两边省事
毕竟能研究一半就搞定的事,谁会多此一举研究两边... 

下面就取的一个周期的一半进行的研究

 
Fs = 2000;           # 采样频率2000,满足采样定理,采样频率大于信号频率的2倍,原始信号频率800
dt = 1/Fs;           # 采样时间间隔
t  = np.arange(0,1,dt)  # 时间向量,Fs个;np.arange( 起点,终点,固定步长):

# 信号长度,按信号分析其规律,取一个完整的采样周期即可,短了不全,长了多余,
# Fs是频率,是规律,取Fs个点的数据就是信号
# 不同角度描述
N = Fs    
x = np.arange(N) 

#1秒的单位时间,Fs次振动,频率为Fs
y  =  7*np.sin(2*np.pi*800*t+50*np.pi/180) + 3  

fft_y=np.fft.fft(y)  # 傅立叶变换

  
  

 
abs_y=np.abs(fft_y)                 # 取复数的绝对值,即复数的模(双边频谱)
amplitude_y=abs_y/(N/2)                   # 归一化处理(双边频谱)
amplitude_positive = amplitude_y[range(int(N/2))] # 只取一半区间(单边频谱)

 
#频率列表,这里N=Fs,1秒的单位时间里的Fs个点,Fs次频率,每个点对应一个频率点
frq=x            # 频率点数N个数,信号长度
frq_positive=frq[range(int(N/2))]  #取一半区间;range(start, stop[, step]),实际对应的是频率分解列表,这里处理的更简单
  

 
plt.plot(frq_positive,amplitude_positive,'blue',ls="--",alpha=0.5,)
plt.title('单边振幅谱(归一化)',fontsize=8,color='blue')
plt.show()
  

 
归一化后的振幅,就是原始信号y=f(t) sin前面的振幅
  

 

  

 

  

 

  

 


fft.fft

 
import numpy as np
import numpy.fft as fft

def sample_time():
    """采样时间向量"""
    # 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
    Fs = 1024*8;              # 采样频率=1秒内采样Fs个点,也叫8KHz
    dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
    L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
    t = [i*dt for i in range(L)]  #从0开始到L-1个数值
    t = np.array(t)         # 转向量
    return t

def sample_data(t):
    """采样信号数据"""
    #信号的周期,规律,信息等,前面采样的方式只是得到一系列的时间点,代入信息的公式/规律中,以便于更好的观察信号
    S1 = 5*np.sin(2*np.pi*100*t-20*2*np.pi/360)+3 
    S2 = np.sin(2*np.pi*200*t-80*2*np.pi/360) 
    S3 = np.sin(2*np.pi*210*t-80*2*np.pi/360) 
    S4 = 0.5*np.sin(2*np.pi*230*t-30*2*np.pi/360) 
    S5 = 2*np.sin(2*np.pi*270*t+30*2*np.pi/360) 
    
    #语音信号是混合波,通常有5个主峰,这里就用5个正弦波模拟
    S = S1+S2+S3+S4+S5
    return S
    

 
t = sample_time()
S = sample_data(t= t)

# Compute the one-dimensional discrete Fourier Transform.
   
# 傅立叶变换,对应周期性离散信号,准确的名称为 discrete Fourier Transform
complex_array =  fft.fft(S)

discrete Fourier Transform

 
离散的数据
sample_time根据离散的时间点,时刻列表,取原始信号上对应时刻上的数据
所得到的数据sample_data为离散数据 
该离散数据是具有周期性,是周期性离散信号,
对应的傅立叶变换为 discrete Fourier Transform
    

 
语音信号就是一种 周期性离散信号 
    

 

    

 


 

  

 


Fourier逆变换

 
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负-的符号

import numpy as np
import numpy.fft as fft

def sample_time():
    """采样时间向量"""
    # 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
    Fs = 1024*8;              # 采样频率=1秒内采样Fs个点,也叫8KHz
    dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
    L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
    t = [i*dt for i in range(L)]  #从0开始到L-1个数值
    t = np.array(t)         # 转向量
    return t

def sample_data(t):
    """采样信号数据"""
    #信号的周期,规律,信息等,前面采样的方式只是得到一系列的时间点,代入信息的公式/规律中,以便于更好的观察信号
    S1 = 5*np.sin(2*np.pi*100*t-20*2*np.pi/360)+3 
    S2 = np.sin(2*np.pi*200*t-80*2*np.pi/360) 
    S3 = np.sin(2*np.pi*210*t-80*2*np.pi/360) 
    S4 = 0.5*np.sin(2*np.pi*230*t-30*2*np.pi/360) 
    S5 = 2*np.sin(2*np.pi*270*t+30*2*np.pi/360) 
    
    #语音信号是混合波,通常有5个主峰,这里就用5个正弦波模拟
    S = S1+S2+S3+S4+S5
    return S
    

 
t=sample_time()
S = sample_data(t=t)
complex_array = fft.fft(S)    # 傅立叶变换
S_ifft = fft.ifft(complex_array) #S_ifft是复数
    

 
#原始信号与傅里叶变换的逆变换信号对比
plt.figure(figsize=(16,8))
plt.subplot(211)
show_step = 500
plt.plot(t[0:show_step], S[0:show_step], 'r',ls="-.",alpha=0.7,label='原始信号')
plt.plot(t[0:show_step], S_ifft.real[0:show_step],'b',ls="--",alpha=0.5,label='傅里叶逆变换')
plt.legend();

plt.subplot(212)
plt.plot(t[0:show_step], S[0:show_step]-S_ifft.real[0:show_step], 'r',ls="--", alpha=0.6,label='信号误差')
plt.legend();
plt.grid(linestyle=':')
    

逆变换信号的实部与原始信号几乎完全重叠

 

    

 

    

 

    

 


 

  

 


FT提取特征

 
采样频率的定义就是1秒采集的样本点数,通常这个数字是物体固有频率的整数倍大小,
比如2倍,4倍,同时这也是一个周期,采样的周期

为什么是1秒的时间?
且不说采样频率,物体的固有属性-频率,也是取1秒时间的振动次数作为定义的

所以,取频率长度的数据,就是取1秒时间,就是取一个周期

 
import matplotlib.pyplot as plt 
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   #用来正常显示负-的符号

import numpy as np
import numpy.fft as fft

def sample_time(fre=1024*8):
    """采样时间向量"""
    # 采样的方式/规律,采的是一系列时间点/时刻,只是这些时刻 具有/内含 周期性
    Fs = fre;              # 采样频率=1秒内采样Fs个点,也叫8KHz
    dt = 1/Fs;                # 采样周期,时间间隔,时间步长,两个采样点之间的时间差
    L = 1024*8*100;               # 信号长度,大于L的最接近的2的次幂NFFT
    t = [i*dt for i in range(L)]  #从0开始到L-1个数值
    t = np.array(t)         # 转向量
    return t

def sample_data(t):
    """采样信号数据"""
    #信号的周期,规律,信息等,前面采样的方式只是得到一系列的时间点,代入信息的公式/规律中,以便于更好的观察信号
    S1 = 5*np.sin(2*np.pi*100*t-20*2*np.pi/360)+3 
    S2 = np.sin(2*np.pi*200*t-80*2*np.pi/360) 
    S3 = np.sin(2*np.pi*210*t-80*2*np.pi/360) 
    S4 = 0.5*np.sin(2*np.pi*230*t-30*2*np.pi/360) 
    S5 = 2*np.sin(2*np.pi*270*t+30*2*np.pi/360) 
    
    #语音信号是混合波,通常有5个主峰,这里就用5个正弦波模拟
    S = S1+S2+S3+S4+S5
    return S
    

 
fre=512
t = sample_time(fre=fre)
S = sample_data(t)
    

 
plt.figure(figsize=(16,8))
plt.subplot(211)
plt.plot(t[0:fre],S[0:fre], c='orangered', label='原始信号(一个采样频率/周期/1秒)')
plt.legend();
plt.grid(linestyle=':')
plt.xlabel('时间(秒)')
plt.ylabel('信号幅值(V)')
plt.title('原始信号时频图')

plt.subplot(212)
plt.plot(t[0:fre//4],S[0:fre//4], c='orangered', label='原始信号[四分之一周期]')
plt.legend();
plt.grid(linestyle=':')
plt.xlabel('时间(秒)')
plt.ylabel('信号幅值(V)')
plt.title('原始信号四分之一周期/1秒时频图')

plt.tight_layout() #避免标签重叠
plt.show()
    

 

    

 

    

 

    

 


 

  

 


参考