Matlab_spectrogram_短时傅里叶分析_实现与讨论
在语音与音乐处理过程中,常用到短时傅里叶变换(Short Time Fourier Transformation, STFT)。在一些学习路径中,STFT也是学习小波之前的预备知识。本文简单实现了 Matlab 中 Spectrogram 函数,在没有小波知识支撑下,讨论了参数的选择,以及分辨率相关的问题。
参考博客:
来源:CSDN 作者:风翼冰舟
来源:知乎 作者:咚懂咚懂咚
来源:CSDN 作者:水可马二 来源:CSDN 作者:沈子恒 来源:CSDN 作者:gent__chen
短时傅里叶变换简介
自己写一下对STFT的认识,不一定对。
短时傅里叶变换,其实还是傅里叶变换,只不过把一段长信号按信号长度(nsc)、重叠点数(nov)重新采样。原始信号的每一个数据点,都有一个电压值对应,即只有一个直流自由度。重新采样之后,数据点个数变少,每一个数据点由(nsc)个点组成,即得到了其他频率的自由度。但是这个点的频谱是有上下限的——上限受采样频率界定,下限受数据时长界定,和 FFT 一样。

这么处理数据是有缘由的。语音与音乐信号中,信号频率常常变化,而且频率成分丰富,导致简单的傅里叶变换不能很好的描述信号。然而我们人耳处理声音的能力很强,可以对很短的一段声音进行精确的频率分析。所以在语音识别以及语音信号预处理过程中,STFT 是 FFT 的仿生改良版(个人理解)。当然,在其他声学相关方向中,STFT也是蛮有用的。没查过相关文献不敢乱说,模态分析、瞬态特性等应该能用上(个人猜测)。

