Matlab信号处理:短时傅里叶变换

短时傅里叶变换(简称STFT)是傅里叶变换在时频域的扩展,它是为分析频域随时间变化的非平稳信号。本文模拟一个啁啾信号(一个线性调频的信号),借助matlab的短时傅里叶变换函数stft,分析其时频特性并绘制时频图,同时复现了matlab的stft函数的计算过程,供大家参考。

1.具体案例

啁啾信号一般是指调频信号,即随着时间的变化,信号的主频在不断发生变化(或增加、或减少)。当这种信号当做音频输出时,听起来会像鸟的唧唧声,所以叫啁啾。

利用matlab的chirp函数生成了一个1s内从100Hz到5000Hz的线性调频信号(啁啾信号),采样频率为24000Hz,具体如下:

从啁啾信号的局部细节图能发现,随着时间的增长,信号波形越来越密集,即信号的频率逐渐增大。在啁啾信号频谱中,低频占据信号的主频,无法发现信号频率的时变特征。

采用stft函数,设置矩形窗,窗长256,滑动步长设置为128,FFT分析的信号长度与窗长一致,均为256,设置stft函数的FrequencyRange为onesided,即仅分析信号的傅里叶变换的单边频谱,获得的短时傅里叶变换结果见下图。

上图为短时傅里叶变换的不同画图方式,分别使用mesh函数和imagesc函数。从上图中能发现,啁啾信号的频率从100Hz到5000Hz线性增长,这表明短时傅里叶变换能较好地分析该啁啾信号,对比FFT的结果,体现短时傅里叶变换在信号时频分析方面的优势。

stft函数的计算流程如下,它利用窗函数,将原始信号划分为了若干个子信号,然后分别采用傅里叶变换,获得其对应的频谱,最后将这些频谱按照不同的时间先后顺序进行拼接,绘制时频图。

在上述原理基础上,手动复现stft的计算过程,获得的时频图如下:

该图与stft获得的时频图是一致的,计算二者的平均偏差结果。从定量结果来看,复现过程结果与函数计算结果一致,验证了复现过程的正确性。 

2.具体代码

输入:信号y矩阵,行X列=单个信号的采样索引X信号数,比如信号的大小为8192X12,表示一个有12个信号的数据矩阵,每个信号长度为8192。如果仅有一个信号,则y应该是一个列向量,同时y的行数尽量为偶数,奇数的话会引起程序索引的警告。

输出:freq表示幅值谱的横轴,向量形式;P1表示幅值谱的纵轴,矩阵形式,单个信号的采样索引X信号数;Theta表示相位谱的纵轴,矩阵形式,单个信号的采样索引X信号数。

主函数main.m代码:

%% 信号处理——短时傅里叶变换

clc
clear all
close all

% 定义时间向量和啁啾信号参数
fs = 24000; % 采样率
T = 1/fs:1/fs:1; % 1秒长的时间向量
f0 = 100; % 起始频率100Hz
f1 = 5000; % 结束频率5000Hz

% 生成啁啾信号
y = chirp(T, f0, 1, f1);

% 播放啁啾信号
sound(y, fs);

filename = 'chirpSignal.mp3';
% 使用audiowrite函数保存为MP3格式
audiowrite(filename, y, fs, 'Quality', 95);

