FFT初步代码分析和逼近曲线
FFT:快速傅里叶变换
文章从两个方面来写,一个是FFT的基础知识,也就是将时域信号转换为频域信号,另一个是合成时域信号。
- 将时域信号转换为频域信号
代码来源于http://bigsec.net/b52/scipydoc/fft_study.html
FFT是将时域信号转换为频域信号,它是对一组数值进行运算,数组长度是2的整数次幂(64,128,256), 数值可以是实数也可以是复数,通常我们的时域信号都是实数,因此下面都以实数为例。我们可以把这一组实数想像成对某个连续信号按照一定取样周期进行取样而得来,如果对这组N个实数值进行FFT变换,将得到一个有N个复数的数组,我们称此复数数组为频域信号,此复数数组符合如下规律:
- 下标为0和N/2的两个复数的虚数部分为0,
- 下标为i和N-i的两个复数共轭,也就是其虚数部分数值相同、符号相反。
下面的例子演示了这一个规律,先以rand随机产生有8个元素的实数数组x,然后用fft对其运算之后,观察其结果为8个复数,并且满足上面两个条件:
import numpy as np
from numpy import * #随机产生8个数
x = np.random(8) #对这8个数进行傅里叶变换
xf = np.fft.fft(x)
# (3.988037788578344+0.0j)
# (-0.4137886303518952+0.4932605470110098j)
# (1.2456400001700039+0.14530526335520622j)
# (0.35597667913863856+0.3148093703101355j)
# (0.8683347993093808+0.0j)
# (0.35597667913863856-0.3148093703101355j)
# (1.2456400001700039-0.14530526335520622j)
# (-0.4137886303518952-0.4932605470110098j) #对xf进行逆傅里叶变换,逆变换之后,实数部分与原来的X相同
xff = np.fft.ifft(xf)
结果分析:下标为0的实数表示时域信号中直流成分是多少,下标为i的a+b * j表示时域信号中周期为N/i个取样值的正弦波和余弦波的成分的多少, 其中a表示cos波形的成分,b表示sin波形的成分。用全是1的数组来做实验。
x = np.ones(8)
#array([1., 1., 1., 1., 1., 1., 1., 1.])
np.fft.fft(x)
#[8.+0.j 0.-0.j 0.+0.j 0.+0.j 0.+0.j 0.-0.j 0.-0.j 0.+0.j]
取一个 周期为8个的取样的正弦波,观察FFT结果
x = np.arange(0, 2*np.pi, 2*np.pi/8)
#array([0. , 0.78539816, 1.57079633, 2.35619449, 3.14159265,
# 3.92699082, 4.71238898, 5.49778714])
y = np.sin(x)
np.fft.fft(y)
#array([ 1.22464680e-16+0.00000000e+00j, -4.36483172e-16-4.00000000e+00j,
# 1.22464680e-16-2.22044605e-16j, 1.91553812e-16-4.44089210e-16j,
# 1.22464680e-16+0.00000000e+00j, 1.91553812e-16+4.44089210e-16j,
# 1.22464680e-16+2.22044605e-16j, -4.36483172e-16+4.00000000e+00j])
用linspace创建取样点x,等分数据时步长只能使用整数
#若步长为8,则会7等分,因此设步长为9,将数据8等分,然后省去最后一个点。
x = np.linspace(0, 2*np.pi, 9, endpoint=False)
y = np.cos(x) np.fft.fft(np.cos(x))/len(x)
#([-8.63506797e-17+0.00000000e+00j, 5.00000000e-01-1.51531594e-16j,
# 3.77494957e-17-9.83914667e-19j, 6.16790569e-18+1.06831260e-17j,
# -3.77494957e-17-4.17485895e-17j, -3.77494957e-17+4.17485895e-17j,
# 6.16790569e-18-1.06831260e-17j, 3.77494957e-17+9.83914667e-19j,
# 5.00000000e-01+1.51531594e-16j])
#可看出实数的有效值是下标为1的数,5.00000000e-01-1.51531594e-16j,和余弦波之间的关系是0.5 * 2 = 1
再取不同的放大倍数作比较。
#将正弦的放大倍数设为2倍
np.fft.fft(2*np.sin(2*x))/len(x) #array([ 2.46716228e-16+0.00000000e+00j, 2.46716228e-17+1.97372982e-16j,
# -3.37020635e-16-1.00000000e+00j, 9.86864911e-17-8.54650083e-17j,
# 9.03044069e-17+0.00000000e+00j, 9.03044069e-17-0.00000000e+00j,
# 9.86864911e-17+8.54650083e-17j, -3.37020635e-16+1.00000000e+00j,
# 2.46716228e-17-1.97372982e-16j]) #可看出有效值在下标为2处,放大系数为2,由2*数值= 放大系数可知正弦对应的复数部分数值为-1. np.fft.fft(0.8*np.cos(2*x))/len(x) #array([-5.24271984e-17+0.00000000e+00j, -2.46716228e-17+9.08065713e-17j,
# 4.00000000e-01-1.76271580e-16j, 6.32210333e-17+2.67078151e-18j,
# 2.46716228e-17+5.34156302e-18j, 2.46716228e-17-5.34156302e-18j,
# 6.32210333e-17-2.67078151e-18j, 4.00000000e-01+1.76271580e-16j,
# -2.46716228e-17-9.08065713e-17j]) #可看出有效值在下标为2处,放大系数为0.8,由2*数值= 放大系数可知正弦对应的复数部分数值为0.4,即4.00000000e-01-1.76271580e-16j。
接下来考虑正弦波和余弦波叠之后,可产生同频率不同相位的各种余弦波。复数的模代表余弦波的振幅,幅角代表此频率余弦波的相位。
x = np.arange(0, 2*np.pi, 2*np.pi/128)
y = 0.3*np.cos(x) + 0.5*np.cos(2*x+np.pi/4) + 0.8*np.cos(3*x-np.pi/3)
yf = np.fft.fft(y)/len(y)
#前5个数值为有效值
yf[:4]
#计算数值对应的相位角
np.angle(yf[1]) #abs:返回绝对值,np.rad2deg:从弧度转为角度
np.abs(yf[1]), np.rad2deg(np.angle(yf[1]))
# (0.15000000000000002, -5.300924469105861e-15)
# 角度是0度,振幅是0.3
np.abs(yf[2]), np.rad2deg(np.angle(yf[2]))
#(0.2500000000000001, 45.000000000000014)
# 角度是45度,振幅是0.5
np.abs(yf[3]), np.rad2deg(np.angle(yf[3]))
#(0.4, -60.00000000000001)
# 角度是-60度,振幅是0.4
也就是说,进行傅里叶变换后,绝对值 * 2 对应振幅,np.rad2deg可求出对应的角度,即相位。
- 合成时域信号
使用正弦波和方波去逐步逼近曲线
import numpy as np
import pylab as pl # 取FFT计算的结果freqs中的前n项进行合成,返回合成结果,计算loops个周期的波形,返回合成波形
def fft_combine(freqs, n, loops=1):
length = len(freqs) * loops
data = np.zeros(length)
index = loops * np.arange(0, length, 1.0) / length * (2 * np.pi)
for k, p in enumerate(freqs[:n]):
if k != 0: p *= 2 # 除去直流成分之外,其余的系数都*2
data += np.real(p) * np.cos(k*index) # 余弦成分的系数为实数部
data -= np.imag(p) * np.sin(k*index) # 正弦成分的系数为负的虚数部
return index, data # 产生size点取样的三角波,其周期为1
#def triangle_wave(size):
# x = np.arange(0, 1, 1.0/size)
# y = np.where(x<0.5, x, 0)
# y = np.where(x>=0.5, 1-x, y)
# return x, y # 产生size点取样的方波,其周期为1
def square_wave(size):
x = np.arange(0, 1, 1.0/size)
y = np.where(x<0.5, 1.0, 0)
return x, y fft_size = 256 # 计算方波和其FFT
x, y = square_wave(fft_size)
fy = np.fft.fft(y) / fft_size # 绘制三角波的FFT的前20项的振幅,由于不含下标为偶数的值均为0, 因此取
# log之后无穷小,无法绘图,用np.clip函数设置数组值的上下限,保证绘图正确
pl.figure()
#np.clip(x,3,8):给数值设定范围,对于小于3的数,全部变成3,大于8的数全部变成8
pl.plot(np.clip(20*np.log10(np.abs(fy[:20])), -120, 120), "o")
pl.xlabel("frequency bin")
pl.ylabel("power(dB)")
pl.title("FFT result of triangle wave") # 绘制原始的三角波和用正弦波逐级合成的结果,使用取样点为x轴坐标
pl.figure()
pl.plot(y, label="original triangle", linewidth=2)
for i in [0,1,3,5,7,9]:
index, data = fft_combine(fy, i+1, 2) # 计算两个周期的合成波形
pl.plot(data, label = "N=%s" % i)
pl.legend()
pl.title("partial Fourier series of triangle wave")
pl.show()
用正弦波去逼近方波结果如下所示:

