MATLAB处理信号得到频谱、相谱、功率谱
(此帖引至网络资源,仅供参考学习)
第一:频谱
一.调用方法
X=FFT(x);
X=FFT(x,N);
x=IFFT(X);
x=IFFT(X,N)
用MATLAB进行谱分析时注意:
(1)函数FFT返回值的数据结构具有对称性。
例:
N=8;
n=0:N-1;
xn=[4 3 2 6 7 8 9 0];
Xk=fft(xn)
→
Xk =
39.0000 -10.7782 + 6.2929i 0 - 5.0000i 4.7782 - 7.7071i 5.0000 4.7782 + 7.7071i 0 + 5.0000i -10.7782 - 6.2929i
Xk与xn的维数相同,共有8个元素。Xk的第一个数对应于直流分量,即频率值为0。
(2)做FFT分析时,幅值大小与FFT选择的点数有关,但不影响分析结果。在IFFT时已经做了处理。要得到真实的振幅值的大小,只要将得到的变换后结果乘以2除以N即可。
二.FFT应用举例
例1:x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t)。采样频率fs=100Hz,分别绘制N=128、1024点幅频图。
clf;
fs=100;N=128; %采样频率和数据点数
n=0:N-1;t=n/fs; %时间序列
x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t); %信号
y=fft(x,N); %对信号进行快速Fourier变换
mag=abs(y); %求得Fourier变换后的振幅
f=n*fs/N; %频率序列
subplot(2,2,1),plot(f,mag); %绘出随频率变化的振幅
xlabel('频率/Hz');
ylabel('振幅');title('N=128');grid on;
subplot(2,2,2),plot(f(1:N/2),mag(1:N/2)); %绘出Nyquist频率之前随频率变化的振幅
xlabel('频率/Hz');
ylabel('振幅');title('N=128');grid on;
%对信号采样数据为1024点的处理
fs=100;N=1024;n=0:N-1;t=n/fs;
x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t); %信号
y=fft(x,N); %对信号进行快速Fourier变换
mag=abs(y); %求取Fourier变换的振幅
f=n*fs/N;
subplot(2,2,3),plot(f,mag); %绘出随频率变化的振幅
xlabel('频率/Hz');
ylabel('振幅');title('N=1024');grid on;
subplot(2,2,4)
plot(f(1:N/2),mag(1:N/2)); %绘出Nyquist频率之前随频率变化的振幅
xlabel('频率/Hz');
ylabel('振幅');title('N=1024');grid on;
fs=100Hz,Nyquist频率为fs/2=50Hz。整个频谱图是以Nyquist频率为对称轴的。并且可以明显识别出信号中含有两种频率成分:15Hz和40Hz。由此可以知道FFT变换数据的对称性。因此用FFT对信号做谱分析,只需考察0~Nyquist频率范围内的福频特性。若没有给出采样频率和采样间隔,则分析通常对归一化频率0~1进行。另外,振幅的大小与所用采样点数有关,采用128点和1024点的相同频率的振幅是有不同的表现值,但在同一幅图中,40Hz与15Hz振动幅值之比均为4:1,与真实振幅0.5:2是一致的。为了与真实振幅对应,需要将变换后结果乘以2除以N。
例2:x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t),fs=100Hz,绘制:
(1)数据个数N=32,FFT所用的采样点数NFFT=32;
(2)N=32,NFFT=128;
(3)N=136,NFFT=128;
(4)N=136,NFFT=512。
clf;fs=100; %采样频率
Ndata=32; %数据长度
N=32; %FFT的数据长度
n=0:Ndata-1;t=n/fs; %数据对应的时间序列
x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t); %时间域信号
y=fft(x,N); %信号的Fourier变换
mag=abs(y); %求取振幅
f=(0:N-1)*fs/N; %真实频率
subplot(2,2,1),plot(f(1:N/2),mag(1:N/2)*2/N); %绘出Nyquist频率之前的振幅
xlabel('频率/Hz');ylabel('振幅');
title('Ndata=32 Nfft=32');grid on;
Ndata=32; %数据个数
N=128; %FFT采用的数据长度
n=0:Ndata-1;t=n/fs; %时间序列
x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t);
y=fft(x,N);
mag=abs(y);
f=(0:N-1)*fs/N; %真实频率
subplot(2,2,2),plot(f(1:N/2),mag(1:N/2)*2/N); %绘出Nyquist频率之前的振幅
xlabel('频率/Hz');ylabel('振幅');
title('Ndata=32 Nfft=128');grid on;
Ndata=136; %数据个数
N=128; %FFT采用的数据个数
n=0:Ndata-1;t=n/fs; %时间序列
x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t);
y=fft(x,N);
mag=abs(y);
f=(0:N-1)*fs/N; %真实频率
subplot(2,2,3),plot(f(1:N/2),mag(1:N/2)*2/N); %绘出Nyquist频率之前的振幅
xlabel('频率/Hz');ylabel('振幅');
title('Ndata=136 Nfft=128');grid on;
Ndata=136; %数据个数
N=512; %FFT所用的数据个数
n=0:Ndata-1;t=n/fs; %时间序列
x=0.5*sin(2*pi*15*t)+2*sin(2*pi*40*t);
y=fft(x,N);
mag=abs(y);
f=(0:N-1)*fs/N; %真实频率
subplot(2,2,4),plot(f(1:N/2),mag(1:N/2)*2/N); %绘出Nyquist频率之前的振幅
xlabel('频率/Hz');ylabel('振幅');
title('Ndata=136 Nfft=512');grid on;
结论:
(1)当数据个数和FFT采用的数据个数均为32时,频率分辨率较低,但没有由于添零而导致的其他频率成分。
(2)由于在时间域内信号加零,致使振幅谱中出现很多其他成分,这是加零造成的。其振幅由于加了多个零而明显减小。
(3)FFT程序将数据截断,这时分辨率较高。
(4)也是在数据的末尾补零,但由于含有信号的数据个数足够多,FFT振幅谱也基本不受影响。
对信号进行频谱分析时,数据样本应有足够的长度,一般FFT程序中所用数据点数与原含有信号数据点数相同,这样的频谱图具有较高的质量,可减小因补零或截断而产生的影响。
例3:x=cos(2*pi*0.24*n)+cos(2*pi*0.26*n)
(1)数据点过少,几乎无法看出有关信号频谱的详细信息;
(2)中间的图是将x(n)补90个零,幅度频谱的数据相当密,称为高密度频谱图。但从图中很难看出信号的频谱成分。
(3)信号的有效数据很长,可以清楚地看出信号的频率成分,一个是0.24Hz,一个是0.26Hz,称为高分辨率频谱。
可见,采样数据过少,运用FFT变换不能分辨出其中的频率成分。添加零后可增加频谱中的数据个数,谱的密度增高了,但仍不能分辨其中的频率成分,即谱的分辨率没有提高。只有数据点数足够多时才能分辨其中的频率成分。
第二: 相谱
(相位谱和频率普是回事儿,想着把频谱中的幅值部分换成相角就可以了)
由于没有找到具体的理论,就举几个例子说明一下。
比如要求y=sin(2*pi*60*t) 的相位谱,
程序如下:
fs=200;N=1024;n=0:N-1;t=n/fs;y=sin(2*pi*60*t);
Y=fft(y,N);
A=abs(Y);f=n*fs/N;
ph=2*angle(Y(1:N/2));
ph=ph*180/pi;
plot(f(1:N/2),ph(1:N/2));
xlabel('频率/hz'),ylabel('相角'),title('相位谱');
grid on;
期中的 ph=2*angle(Y(1:N/2));ph=ph*180/pi;是利用angle函数求出每个点的角度,并由弧度转化成角度!
angle函数解释:
Phase angle
Syntax
P = angle(Z)
Description
P = angle(Z) returns the phase angles, in radians, for each element of complex array Z. The angles lie between ±π.
For complex Z, the magnitude R and phase angle theta are given by
R = abs(Z)
theta = angle(Z)
and the statement
Z = R.*exp(i*theta)
converts back to the original complex Z.
Examples
Z = [ 1 - 1i 2 + 1i 3 - 1i 4 + 1i
1 + 2i 2 - 2i 3 + 2i 4 - 2i
1 - 3i 2 + 3i 3 - 3i 4 + 3i
P = angle(Z)
P =
-0.7854 0.4636 -0.3218 0.2450
1.1071 -0.7854 0.5880 -0.4636
-1.2490 0.9828 -0.7854 0.6435
1.3258 -1.1071 0.9273 -0.7854
Algorithms
The angle function can be expressed as angle(z) = imag(log(z)) = atan2(imag(z),real(z)).
第三:功率谱
matlab实现经典功率谱估计
fft做出来是频谱,psd做出来是功率谱;功率谱丢失了频谱的相位信息;频谱不同的信号其功率谱是可能相同的;功率谱是幅度取模后平方,结果是个实数
matlab中自功率谱密度直接用psd函数就可以求,按照matlab的说法,psd能实现Welch法估计,即相当于用改进的平均周期图法来求取随机信号的功率谱密度估计。psd求出的结果应该更光滑吧。
1、直接法:
直接法又称周期图法,它是把随机序列x(n)的N个观测数据视为一能量有限的序列,直接计算x(n)的离散傅立叶变换,得X(k),然后再取其幅值的平方,并除以N,作为序列x(n)真实功率谱的估计。
Matlab代码示例:
clear;
Fs=1000; %采样频率
n=0:1/Fs:1;
%产生含有噪声的序列
xn=cos(2*pi*40*n)+3*cos(2*pi*100*n)+randn(size(n));
window=boxcar(length(xn)); %矩形窗
nfft=1024;
[Pxx,f]=periodogram(xn,window,nfft,Fs); %直接法
plot(f,10*log10(Pxx));
2、间接法:
间接法先由序列x(n)估计出自相关函数R(n),然后对R(n)进行傅立叶变换,便得到x(n)的功率谱估计。
Matlab代码示例:
clear;
Fs=1000; %采样频率
n=0:1/Fs:1;
%产生含有噪声的序列
xn=cos(2*pi*40*n)+3*cos(2*pi*100*n)+randn(size(n));
nfft=1024;
cxn=xcorr(xn,'unbiased'); %计算序列的自相关函数
CXk=fft(cxn,nfft);
Pxx=abs(CXk);
index=0:round(nfft/2-1);
k=index*Fs/nfft;
plot_Pxx=10*log10(Pxx(index+1));
plot(k,plot_Pxx);
3、改进的直接法:对于直接法的功率谱估计,当数据长度N太大时,谱曲线起伏加剧,若N太小,谱的分辨率又不好,因此需要改进。
3.1、Bartlett法
Bartlett平均周期图的方法是将N点的有限长序列x(n)分段求周期图再平均。
Matlab代码示例:
clear;
Fs=1000;
n=0:1/Fs:1;
xn=cos(2*pi*40*n)+3*cos(2*pi*100*n)+randn(size(n));
nfft=1024;
window=boxcar(length(n)); %矩形窗
noverlap=0; %数据无重叠
p=0.9; %置信概率
[Pxx,Pxxc]=psd(xn,nfft,Fs,window,noverlap,p);
index=0:round(nfft/2-1);
k=index*Fs/nfft;
plot_Pxx=10*log10(Pxx(index+1));
plot_Pxxc=10*log10(Pxxc(index+1));
figure(1)
plot(k,plot_Pxx);
pause;
figure(2)
plot(k,[plot_Pxx plot_Pxx-plot_Pxxc plot_Pxx+plot_Pxxc]);
3.2、Welch法
Welch法对Bartlett法进行了两方面的修正,一是选择适当的窗函数w(n),并再周期图计算前直接加进去,加窗的优点是无论什么样的窗函数均可使谱估计非负。二是在分段时,可使各段之间有重叠,这样会使方差减小。
Matlab代码示例:
clear;
Fs=1000;
n=0:1/Fs:1;
xn=cos(2*pi*40*n)+3*cos(2*pi*100*n)+randn(size(n));
nfft=1024;
window=boxcar(100); %矩形窗
window1=hamming(100); %海明窗
window2=blackman(100); %blackman窗
noverlap=20; %数据无重叠
range='half'; %频率间隔为[0 Fs/2],只计算一半的频率
[Pxx,f]=pwelch(xn,window,noverlap,nfft,Fs,range);
[Pxx1,f]=pwelch(xn,window1,noverlap,nfft,Fs,range);
[Pxx2,f]=pwelch(xn,window2,noverlap,nfft,Fs,range);
plot_Pxx=10*log10(Pxx);
plot_Pxx1=10*log10(Pxx1);
plot_Pxx2=10*log10(Pxx2);
figure(1)
plot(f,plot_Pxx);
pause;
figure(2)
plot(f,plot_Pxx1);
pause;
figure(3)
plot(f,plot_Pxx2);
第四: 相关性分析
1. 首先说说自相关和互相关的概念。
t=[0:dt:100];
x=cos(t);
[a,b]=xcorr(x,'unbiased');
plot(b*dt,a)
上面代码是求自相关函数并作图,对于互相关函数,稍微修改一下就可以了,即把[a,b]=xcorr(x,'unbiased');改为[a,b]=xcorr(x,y,'unbiased');便可。
2. 实现过程:
在Matalb中,求解xcorr的过程事实上是利用Fourier变换中的卷积定理进行的,即R(u)=ifft(fft(f)×fft(g)),其中×表示乘法,注:此公式仅表示形式计算,并非实际计算所用的公式。当然也可以直接采用卷积进行计算,但是结果会与xcorr的不同。事实上,两者既然有定理保证,那么结果一定是相同的,只是没有用对公式而已。下面是检验两者结果相同的代码:
dt=.1;
t=[0:dt:100];
x=3*sin(t);
y=cos(3*t);
subplot(3,1,1);
plot(t,x);
subplot(3,1,2);
plot(t,y);
[a,b]=xcorr(x,y);
subplot(3,1,3);
plot(b*dt,a);
yy=cos(3*fliplr(t)); % or use: yy=fliplr(y);
z=conv(x,yy);
pause;
subplot(3,1,3);
plot(b*dt,z,'r');
即在xcorr中不使用scaling。
(1)相关程度与相关函数的取值有什么联系?
对于相关系数的大小所表示的意义目前在统计学界尚不一致,但通常按下是这样认为的:
相关系数 相关程度
0.00-±0.30 微相关
±0.30-±0.50 实相关
±0.50-±0.80 显著相关
±0.80-±1.00 高度相关
分别用这两个函数对同一个序列计算,为什么结果不太一样?因为xcorr是没有将均值减掉做的相关,autocorr则是减掉了均值的。而且,用离散信号做自相关时,信号截取长度(采样点N)不一样,自相关函数就不一样。
(3)xcorr是计算互相关函数,带有一个option的参数:
a=xcorr(x,y,'option')
option=baised时,是计算互相关函数的有偏估计;
option=unbaised时,是计算互相关函数的无偏估计;
option=coeff时,是计算归一化的互相关函数,即为互相关系数,在-1至1之间;
option=none,是缺省的情况。
所以想要计算互相关系数,可用'coeff'参数。
*************************************************************************
用这个xcorr函数作离散互相关运算时要注意,当x, y是不等长向量时,短的向量会自动填0与长的对齐,运算结果是行向量还是列向量就与x一样。
互相关运算计算的是x,y两组随机数据的相关程度,使用参数coeff时,结果就是互相关系数,在-1至1之间,否则结果不一定在这范围,有可能很大也有可能很小,这视乎x, y数据的大小,所以一般要计算两组数据的相关程度,一般选择coeff参数,对结果进行归一化。
所谓归一化简单理解就是将数据系列缩放到-1到1范围,正式的就是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为纯量。变换式为X=(X实测--Xmin)/(Xmax-Xmin)。
一般来说选择归一化进行互相关运算后,得到结果绝对值越大,两组数据相关程度就越高。
MATLAB处理信号得到频谱、相谱、功率谱的更多相关文章
- 用MATLAB对信号做频谱分析
1.首先学习下傅里叶变换的东西.学高数的时候老师只是将傅里叶变换简单的说了下,并没有深入的讲解.而现在看来,傅里叶变换似乎是信号处理的方面的重点只是呢,现在就先学习学习傅里叶变换吧. 上面这幅图在知乎 ...
- Python科学计算(两)——时域波形和正弦信号的频谱
Python科学计算(两)-- 时域和频域波形为正弦波形信号生成.计算和显示 # -*- coding: utf-8 -*- import numpy as np import matplotlib. ...
- matlab 正弦信号产生
fs=2400;%设定采样频率N=1000; %采样的点数n=0:N-1;t=n/fs; %1/fs相当于隔多长时间才一个点f1=50;%设定争先信号频率xn=sin(2*pi*f1*t);figur ...
- 【MATLAB】画信号频谱的子函数
输入信号序列和采样率,该子函数可以画出该信号的频谱图. function [f,spec,NFFT]=spec_fft_plot(sample,L,Fs) % 输入数据说明: % sample:信号序 ...
- 信号处理基础概念比较----频谱vs功率谱vs能谱
频谱: 对动态信号在频率域内进行分析,分析的结果是以频率为坐标的各种物理量的谱线和曲线,可得到各种幅值以频率为变量的频谱函数F(ω).频谱是个很不严格的东西,常常指信号的Fourier变换.频谱分析中 ...
- MATLAB信号与系统分析(五)——连续时间信号的频谱分析
一.实验目的: 1.掌握傅立叶级数(FS),学会分析连续时间周期信号的频谱分析及MATLAB实现: 2.掌握傅立叶变换(FT),了解傅立叶变换的性质以及MATLAB实现. 二.利用符号运算求傅里叶级数 ...
- 小波变换检测信号突变点的MATLAB实现
之前在不经意间也有接触过求突变点的问题.在我看来,与其说是求突变点,不如说是我们常常玩的"找不同".给你两幅图像,让你找出两个图像中不同的地方,我认为这其实也是找突变点在生活中的应 ...
- MATLAB—信号与系统中的应用
文章目录 一. 理论知识 1.线性系统的响应 2.微分方程的解 Ⅰ.经典解 Ⅱ.完全响应 3.零输入响应 4.零状态响应 5.冲激响应 6.阶跃响应 7.卷积求零状态响应 二.连续信号的MATLAB描 ...
- 基于Matlab的MMSE的语音增强算法的研究
本课题隶属于学校的创新性课题研究项目.2012年就已经做完了,今天一并拿来发表. 目录: --基于谱减法的语音信号增强算法..................................... ...
随机推荐
- 安装第三方Python模块,增加InfoPi的健壮性
这3个第三方Python模块是可选的,不安装的话InfoPi也可以运行. 但是如果安装了,会增加InfoPi的健壮性. 目录 1.cchardet 自动检测文本编码 2.lxml 用于解析 ...
- Qt中数据模块学习
QtSql模块 驱动类型和数据库:不同的数据库用不同的驱动连接(接口不同) QDB2->DB2 QOCI->orcle QODBC->SQLServer等 QSqlDataBase类 ...
- polyfill之javascript函数的兼容写法——Array篇
1. Array.isArray(obj) if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype. ...
- 一段关于测试和自定义Attribute的代码
来自<西夏普入门经典> using System; using System.Collections.Generic; using System.Linq; using System.Te ...
- 用freemarker定义宏实现自定义公用控件
参考文章: Freemarker自定义标签的简单分析 定义一个基本的文本框:传入参数为:resourceName idName resourceVal="" idVal=" ...
- 【zz】MIT牛人解说数学体系
作者:林达华 一.为什么要深入数学的世界 作为计算机的学生,我(原作者)没有任何企图要成为一个数学家.我学习数学的目 的,是要想爬上巨人的肩膀,希望站在更高的高度,能把我自己研究的东西看得更深广一些. ...
- 读取 java.nio.ByteBuffer 中的字符串(String) 写入方式flash.utils.ByteArray.writeUTF
通过研究ByteArray的写入格式以及方法说明,可以发现writeUTF是先使用2位写入字符串的长度,然后在其后写入字符串编码. flash.utils.ByteArray.writeUTF(val ...
- vc++>>Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enable
用VC来连接远程MYSQL时,出现如标题一样的错误,网上搜索了此错误产生的原因,最后自己找到了解决办法. 此错误产生的原因: 异常原因在于服务器端的密码管理协议陈旧,使用的是旧有的用户密码格式存储:但 ...
- 考虑virtual函数以外的选择
在C++中,有四种选择可以替代virtual函数的功能: 1.non-virtual interface(NVI)手法,这是一种template method模式.它以public non-virtu ...
- 通过创建临时表合并hive小文件
#!/bin/bash #set -x DB=$1 #获取hive表定义 ret=$(hive -e "use ${DB};show tables;"|grep -v _es|gr ...