%
[freq1,P1,~]=frequ_am_phase(y',fs);
figure;
subplot(311);plot(T,y,'b-');xlabel('Time/s');ylabel('Amplitude/g');axis tight;
title("啁啾信号的时域波形")
subplot(312);plot(T(1:5000),y(1:5000),'b-');xlabel('Time/s');ylabel('Amplitude/g');axis tight;
title("时域波形的局部细节")
subplot(313);plot(freq1,P1,'b-');xlabel('Frequency/Hz');ylabel('Amplitude/g');
title("啁啾信号的频域波形")


[s,f,t] = stft(y,fs,Window=rectwin(256),OverlapLength=128,FFTLength=256,FrequencyRange="onesided");


figure
mesh(t,f,abs(s));colorbar;
xlabel('Time/s');ylabel('Frequency/Hz');zlabel('Amplitude/g');axis tight;
title("matlab的stft函数获得时频图")

figure
imagesc(t,f,abs(s));colorbar;
set(gca, 'YDir', 'normal');
xlabel('Time/s');ylabel('Frequency/Hz');axis tight;
title("matlab的stft函数获得时频图")

%%  复现短时傅里叶变换结果
rect_win=256;  %矩形窗口的长度
FFT_Length=256;  %FFT分析的长度  
overlap_len=128; %分割信号重叠的长度
seg_counts=floor((length(y)-overlap_len)/(rect_win-overlap_len));
stft_abs=(abs(s));
for i=1:seg_counts
    index=(i-1)*(rect_win-overlap_len)+1:(i-1)*(rect_win-overlap_len)+rect_win;
    sub_y=y(index);
    %复现过程
    Y=fft(sub_y,FFT_Length);          % FFT 快速傅里叶变换
    freq=(0:FFT_Length/2)*fs/FFT_Length;   % 设置频率刻度  横轴Hz
    P2 = abs(Y);
    P1 = P2(1:FFT_Length/2+1)';
    P1(:,3)=stft_abs(:,i);
    y_matrix__man(:,i)=P1(:,1);
end

figure;
imagesc(t,freq,y_matrix__man);colorbar;
set(gca, 'YDir', 'normal');
xlabel('Time/s');ylabel('Frequency/Hz');axis tight;
title("手动计算绘制的短时傅里叶变换时频图")

fprintf('matlab的stft函数获得时频图与手写复现之间的差为%f \n',sum(stft_abs-y_matrix__man,'all'));

幅值谱和相位谱计算函数frequ_am_phase.m代码:

function [freq,P1,Theta]=frequ_am_phase(y,fs,tol)

%% 绘制信号频域的幅值谱和相位谱
%% 参数解释: 
%     y: 表示输入信号,它可以为一个矩阵,行X列,具体为单个信号的采样索引X信号数
%        比如y的大小为8192X12,表示一个有12个信号的数据矩阵,每个信号长度为8192
%        注意,如果仅有一个信号,则y应该是一个列向量
%        同时,y的行数尽量为偶数,奇数的话会引起程序索引的警告
%     fs:表示采样频率
%     tol:相位阈值参数
%     freq:表示幅值谱的横轴
%     P1:表示幅值谱的纵轴
%     Theta:表示相位谱的纵轴

if nargin==2
    tol=1e-6;  %计算误差的默认阈值
end

L=size(y,1);         % 信号长度
% Y=fft(y,2^nextpow2(L));          % FFT 快速傅里叶变换
Y=fft(y,L);          % FFT 快速傅里叶变换
freq=(0:L/2)*fs/L;   % 设置频率刻度  横轴Hz
%幅值谱
P2 = abs(Y/L);
P1 = P2(1:L/2+1,:);
P1(2:end-1,:) = 2*P1(2:end-1,:);  %纵轴 幅值

%相位谱
P2(2:end-1,:)=2*P2(2:end-1,:);
for i=1:size(Y,2)
    Y(P2(:,i)<tol,i) = 0;
    theta(:,i) = angle(Y(:,i))/pi;
end
Theta=theta(1:L/2+1,:);
end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/918893.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux网络:基于文件的网络架构

Linux网络&#xff1a;基于文件的网络架构 网络架构TCP全连接队列 网络架构 在Linux中提供了多种系统调用&#xff0c;完成网络操作。比如TCP连接的建立&#xff0c;各种报文的收发等等。但是所有的Linux网络操作&#xff0c;都源于系统调用socket&#xff0c; 在Linux的man手…

【SpringBoot】23 文件预览(kkFileView)

Gitee仓库 https://gitee.com/Lin_DH/system 介绍 文件预览功能是指在不打开或编辑文件的情况下&#xff0c;通过某种方式查看文件的内容、格式或者部分内容的功能。该功能通常用于文件管理系统、办公工具、在线教育平台、企业协作平台、电子邮件客户端等领域&#xff0c;能…

Android笔记(三十七):封装一个RecyclerView Item曝光工具——用于埋点上报

背景 项目中首页列表页需要统计每个item的曝光情况&#xff0c;给产品运营提供数据报表分析用户行为&#xff0c;于是封装了一个通用的列表Item曝光工具&#xff0c;方便曝光埋点上报 源码分析 核心就是监听RecyclerView的滚动&#xff0c;在滚动状态为SCROLL_STATE_IDLE的时…

关于Java合并多个Excel中的数据【该数据不是常规列表】,并入库保存的方案

1. 背景 最近在使用RPA&#xff08;机器人流程自动化&#xff09;做数据采集的时候。发现那个RPA采集&#xff0c;一次只能采集相同格式的数据&#xff0c;然后入到Excel或者库中。由于院内系统的业务限制&#xff0c;导致采集的数据是多个Excel&#xff0c;并且我们这边的需求…

Robot | 用 RDK 做一个小型机器人(更新中)

目录 前言架构图开发过程摄像头模型转换准备校准数据使用 hb_mapper makertbin 工具转换模型 底版开发 结语 前言 最近想开发一个小型机器人&#xff0c;碰巧看到了 RDK x5 发布了&#xff0c;参数对于我来说非常合适&#xff0c;就买了一块回来玩。 外设也是非常丰富&#xf…

NPOI 实现Excel模板导出

记录一下使用NPOI实现定制的Excel导出模板&#xff0c;已下实现需求及主要逻辑 所需Json数据 对应参数 List<PurQuoteExportDataCrInput> listData [{"ItemName": "电缆VV3*162*10","Spec": "电缆VV3*162*10","Uom":…

TCP/IP--Socket套接字--JAVA

目录 一、概念 二、分类 1.流套接字 2.数据报套接字 三、UDP数据报套接字编程 1.API介绍 2.基于UDP实现简单回显服务器 一、概念 Socket套接字&#xff0c;是由系统提供⽤于⽹络通信的技术&#xff0c;是基于TCP/IP协议的⽹络通信的基本操作单元。 基于Socket套接字的⽹络…

从大数据到大模型:现代应用的数据范式

作者介绍&#xff1a;沈炼&#xff0c;蚂蚁数据部数据库内核负责人。2014年入职蚂蚁&#xff0c;承担蚂蚁集团的数据库架构职责&#xff0c;先后负责了核心链路上OceanBase&#xff0c;OceanBase高可用体系建设、NoSQL数据库产品建设。沈炼对互联网金融、数据库内核、数据库高可…

2024雪浪小镇·京东科技上海产业对接会

11月15日下午对接会由京东科技主办在上海南翔温德姆酒店顺利召开,来自上海本地的AIoT及工业互联网优秀企业、投资人、京东生态合作伙伴齐聚一堂,共同探讨技术赋能和产业协同之路,加速企业发展和促进产业升级。 无锡经开区是无锡最年轻、最具创新动力、产业张力、宜居魅力和开放…

Vue3踩坑记录

目录 一、定义常变量 1.1、ref和reactive到底用谁&#xff1f; 二、双向绑定 2.1、直接改变表格该行数据 2.1、在弹窗改变表格该行数据 一、定义常变量 1.1、ref和reactive到底用谁&#xff1f; 已知&#xff1a;使用ref定义基础类型数据&#xff1b;使用reactive定义复…

ROM修改进阶教程------安卓14去除修改系统应用后导致的卡logo验证步骤 适用安卓13 14 安卓15可借鉴参考

上期的博文解析了安卓14 安卓15去除系统应用签名验证的步骤解析。我们要明白。修改系统应用后有那些验证。其中签名验证 去卡logo验证 与可降级安装应用验证等等的区别。有些要相互结合使用。今天的博文将对修改系统应用后卡logo验证做个步骤解析。 通过博文了解💝💝�…

2024.11.18晚Linux复习课笔记

第一章 cat -n显示行号 -b不显示空行号 pwd 打印当前的工作目录 cd ls 打印当前工作的所有文件 -a -A -l:显示当前文件的详细信息 -r:递归显示 passwd:修改密码 ip a 查看ip地址 poweroff shutdown -h 关机 reboot shutdown -r 第二章 man --help …

数据可视化如何帮助企业提升数据洞察力?

数据驱动时代&#xff0c;企业每天都在面对数据的洪流。一方面&#xff0c;拥有海量数据意味着蕴藏着无尽的机会&#xff1b;另一方面&#xff0c;如果无法提炼这些数据背后的价值&#xff0c;它们只会成为业务发展的负担。例如&#xff0c;许多企业手握丰富的销售数据&#xf…

报错java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not ...解决方法

在运行项目时出现java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field com.sun.tools.javac.tree.JCTree qualidzz这样的报错 解决方法 1.第一步&#xff1a;在pom文件中将lombok的版本改成最新的 此时1.18.34是新…

MyBatisPlus(Spring Boot版)的基本使用

1. 初始化项目 1.1. 配置application.yml spring:# 配置数据源信息datasource:# 配置数据源类型type: com.zaxxer.hikari.HikariDataSource# 配置连接数据库信息driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis_plus?characterEncodi…

【MongoDB】MongoDB的集群,部署架构,OptLog,集群优化等详解

文章目录 一、引入复制集的原因二、复制集成员&#xff08;一&#xff09;基本成员&#xff08;二&#xff09;主节点&#xff08;Primary&#xff09;细化成员 三、复制集常见部署架构&#xff08;一&#xff09;基础三节点&#xff08;二&#xff09;跨数据中心 四、复制集保…

Golang | Leetcode Golang题解之第564题寻找最近的回文数

题目&#xff1a; 题解&#xff1a; func nearestPalindromic(n string) string {m : len(n)candidates : []int{int(math.Pow10(m-1)) - 1, int(math.Pow10(m)) 1}selfPrefix, _ : strconv.Atoi(n[:(m1)/2])for _, x : range []int{selfPrefix - 1, selfPrefix, selfPrefix …

git根据远程分支创建本地新分支

比如我当前本地仓库有4个 remote 仓库&#xff0c;我希望根据其中的一个 <remote>/<branch> 创建本地分支&#xff1a; 先使用 github fetch <remote> 拉取 <remote> 的分支信息&#xff0c;然后在 git checkout -b 创建新分支时使用 -t <remote>…

r-and-r——提高长文本质量保证任务的准确性重新提示和上下文搜索的新方法可减轻大规模语言模型中的迷失在中间现象

概述 随着大规模语言模型的兴起&#xff0c;自然语言处理领域取得了重大发展。这些创新的模型允许用户通过输入简单的 "提示 "文本来执行各种任务。然而&#xff0c;众所周知&#xff0c;在问题解答&#xff08;QA&#xff09;任务中&#xff0c;用户在处理长文本时…