上图是我用本文的例程实现的语音“XX大学”的 STFT 结果。语音是自己拿录音笔录的,时间域上没有做截断,但由于自己声线太低,频率域截到 2000 Hz。可以看到,我在开始之后等了一段时间才开始说话,后面有几段“嘎嘣脆”的噪声。还可以看到,我的元音发音还是很清晰的,但声线真心低。理论上能从这张图还原出原始信号,不在话下。
Spectrogram 函数函数实现
简单编了一个 STFT 函数如下:
function [ S , W , T ] = mf_spectrogram...
( signal , nsc , nov , fs )
%MF_SPECTROGRAM Short-time Fourier transform realization
% Input
% signal - Signal vector
% nsc - Abb. of Number SeCtion
% nov - Abb. of Number OverLap
% fs - Abb. of Frequency of Sample
% Output
% S - A matrix that each colum is a FFT for time of nsc
% W - A vector labeling frequency
% T - A vector labeling time % Signal Preprocessing
h = hamming(nsc, 'periodic'); % Hamming weight function
L = length(signal); % Length of Signal
nst = nsc-nov; % Number of STep per colum
ncl = fix( (L-nsc)/nst ) + 1; % Number of CoLum
nff = 2^nextpow2(nsc); % Number of Fast Fourier Transformation
Ps = zeros(nsc,ncl);
for n = 1:ncl % Ps means Processed Signal
Ps(:,n) = signal( (n-1)*nst+1 : (n-1)*nst+nsc ).*h';
end % Ps is a matrix % Short-time Fourier transform
STFT0 = fft(Ps,nff); % Turn into DFT in dB
STFT1 = abs(STFT0/nff);
STFT2 = STFT1(1:nff/2+1,:); % Symmetric results of FFT
STFT2(2:end-1,:) = 2*STFT2(2:end-1,:); % Add the value of the other half
STFT3 = 20*log10(STFT2); % Turn sound pressure into dB level % Axis Generating
fax = fs*(0:(nff/2))/nff; % Frequency axis setting
tax = ( .5*nsc : nst : nst*(ncl-1)+.5*nsc ) / fs; % Time axis generating
[ffax,ttax] = meshgrid(tax,fax); % Generating grid of figure % Output
W = ffax;
T = ttax;
S = STFT3;
end
为了节省代码量,我搞了一个绘图函数:
function [ ] = my_pcolor( f , t , s )
%MY_PCOLOR 绘图函数
% Input
% f - 频率轴矩阵
% t - 时间轴矩阵
% s - 幅度轴矩阵
gca = pcolor(f,t,s); % 绘制伪彩色图
set(gca, 'LineStyle','none'); % 取消网格,避免一片黑
handl = colorbar; % 彩图坐标尺
set(handl, 'FontName', 'Times New Roman', 'FontSize', 14)
ylabel(handl, 'Magnitude, dB') % 坐标尺名称
end
下面是实现的例程:
clc
clear
close all % 基本参数
fa = [ 50 800 ]; % 扫描频率上下限
fs = 6400; % 采样频率 % 分辨率相关设定参数
te = 1; % [s] 扫频时间长度
fre = 8; % [s] 频率分辨率
tre = 0.002; % [Hz] 时间分辨率 % Chirp 信号生成
t = 0:1/fs:te; % [s] 时间序列
sc = chirp(t,fa(1),te,fa(2)); % 信号生成 % 分辨率相关输入参数
nsc = floor(fs/fre);
% nov = floor(nsc-(fs*tre));
nov = floor(nsc*0.9);
nff = max(256,2^nextpow2(nsc)); % 计算与绘制结果
subplot(1,3,1) % 绘制自编函数结果
[S,W,T] = mf_spectrogram(sc,nsc,nov,fs);
my_pcolor(W,T,S)
caxis([-130.86,-13.667]);
title('自编函数');
xlabel('时间 second');
ylabel('频率 Hz');
subplot(1,3,2) % 绘制 Matlab 函数结果
s = spectrogram(sc,hamming(nsc),nov,nff,fs,'yaxis');
% Turn into DFT in dB
s1 = abs(s/nff);
s2 = s1(1:nff/2+1,:); % Symmetric results of FFT
s2(2:end-1,:) = 2*s2(2:end-1,:); % Add the value of the other half
s3 = 20*log10(s2); % Turn sound pressure into dB level
my_pcolor(W,T,s3 )
caxis([-130.86,-13.667]);
title('Matlab 自带函数');
xlabel('时间 second');
ylabel('频率 Hz');
subplot(1,3,3) % 两者误差
my_pcolor(W,T,20*log10(abs(10.^(s3/20)-10.^(S/20))))
caxis([-180,-13.667]);
title('error');
ylabel('频率 Hz');
xlabel('时间 second');
suptitle('Spectrogram 实现与比较');
跑的结果我就不贴了,Demo确定是没问题的。网上也有很多相关话题的,例程都比较简单,但我非常善于把问题复杂化:te(扫描长度)、fre(频率下限)、tre(时域分辨率)、nsc(单段数据长度)、nov(重叠数据点数)、nff(FFT点数) 等参数都是为了看设定什么样的参数能够使得 STFT 结果最优。我只是科普性地了解过小波,公式推导还没展开,所以在此只能“实验性”地讨论“尺度”相关的话题。
观察频率上限受到采样频率限制,频率下限受到nsc限制。nsc越大,单段数据时间跨度越长,在该段时间内频率如果变化快,会导致频域分辨率降低(te = 1 ; fre = 2 ; nov = 99%)。另一方面,为了保持 FFT 频率分辨率,设置 nff 不低于256,这使得当nsc较小时,单段信号中,低频成分可能也就几个周期就结束了,等同于时域加了一个矩形窗,最终造成了频域产生旁瓣。一句话,单段信号过短,低频效果不好;单段信号过长,捕捉不到频率快速变化的信号。
数据长度、FFT 点数对结果的影响
实验性地比较了一下不同数据长度、FFT点数对结果的影响:
% This script is demonstrating zero effects
% Basic parameter
fs = 100; % 采样频率
Ndata = [ 30 60 500 ]; % 数据长度
Nff = [ 32 64 512 ]; % FFT的数据长度 % Signal Generating
t1 = ( 0:Ndata(1)-1 )/fs;
t2 = ( 0:Ndata(2)-1 )/fs;
t3 = ( 0:Ndata(3)-1 )/fs;
x1 = 0.5*sin(2*pi*15*t1)+2*sin(2*pi*40*t1); % 时间域信号
x2 = 0.5*sin(2*pi*15*t2)+2*sin(2*pi*40*t2); % 时间域信号
x3 = 0.5*sin(2*pi*15*t3)+2*sin(2*pi*40*t3); % 时间域信号 % FFT and Plot
for n = 1:3 % Ndata sweep
xname = ['x',num2str(n)];
x = eval(xname);
for m = 1:3 % Nff sweep
name = ['y',num2str(n),num2str(m)];
eval([name '=fft(x,Nff(m));'])
y = eval(name);
Y = abs(y);
f = (0:Nff(m)-1)*fs/Nff(m); % 真实频率 subplot(3,3,(n-1)*3+m)
plot(f(1:Nff(m)/2),[Y(1),Y(2:Nff(m)/2)*2]/min(Ndata(n),Nff(m)));
xlabel('频率/Hz');
ylabel('振幅');
ylim([0,2]);
title(['Ndata=',num2str(Ndata(n)),' Nfft=',num2str(Nff(m))]);
grid on;
end
end
为了节省代码,同时运行结束后保留计算数据,使用了 eval 函数对变量和字符串进行相互转化。绘制了9个图如下:

