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 [ ...
随机推荐
- 廖雪峰Java11多线程编程-3高级concurrent包-3Condition
Condition实现等待和唤醒线程 java.util.locks.ReentrantLock用于替代synchronized加锁 synchronized可以使用wait和notify实现在条件不 ...
- 【转载】gdb基本命令总结
本文介绍使用gdb调试程序的常用命令. 主要内容: [简介] [举例] [其他] [简介] ============= GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.如果你是在 U ...
- C#一般处理程序设置和读取session(session报错“未将对象引用设置到对象的实例”解决)
登陆模块时,用到了session和cookie.在一般处理程序中处理session,一直报错.最后找到问题原因是需要调用 irequiressessionstate接口. 在ashx文件中,设置ses ...
- ConcurrentHashMap 和 Hashtable 的区别
ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同. 1.底层的数据结构: ConcurrentHashMap 在jdk1.7之前采用的是 分段的数组 ...
- MYSQL获取同时关注了某两个(或者N个)用户的用户
使用redis的set类型数据的话会比较容易,但是业务场景就是在mysql里面,因此也需要思考解决方法 表结构: CREATE TABLE `table_name` ( `id` ) unsigned ...
- js页面的弹框怎么关闭啊
1.单纯的关闭window.opener.location.reload(); //刷新父窗口中的网页window.close();//关闭当前窗窗口2.提交后关闭 function save(){d ...
- Linux的基本原则
Linux的基本原则:1.由目的单一的小程序组成,一个程序只做一件事,且做好: 2.’组合小程序完成复杂任务: 3.一切皆文件: 4.尽量避免捕获用户接口: 5.配置文件保存为纯文本格式: 6.提供机 ...
- shell脚本实现读取一个文件中的某一列,并进行循环处理
shell脚本实现读取一个文件中的某一列,并进行循环处理 1) for循环 #!bin/bash if [ ! -f "userlist.txt" ]; then echo &qu ...
- Java 使用模板生成 Word 文件---基于 Freemarker 模板框架
Java项目引入 Freemarker 插件自行完成. 步骤如下: .编写 Word 模板,并将模板中要用代码动态生成数据用 Freemarker 变量取代,即${变量名},如${username}: ...
- 11.Hibernate一对多关系
创建JavaBean 一方: Customer private long cust_id; private String cust_name; private long cust_user_id; p ...