用正弦波去逼近三角波如下所示:

FFT初步代码分析和逼近曲线的更多相关文章
- 2018-2019-2 网络对抗技术 20165206 Exp4 恶意代码分析
- 2018-2019-2 网络对抗技术 20165206 Exp4 恶意代码分析 - 实验任务 1系统运行监控(2分) (1)使用如计划任务,每隔一分钟记录自己的电脑有哪些程序在联网,连接的外部IP ...
- 2018-2019-2 网络对抗技术 20165305 Exp4 恶意代码分析
Exp4 恶意代码分析 1.实践目标 1.1是监控你自己系统的运行状态,看有没有可疑的程序在运行. 1.2是分析一个恶意软件,就分析Exp2或Exp3中生成后门软件:分析工具尽量使用原生指令或sysi ...
- Exp4 恶意代码分析 20154320 李超
恶意代码 概述 恶意代码是指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的计算机代码.最常见的恶意代码有计算机病毒(简称病毒).特洛伊木马(简称木马).计算机蠕虫(简称蠕虫).后门.逻辑炸弹等. ...
- 20145317《网络对抗》Exp4 恶意代码分析
20145317<网络对抗>Exp4 恶意代码分析 一.基础问题回答 (1)总结一下监控一个系统通常需要监控什么.用什么来监控. 通常监控以下几项信息: 注册表信息的增删添改 系统上各类程 ...
- opencv —— approxPolyDP 生成逼近曲线
生成逼近曲线:approxPolyDP 函数 该函数采用 Douglas-Peucker 算法(也称迭代终点拟合算法).可以有效减少多边形曲线上点的数量,生成逼近曲线,简化后继操作. 经典的 Doug ...
- 病毒木马查杀实战第010篇:QQ盗号木马之十六进制代码分析
前言 按照我的个人习惯,在运用诸如IDA Pro与OllyDBG对病毒进行逆向分析之前,我都会利用一些自动化的工具,通过静态或动态的分析方法(参见<病毒木马查杀第008篇:熊猫烧香之病毒查杀总结 ...
- Android代码分析工具lint学习
1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...
- pmd静态代码分析
在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...
- [Asp.net 5] DependencyInjection项目代码分析-目录
微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...
随机推荐
- 廖雪峰Java14Java操作XML和JSON-1XML-3SAX
SAX:Simple API for XML 基于事件的API import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXPars ...
- HOOK NtCreateSection
本程序使用了hde32反汇编引擎,所以性能更加稳定! #pragma once #include <ntddk.h> NTSYSAPI NTSTATUS NTAPI NtCreateSec ...
- java面向对象特征 — 一句话概括
java基础学习总结之基本特征,最开始学习的时候,是形而上的理解,用了3年多,再回头看,理解起来颇为顺理成章 语言学习大概就是这样一种规律,学习,不甚解,应用,应用,渐深入人心,回头一看,恍然一悟 最 ...
- os一些记录
X86-32 内存机制 寄存器 段寄存器 指令寄存器 标志寄存器 编程技巧 通用格式双向链表 操作的接口 由一个指针找到宿主节点的方法
- 02-认识js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Codeforces 486D. Valid Sets
D. Valid Sets time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- windows API 第 18篇 FindFirstVolume FindNextVolume
函数定义:Retrieves the name of a volume on a computer. FindFirstVolume is used to begin scanning the vol ...
- /etc/sysctl.conf配置文件
# vi /etc/sysctl.conf # add by digoal.zhou fs.aio-max-nr = fs. kernel.core_pattern= /data01/corefile ...
- CF1140F - Extending Set of Points
题意:对于点集S,定义函数F(S)为对S不断扩展到不能扩展时S的点数.一次扩展定义为如果有一个平行于坐标轴的矩形的三个点在S中,则第四个点加入S. 动态在S中加点删点,每次操作完后求F(S)的值. 解 ...
- Web API 接口说明文档
1.采用 Web API Help Page 显示效果 2.swaggerui 创建文档接口 效果图 3.swagger ui 安装配置 nuget 安装 2.设置xml文件 3.配置根路径 预览sw ...