横向是提高 FFT 点数的比较,纵向是提高数据长度的比较。可以看到,提高 FFT 点数会使得频域分辨率提高;增长数据长度,能够减少旁瓣的生成。
END
Matlab_spectrogram_短时傅里叶分析_实现与讨论的更多相关文章
- spectrogram函数做短时傅里叶分析
整理自:http://blog.sina.com.cn/s/blog_6163bdeb0102dwfw.html 今天偶人发现原来matlab自带了短时傅里叶变换的分析函数,老版本的matlab是sp ...
- (4)_结果与讨论Result and Discussion【论文写作】
- Atitit 语音识别的技术原理
Atitit 语音识别的技术原理 1.1. 语音识别技术,也被称为自动语音识别Automatic Speech Recognition,(ASR),2 1.2. 模型目前,主流的大词汇量语音识别系统多 ...
- 数据结构--树(遍历,红黑,B树)
平时接触树还比较少,写一篇博文来积累一下树的相关知识. 很早之前在数据结构里面学的树的遍历. 前序遍历:根节点->左子树->右子树 中序遍历:左子树->根节点->右子树 后序遍 ...
- 手写一个更好用的performSelector/msgSend(详细修改版)
这其实是一个NSInvocation练习作业 GitHub源码 vk_msgSend 引子 工作中难免会遇到一些场景,开发的时候不想引入整个头文件,但是又想调用一些方法 动态创建,动态调用看起来比较酷 ...
- Atitit.木马 病毒 免杀 技术 360免杀 杀毒软件免杀 原理与原则 attilax 总结
Atitit.木马 病毒 免杀 技术 360免杀 杀毒软件免杀 原理与原则 attilax 总结 1. ,免杀技术的用途2 1.1. 病毒木马的编写2 1.2. 软件保护所用的加密产品(比如壳)中,有 ...
- C语言ASM汇编内嵌语法【转】
转自:http://www.cnblogs.com/latifrons/archive/2009/09/17/1568198.html GCC 支持在C/C++代码中嵌入汇编代码,这些汇编代码被称作G ...
- 【DWT笔记】傅里叶变换与小波变换
[DWT笔记]傅里叶变换与小波变换 一.前言 我们经常接触到的信号,正弦信号,余弦信号,甚至是复杂的心电图.脑电图.地震波信号都是时域上的信号,我们也成为原始信号,但是通常情况下,我们在原始信号中得到 ...
- 【codeforces 553E】 Kyoya and Train
http://codeforces.com/problemset/problem/553/E (题目链接) 艹尼玛,CF还卡劳资常数w(゚Д゚)w!!系统complex被卡TLE了T_T,劳资写了一天 ...
随机推荐
- pyhton课堂随笔-基本画图
%matplotlib inline import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np impor ...
- c#+Unity3D
Windows系统unity3d中的快捷键 自己整理常用; f2 改名 shift + 三维轴中间:45度 点击左键时 F:聚焦 V顶点贴合 ws拉近拉远 ad左右 qe 上下 长按右键 自由调换视角 ...
- Windows编译安装使用cephfs客户端
本文介绍如何将cephfs映射到windows的一个盘上,以磁盘映射的方式访问cephfs. 1.下载必要安装包 tdm-gcc:(安装时选32位)https://sourceforge.net/pr ...
- Cognos集成至portal平台查看报表报错RSV-BBP-0022
1. 问题描述 绝对密切性请求“asynchWait_Request”失败,所请求的会话不存在. 2. 问题分析 Session会话传递失败. 3. 解决方案 将cognos所在服务器地址IP添加进I ...
- 在Linux和Windows之间的远程控制的实现
主要开发工作用Linux,邮件和文档等主要在Windows,两者之间经常需要传输数据,两台主机都必须同时运行着. 但是,通常来说,它们需要同时准备两套显示器.鼠标和键盘,既占地方又不够方便. 远程控制 ...
- unistd.h
unistd.h是unix std的意思,是POSIX标准定义的unix类系统定义符号常量的头文件, 包含了许多UNIX系统服务的函数原型 unistd.h在unix中类似于window中的windo ...
- ES6笔记(二)
一.字符串的扩展1. 用于从码点返回到对应字符. String.fromCodePoint(xx)2. for...of可以遍历字符串3. includes():返回布尔值,表示是否找到了参数字符串. ...
- 微信内嵌浏览器打开手机浏览器下载APP(APK)的方法
想必大家会经常碰到网页链接在微信内无法打开和微信内无法打开app下载页的情况.通常这种情况微信会给个提示 “已停止访问该网址” ,那么导致这个情况的因素有哪些呢,主要有以下四点 1.网页链接被举报次数 ...
- python练习小文章-文本爬虫
一入“程”门深四海...... 有学习就得有练习,我来练一个文本爬虫,代码直接写到下面,抓取的是网页图片,简单好学,适合新手练习. 话不多说直接上干货! 1. 目标网址:https://www.jik ...
- BPM与OA区别
核心差异: OA解决的是流程有无问题 BPM解决的是流程更好更优的问题 主要差异如下: 1.BPM有更好的广度跟深度 这里的广度是指应用场景的广度. BPM一般都会以端到端的方式衔接企业运营过程的上下 ...