2. MATLAB零基础快速上手
水声通信仿真最终要落到“产生信号—处理信号—观察结果”这条链路上,而 MATLAB 正是承载这条链路最常用的工具。本节不追求把 MATLAB 讲成一本语言手册,而是围绕仿真中真正会反复用到的四件事展开:矩阵与向量运算、脚本与函数、绘图、调试,并用一个“生成正弦信号并显示频谱”的小任务把它们串起来。学完本节,你应当能独立写出一个可运行、可修改、可复现的脚本,并看懂它输出的时域波形和频谱图。
一、先建立“一切皆矩阵”的直觉
MATLAB 的名字来自 Matrix Laboratory,它的基本数据单位是矩阵,标量是 1×1 矩阵,向量是 1×n 或 n×1 矩阵。水声仿真里,一个采样序列就是一行或一列向量,一段多通道接收数据就是一个矩阵,每一列对应一个阵元或一次快拍。理解这一点,后面的索引、运算和绘图都会顺理成章。
创建向量最常用的是冒号运算符和 linspace。例如 t = 0:1/fs:T-1/fs 生成从 0 开始、步长 1/fs 的时间序列;f = linspace(-fs/2, fs/2, N) 生成等间隔的频率轴。索引从 1 开始而不是 0,这是初学者最容易出错的地方:x(1) 是第一个元素,x(end) 是最后一个元素,x(1:100) 取前 100 个点。矩阵用分号换行、逗号或空格分列,例如 A = [1 2; 3 4]。
运算要区分“逐元素”和“矩阵意义”。A*B 是矩阵乘法,A.*B 是对应元素相乘;同理有 ./ 和 .^。在信号处理中,对向量逐点做运算几乎都要加点,例如给信号加窗 xw = x .* w,或者计算功率 p = x .^ 2。忘记加点往往不报错但结果完全错误,这是调试时的高频陷阱。
二、脚本与函数:把一次性的命令变成可复用的工具
在命令行窗口逐条输入适合探索,但仿真需要可重复执行,因此应写成脚本(.m 文件)。脚本是一串按顺序执行的命令,共享工作区变量;函数则封装输入输出,内部变量不污染工作区。一个实用的习惯是:主脚本负责参数设置和流程编排,具体算法写成函数。
函数的基本形式是 function [y, f] = mySpectrum(x, fs),文件名必须与函数名一致。函数内部应尽量只依赖传入参数,避免隐式使用全局变量,这样换一组数据时不会出现“结果对不上却找不到原因”的情况。下面给出本节实战任务的完整脚本框架,参数均为教学示例值,实际使用时按需修改:
fs = 8000; % 采样率 8 kHz(示例)
T = 0.5; % 信号时长 0.5 s
f0 = 1000; % 正弦频率 1 kHz
A = 1; % 幅度
N = round(fs*T); % 采样点数
t = (0:N-1)/fs; % 时间轴,从 0 开始
x = A*sin(2*pi*f0*t); % 生成正弦信号
% 频谱:加窗后做 FFT,并做幅度归一化
w = hann(N)'; % 汉宁窗,行向量
xw = x .* w;
X = fft(xw);
X = X(1:N/2+1); % 取单边谱
P = abs(X)/(sum(w)/2);% 幅度校正
f = (0:N/2)*fs/N; % 频率轴
figure;
subplot(2,1,1); plot(t, x); xlabel('时间/s'); ylabel('幅度');
title('正弦信号时域波形'); grid on;
subplot(2,1,2); plot(f, P); xlabel('频率/Hz'); ylabel('幅度');
title('单边幅度谱'); xlim([0 2000]); grid on;
这段代码体现了几个关键点。第一,时间轴用 (0:N-1)/fs 而不是 0:1/fs:T,保证点数与 FFT 长度严格一致。第二,频谱分析前加窗可以减小截断引起的频谱泄漏,汉宁窗是常用选择;加窗会降低幅度,因此用 sum(w)/2 做归一化校正。第三,只取前 N/2+1 个点得到单边谱,频率分辨率 Δf = fs/N,本例中为 8000/4000 = 2 Hz。这些量之间的关系,正是仿真中判断“频谱是否合理”的依据。
三、绘图:让结果“看得见”
绘图不是装饰,而是验证手段。时域图看波形是否完整、有无削顶或直流偏置;频域图看峰值位置是否落在预期频率、旁瓣是否合理。常用命令包括 plot、stem(离散序列)、subplot(分图)、xlabel/ylabel/title、grid on、xlim/ylim。对频谱建议用 plot 而非 stem,点数多时更清晰;对短序列则 stem 更能体现离散性。
下图把本节任务的信号链与关键参数关系画在一起:从参数设置、时间轴构造、正弦生成、加窗、FFT、单边谱与幅度校正,到最终两张图的判读要点。它对应的是“数据流与参数关系”,而不是操作步骤清单,便于你在写代码时对照检查每一环的输入输出。
四、调试:从“报错”到“结果不对”
MATLAB 的调试分两类。第一类是语法与维度错误,例如索引越界、矩阵维度不匹配,命令行会给出红色提示和出错行号,按提示检查即可。第二类是“能运行但结果不对”,这类更需要方法:先用小规模数据手算验证,再用 size、length、max、min、isnan 检查中间变量;在可疑行设置断点(编辑器行号左侧点击),用 dbstop if error 让程序在出错处暂停;必要时用 disp 或 fprintf 打印关键量。
针对本节任务,几个典型现象值得记住:频谱峰值不在 1000 Hz,多半是频率轴 f 与 FFT 结果没有对齐;幅度远小于 1,通常是忘记加窗归一化;时域波形“看起来在变”,可能是时间轴步长写成了 1/fs 之外的数;出现 Undefined function,检查函数文件名与函数名是否一致、当前文件夹是否在搜索路径中。养成“每改一处、重跑一次、看图确认”的习惯,比一次性写完再排查高效得多。
五、把任务做成可复现的小实验
建议你按下面的方式完成一次完整练习:先固定 fs = 8000 Hz、T = 0.5 s、f0 = 1000 Hz,运行脚本,确认时域图有 500 个周期、频域峰值在 1000 Hz 且幅度约为 1;然后把 f0 改为 1500 Hz,观察峰值移动;再把 T 改为 0.25 s,观察 Δf 变为 4 Hz、谱线变粗;最后把 x .* w 改成 x * w,看 MATLAB 是否报维度错误,从而加深对逐元素运算的理解。每次只改一个参数,记录现象与原因,这就是最朴素的仿真验证思维。
plot(abs(fft(x))) 会得到左右对称的双边谱。做单边谱时必须截取前 N/2+1 点并重建频率轴,否则横轴与峰值位置会对不上。本节的任务虽小,却覆盖了后续水声仿真最常用的动作:用向量构造时间与频率轴、用逐元素运算生成和加窗信号、用 FFT 做谱分析、用 subplot 对照时频结果、用断点和中间量检查定位问题。把这套流程练熟,后面处理调制信号、信道响应和接收阵列数据时,你只需要替换信号模型和分析对象,工具链本身不再成为障碍。