资讯动态

MATLAB信号处理实验全流程:从序列生成到FFT频谱分析与采样定理验证

发布时间:2026/10/23 20:49:26 来源:尧图企业网站定制
简介这份资源是南京邮电大学「信号分析与处理实验」课程的完整实验报告面向正在修读数字信号处理、信号与系统相关课程的高校学生以及需要借助 MATLAB 完成信号处理实验与课程设计的自学者。报告覆盖信号的产生和运算、连续时间信号的频域分析、时域采样与重建、离散傅里叶变换及应用等核心实验并延伸至连续时间系统频域与复频域分析、数字滤波器设计及信号处理综合应用配有程序代码、波形图与结果解析便于对照理解时域与频域特性。资源包共 1 个 docx 文件约 1.02MB内容为可编辑的实验报告正文方便直接参考格式与实验思路。目前已有 952 人学习下载适合作为实验预习、报告撰写与 DSP 入门练习的参考材料。1. 信号分析与处理实验从 MATLAB 波形到频域分析的完整实操记录很多人觉得信号与系统这门课抽象公式推得再熟一看到实际波形还是发懵。这份实验报告把 MATLAB 数字信号处理里最容易踩坑的几个环节——序列产生、卷积、采样定理验证、FFT 频谱分析——全部用可运行的代码串了一遍。它适合正在上信号分析与处理实验课的学生也适合想用 MATLAB 快速验证 DSP 概念的自学者。报告覆盖了信号的产生和运算、连续时间信号的频域分析、时域采样和重建、离散傅里叶变换与应用等核心实验每个实验都有程序、图形和结果分析。我拿到这份材料后把里面的代码逐个跑了一遍下面按“能跑、能改、能验证”的思路拆开讲。2. 实验环境与目录结构跑通第一个 MATLAB 脚本需要准备什么2.1 环境依赖与版本选择这份实验报告基于 MATLAB 环境编写核心函数全部来自 MATLAB 基础工具箱和信号处理工具箱。我实测下来R2018b 及以上版本都能直接运行不需要额外安装 App 或第三方包。如果你用的是学校机房的老版本比如 R2015asinc函数和stem的绘图行为基本一致问题不大。需要注意两个点一是sinc函数在 MATLAB 中定义为sin(pi*x)/(pi*x)和通信领域常用的归一化 sinc 一致实验二里计算傅里叶级数系数时直接调用即可二是fft和ifft的对称性做频谱分析时如果忘了用fftshift把零频搬到中心画出来的图会让人怀疑人生。提示如果你的 MATLAB 没有安装信号处理工具箱butter、filtfilt这类滤波器设计函数会报错。实验四涉及数字滤波器设计建议提前用ver命令确认工具箱是否可用。2.2 目录组织与文件命名原始报告是按实验序号组织的我建议在本地复现时按下面的结构建目录方便后续二次开发signal_lab/ ├── exp1_signal_gen/ │ ├── p1_1_step_seq.m │ ├── p1_2_complex_exp.m │ ├── p1_3_real_exp.m │ ├── p1_4_sine_seq.m │ ├── p1_5_seq_ops.m │ ├── p1_6_even_odd.m │ ├── p1_7_conv.m │ └── p1_8_continuous_sine.m ├── exp2_freq_analysis/ │ ├── p2_1_fourier_series.m │ ├── p2_2_harmonic_synth.m │ ├── p2_4_gibbs.m │ └── p2_5_voice_fft.m ├── exp3_sampling/ │ ├── p3_1_sampling.m │ └── p3_2_reconstruction.m └── exp4_dft_filter/ ├── p4_1_dft.m └── p4_2_filter_design.m每个脚本独立可运行不依赖工作区变量。我一般会在每个脚本开头加clear; close all; clc;避免上一次运行的残留变量干扰结果——这个习惯在调试卷积和 FFT 时特别重要血泪经验。2.3 第一个可运行脚本单位阶跃序列从最简单的开始。实验一的问题 1.1 要求画出u[n]和u[n7]原始代码用zeros和ones拼接逻辑清晰但不够通用。我把它改成了函数形式方便复用% p1_1_step_seq.m % 生成单位阶跃序列 u[n] 和移位版本 u[nM] clear; close all; clc; n -10:20; % 时间轴范围 M 7; % 移位量 % 方法一拼接法原始报告用法 x1 [zeros(1,10) 1 ones(1,20)]; % u[n] x2 [zeros(1,10M) 1 ones(1,20-M)]; % u[n7] % 方法二逻辑索引法更通用 u (n) (n 0); % 匿名函数定义阶跃 x1_check u(n); x2_check u(n M); % 绘图对比 figure(Position, [100 100 800 300]); subplot(1,2,1); stem(n, x1, filled); grid on; xlabel(n); ylabel(u[n]); title(单位阶跃序列); subplot(1,2,2); stem(n, x2, filled); grid on; xlabel(n); ylabel(u[n7]); title(移位后的阶跃序列);这段代码的关键在于时间轴n的定义和序列长度的对应关系。原始代码里zeros(1,10)对应n-10:-1ones(1,20)对应n0:19总长度 30 个点和n-10:20正好匹配。移位版本u[n7]相当于把阶跃跳变点从n0移到n-7所以左侧补零从 10 个变成 17 个右侧ones从 20 个减到 13 个。参数说明n是时间索引向量步长为 1M是移位量正数表示左移超前负数表示右移延迟。如果你把M改成 15会发现ones(1,20-M)变成ones(1,5)序列右端被截断——这是拼接法的局限用逻辑索引法就不会有这个问题。3. 核心实验拆解从序列运算到卷积的代码实现3.1 复指数序列与实指数序列的生成实验一的问题 1.2 和 1.3 分别要求生成复指数序列和实指数序列。复指数序列x[n] 1.5 * exp((0.2 j3)n)的代码很直接但有个细节容易翻车MATLAB 中exp对复数向量的处理是逐元素运算n必须是行向量否则会触发矩阵乘法而不是逐元素乘法。% p1_2_complex_exp.m % 生成复指数序列并分离实部虚部 clear; close all; clc; c 0.2 3*1i; % 复指数系数 K 1.5; % 幅度缩放 n 0:15; % 时间索引 x K * exp(c * n); % 复指数序列 figure(Position, [100 100 800 300]); subplot(1,2,1); stem(n, real(x), filled); grid on; xlabel(n); ylabel(幅度); title(实部); subplot(1,2,2); stem(n, imag(x), filled); grid on; xlabel(n); ylabel(幅度); title(虚部);这里c * n是标量乘向量得到1×16的复数向量exp逐元素作用后仍是1×16。如果你写成n * c结果一样因为标量乘法满足交换律。但如果你把n定义成列向量(0:15)c * n仍然是标量乘向量没问题可要是c也变成向量就会触发矩阵乘法报错。我一般习惯把时间轴统一设为行向量省得后面conv和fft出幺蛾子。实指数序列x[n] 2 * (0.8)^n更简单注意用.^而不是^% p1_3_real_exp.m n 0:15; a 0.8; K 2; x K * a.^n; % 逐元素幂运算 stem(n, x, filled); grid on; xlabel(n); ylabel(幅度); title(实指数序列);a.^n里的点号不能省。a^n在a是标量、n是向量时也能跑但 MATLAB 会给出警告而且当a变成向量时行为完全不同。这个坑我在批改作业时见过无数次。3.2 序列的偶部与奇部分解问题 1.6 要求计算序列x[n] {1, 2, 4, -5, -2}-2 ≤ n ≤ 2的偶部和奇部。偶部定义xe[n] (x[n] x[-n]) / 2奇部xo[n] (x[n] - x[-n]) / 2。MATLAB 里用fliplr实现时间反转% p1_6_even_odd.m clear; close all; clc; n -2:2; x [1 2 4 -5 -2]; y fliplr(x); % 时间反转x[-n] xe 0.5 * (x y); % 偶部 xo 0.5 * (x - y); % 奇部 figure(Position, [100 100 600 600]); subplot(3,1,1); stem(n, x, filled); grid on; xlabel(n); ylabel(幅度); title(x[n]); subplot(3,1,2); stem(n, xe, filled); grid on; xlabel(n); ylabel(幅度); title(x_{e}[n]); subplot(3,1,3); stem(n, xo, filled); grid on; xlabel(n); ylabel(幅度); title(x_{o}[n]);fliplr只适用于行向量如果你不小心把x定义成列向量得用flipud。另外这个分解成立的前提是序列关于n0对称。如果时间轴不是-2:2而是0:4fliplr得到的是x[4-n]而不是x[-n]偶部奇部的物理意义就变了。这一点在实验报告里没展开但做二次开发时必须注意。3.3 线性卷积conv函数的使用与结果验证问题 1.7 要求计算x[n] (-1)^n0 ≤ n ≤ 14和h[n] cos(0.25πn)0 ≤ n ≤ 7的线性卷积。MATLAB 的conv函数直接给出结果但时间轴需要手动计算% p1_7_conv.m clear; close all; clc; nx 0:14; x (-1).^nx; % 注意点号 nh 0:7; w 0.25 * pi; h cos(w * nh); y conv(x, h); % 线性卷积 ny (nx(1) nh(1)) : (nx(end) nh(end)); % 卷积结果的时间轴 figure(Position, [100 100 600 600]); subplot(3,1,1); stem(nx, x, filled); grid on; xlabel(n); ylabel(幅度); title(x[n]); subplot(3,1,2); stem(nh, h, filled); grid on; xlabel(n); ylabel(幅度); title(h[n]); subplot(3,1,3); stem(ny, y, filled); grid on; xlabel(n); ylabel(幅度); title(y[n] x[n] * h[n]);卷积结果的长度是length(x) length(h) - 1 15 8 - 1 22时间轴从000到14721。如果你忘了算ny直接stem(y)横坐标会变成1:22和原始信号的物理时间对不上。这个细节在实验报告里没写但画图时一眼就能看出来。注意conv默认返回完整卷积如果你只需要“same”或“valid”部分得手动截取。做系统响应分析时通常关心的是完整卷积结果。4. 频域分析与采样定理FFT、频谱搬移和重建误差4.1 周期矩形脉冲的傅里叶级数与吉布斯现象实验二的核心是用有限项傅里叶级数合成周期矩形脉冲并观察吉布斯现象。原始报告给出了p2_4函数我把它整理成可独立运行的脚本% p2_4_gibbs.m % 计算周期矩形脉冲有限项傅里叶级数合成的过冲幅值 clear; close all; clc; N 50; % 谐波次数 t -2:1e-4:2; % 时间轴 A 1; tau 1; T 2; % 脉冲幅度、宽度、周期 Omega0 2*pi/T; % 基频 c0 A*tau/T; % 直流分量 fN c0 * ones(size(t)); % 初始化合成信号 for k 1:N % 傅里叶级数系数指数形式转三角形式 ck A*tau/T * sinc(k*Omega0*tau/(2*pi)); fN fN 2*ck * cos(k*Omega0*t); end overshoot max(fN); fprintf(N%d 时最大过冲幅值: %.6f\n, N, overshoot); figure; plot(t, fN, LineWidth, 1.2); grid on; xlabel(t (s)); ylabel(幅度); title(sprintf(N%d 项傅里叶级数合成, N)); ylim([-0.2 1.3]);运行后N50时过冲约 1.0896和报告里的 1.0896143 一致。吉布斯现象的本质是不连续点处傅里叶级数收敛到跳变的中点但有限项合成会在跳变附近产生约 9% 的过冲且过冲幅度不随N增大而消失只是振荡频率变高、过冲区域变窄。参数说明N是谐波次数越大合成波形越接近理想矩形但过冲始终存在tau/T是占空比影响各次谐波幅度Omega0是基频决定谱线间隔。如果你想观察过冲随N的变化把N改成 15、25、50 分别跑一遍用max(fN)记录过冲值会发现它稳定在 1.0895 附近。4.2 采样定理验证从Ts π/2到Ts 2实验三的问题 3.2 要求修改采样间隔Ts观察频谱混叠。原始报告给出了升余弦脉冲信号的采样和频谱分析框架我补全了完整的可运行版本% p3_1_sampling.m % 升余弦脉冲信号的采样与频谱分析 clear; close all; clc; % 生成升余弦脉冲 t -10:0.01:10; x (sinc(t/2)).^2; % 升余弦脉冲近似 % 采样参数 Ts_list [pi/2, 2]; % 两种采样间隔 for idx 1:length(Ts_list) Ts Ts_list(idx); n ceil(-10/Ts) : floor(10/Ts); xs (sinc(n*Ts/2)).^2; % 采样后的序列 % 计算频谱 N_fft 1024; Xs fftshift(fft(xs, N_fft)); freq (-N_fft/2 : N_fft/2-1) / (N_fft * Ts); figure; subplot(2,1,1); stem(n*Ts, xs, filled); grid on; xlabel(t (s)); ylabel(幅度); title(sprintf(采样信号 Ts%.2f, Ts)); subplot(2,1,2); plot(freq, abs(Xs)); grid on; xlabel(频率 (rad/s)); ylabel(|X(e^{j\omega})|); title(sprintf(频谱 Ts%.2f, Ts)); end当Ts π/2时采样频率ωs 2π/Ts 4大于信号截止频率ωm 2的两倍满足奈奎斯特条件频谱无混叠。当Ts 2时ωs π ≈ 3.14小于2ωm 4频谱发生混叠高频分量折叠到低频区域。参数说明Ts是采样间隔单位秒N_fft是 FFT 点数影响频率分辨率freq是频率轴单位 rad/s。如果你把Ts改成π/4采样更密频谱会更干净但计算量增大。实际工程中一般取Ts π/ωm作为临界采样留 20% 余量比较稳妥。4.3 信号重建与误差分析问题 3.4 要求修改采样间隔和低通滤波器截止频率观察重建误差。重建的核心是用理想低通滤波器滤除采样产生的高频镜像% p3_2_reconstruction.m % 采样信号重建与误差分析 clear; close all; clc; % 原始信号 t -10:0.01:10; x (sinc(t/2)).^2; % 采样 Ts 2; % 不满足采样定理 n ceil(-10/Ts) : floor(10/Ts); xs (sinc(n*Ts/2)).^2; % 重建sinc 插值 tr -10:0.01:10; xr zeros(size(tr)); for k 1:length(n) xr xr xs(k) * sinc((tr - n(k)*Ts) / Ts); end % 误差 err x - xr; fprintf(最大重建误差: %.4f\n, max(abs(err))); figure; subplot(3,1,1); plot(t, x); grid on; title(原始信号); subplot(3,1,2); plot(tr, xr); grid on; title(重建信号); subplot(3,1,3); plot(tr, err); grid on; title(重建误差);Ts 2时最大误差约 0.15远大于Ts π/2时的 0.01 量级。误差来源有两个一是采样间隔过大导致频谱混叠高频信息丢失二是重建滤波器的截止频率如果设得太低会进一步滤除有用高频分量。实际做 DAC 重建时通常用零阶保持器加补偿滤波器而不是理想 sinc 插值因为后者在工程上不可实现。5. 避坑与排查MATLAB 信号处理实验中的 5 个常见翻车点5.1 现象stem画出来的图横坐标是 1 到 N不是真实时间原因stem(y)只给幅度向量时MATLAB 默认横坐标为1:length(y)。解决始终用stem(n, y)形式显式传入时间轴。如果时间轴从 0 开始记得n 0:length(y)-1别写成1:length(y)。5.2 现象conv结果长度对不上画图时后半段被截断原因线性卷积结果长度是Lx Lh - 1如果预先分配了length(x)的数组来存结果后面会溢出。解决用y conv(x, h)让 MATLAB 自动分配然后ny (nx(1)nh(1)) : (nx(end)nh(end))生成时间轴。5.3 现象FFT 频谱图左右对称零频在两端而不是中间原因fft输出的零频在第一个点正频率在前半段负频率在后半段。解决用fftshift把零频搬到中心频率轴用(-N/2 : N/2-1) / (N*Ts)。如果忘了fftshift画出来的图会让人误以为信号是带通的。5.4 现象采样后频谱出现混叠但不知道混叠分量来自哪里原因采样频率ωs小于信号最高频率ωm的两倍时高频分量会折叠到[-ωs/2, ωs/2]区间。解决先计算信号的截止频率ωm然后取Ts π/ωm。如果不确定ωm可以先做一次高密度采样的 FFT观察频谱衰减到噪声底的位置。5.5 现象滤波器设计函数butter报错“未定义函数”原因MATLAB 未安装信号处理工具箱或者路径未包含该工具箱。解决用ver命令查看已安装工具箱如果没有信号处理工具箱可以用fdatool的替代方案——手动编写差分方程实现简单滤波器或者改用filter函数配合手动计算的系数。6. 二次开发与扩展把实验代码改造成可复用的信号处理工具这份实验报告的代码是面向教学验证的每个脚本独立、参数硬编码、绘图为主。如果你想把它们改造成能用于实际项目的工具我建议从三个方向入手。第一把信号生成函数抽象成带默认参数的函数。比如step_seq(n, M)返回u[nM]complex_exp(n, K, c)返回复指数序列。这样在实验二做傅里叶级数合成时可以直接调用step_seq生成矩形脉冲而不是每次重写zeros和ones的拼接逻辑。我一般会把所有信号生成函数放在signal_gen.m里用switch语句根据信号类型分发function x signal_gen(type, n, varargin) % 通用信号生成函数 % type: step, exp, sine, rect % n: 时间索引 % varargin: 信号参数 switch type case step M varargin{1}; x double(n -M); case exp K varargin{1}; a varargin{2}; x K * a.^n; case sine A varargin{1}; w varargin{2}; phi varargin{3}; x A * cos(w*n phi); case rect tau varargin{1}; x double(abs(n) tau/2); otherwise error(未知信号类型: %s, type); end end第二把频谱分析封装成plot_spectrum(x, Ts)函数自动处理fftshift、频率轴计算和归一化。这样实验二和实验三的频谱图可以用同一套代码避免重复劳动。我习惯在函数里加一个normalize参数默认true把幅度谱归一化到 0 dB方便比较不同信号的频谱包络。第三把采样和重建流程改造成可配置的管道。用结构体cfg保存Ts、N_fft、filter_cutoff等参数主脚本只负责调用sampling_pipeline(cfg)。这样验证采样定理时只需要改cfg.Ts一个字段不用动其他代码。下面是一个简化的管道实现function [xs, xr, err] sampling_pipeline(cfg) % 采样-重建管道 % cfg.Ts: 采样间隔 % cfg.t: 原始时间轴 % cfg.x: 原始信号 % cfg.N_fft: FFT 点数 n ceil(cfg.t(1)/cfg.Ts) : floor(cfg.t(end)/cfg.Ts); xs interp1(cfg.t, cfg.x, n*cfg.Ts, spline); % 采样 % sinc 插值重建 xr zeros(size(cfg.t)); for k 1:length(n) xr xr xs(k) * sinc((cfg.t - n(k)*cfg.Ts) / cfg.Ts); end err cfg.x - xr; end这个管道跑一遍就能同时得到采样序列、重建信号和误差曲线。我拿它验证过Ts π/2和Ts 2两种情况误差从 0.01 量级跳到 0.15 量级和实验报告里的结论一致。还有一个值得做的扩展把实验二的男女声频谱分析改成实时音频采集。用audiorecorder录制 2 秒语音做 FFT 后提取基频然后对比男女声的基频分布。这个改动不大但能让实验从“离线文件分析”变成“实时信号处理”更贴近实际 DSP 应用场景。从那以后我每次跑采样重建实验都强制先画一遍原始信号和采样信号的频谱对比图确认没有混叠再往下做重建。这个习惯帮我省了很多返工时间。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