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 [ ...
随机推荐
- 廖雪峰Java12maven基础-1maven入门-1maven介绍
1.Java项目: * 1.1.首先确定引入哪些依赖包,如commons-logging, log4j, selenium * 1.2.确定项目的目录结构 * 1.3.配置环境:如JDK的版本号 * ...
- 代码内存泄露检测工具(linux gcc + valrind)
参考博客: https://www.cnblogs.com/wangkangluo1/archive/2011/07/20/2111248.html linux命令如下:valgrind --tool ...
- BZOJ1912:[APIO2010]patrol巡逻
Description Input 第一行包含两个整数 n, K(1 ≤ K ≤ 2).接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n). Ou ...
- 第一个duilib程序 - 实现HelloWorld详解
duilib是一个windows下的皮肤库,用win32写的... 先看个效果图吧: 要使用duilib库,必须先把库导入,代码如下: View Row Code 1 #include "x ...
- PHPstorm同步服务器代码的缺点---命名空间undefined
在把一个服务器的代码同步到phpstorm下开发的时候,发现新建的命名空间代码都失效了,然而换到 https://blog.csdn.net/afraid_to_have/article/deta ...
- System.Web.Mvc.ViewEngineResult.cs
ylbtech-System.Web.Mvc.ViewEngineResult.cs 1.程序集 System.Web.Mvc, Version=5.2.3.0, Culture=neutral, P ...
- 关于前端调用后端php数据跨域的问题
https://blog.csdn.net/qq_21386275/article/details/87269979 js前端 <!DOCTYPE html><html>< ...
- 版本控制git之二 分支 切换分支 创建分支 合并 删除
版本控制git之二 分支 有人把 Git 的分支模型称为它的`‘必杀技特性’',也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出. 为何 Git 的分支模型如此出众呢? Git 处 ...
- myeclipse工程更新后java图标变为空心的解决办法
今天用svn更新了工程发现目录结构改变了,同时所有的java文件的图标变成了空心的.解决办法如下 1.右键单击工程目录名,选择properties. 2.选择java bulid path,正常的应该 ...
- js时间比较大小,时间加减
第一种: //时间类比较 startTime= new Date(Date.parse(starttime)); endTime=new Date(Date.parse(endTime)); //进行 ...