MATLAB生成BPSK水声通信发射波形:从比特流到WAV文件
MATLAB生成BPSK水声通信发射波形:从比特流到WAV文件
关键词:MATLAB BPSK、水声通信仿真、BPSK WAV、载波频率、采样率、符号率、通信原理课程设计
水声通信的发射端,最容易被低估的一步是:把 0/1 比特真正变成一条可播放、可写入 WAV 的实值声学波形。
这篇文章用一个可复现的 MATLAB 项目,从随机比特流出发,生成带根升余弦脉冲成形的 BPSK 通带波形,并保存为 WAV 文件。本文只讨论发射端;同步、解调、信道估计和 BER 属于接收端工作,不在本文范围内。在这里插入图片描述
本文配套项目:ZoperIOT/underwater-acoustic-modulation
1. BPSK 在水声通信中做什么?
BPSK(Binary Phase Shift Keying,二进制相移键控)用两个相位表示 1 bit 信息。最常见的映射可以写成:
b k ∈ { 0 , 1 } ⟶ a k = 2 b k − 1 ∈ { − 1 , + 1 } b_k \in \{0,1\}\quad\longrightarrow\quad a_k = 2b_k-1 \in \{-1,+1\}bk∈{0,1}⟶ak=2bk−1∈{−1,+1}
映射后的符号先经过根升余弦(RRC)脉冲成形,再与载波相乘,得到实值通带信号。写成连续时间形式,可理解为:
s ( t ) = ℜ { ∑ k a k g ( t − k T s ) e j 2 π f c t } s(t)=\Re\left\{\sum_k a_k g(t-kT_s)e^{j2\pi f_c t}\right\}s(t)=ℜ{k∑akg(t−kTs)ej2πfct}
其中g ( t ) g(t)g(t)是脉冲成形滤波器,T s = 1 / R s T_s=1/R_sTs=1/Rs是符号周期,f c f_cfc是载波频率。
对初学者来说,BPSK 是很好的发射端起点:映射清楚、波形直观,也便于后续扩展到 QPSK、QAM 或 OFDM。
2. 环境与项目准备
- 下载或克隆项目:underwater-acoustic-modulation。
- 在 MATLAB 中将当前目录切到项目根目录。
- 将
src加入路径。
项目只使用 MATLAB 基础数值函数;RRC 滤波器已经包含在仓库内,不依赖 Communications Toolbox。
3. 先理解这 4 个参数
下面的配置是项目中适合先跑通的起点:96 kHz 采样率、10 kHz 载波、200 Baud 符号率。
| 参数 | 含义 | 本文取值 | 设置时的硬约束 / 建议 |
|---|---|---|---|
sampleRate/f s f_sfs | 每秒采样点数 | 96000 Hz | sampleRate / symbolRate必须是整数 |
carrierFrequency/f c f_cfc | 声学载波频率 | 10000 Hz | 必须小于f s / 2 f_s/2fs/2,且要落在换能器可用频段 |
symbolRate/R s R_sRs | 每秒发送符号数 | 200 Baud | 越高越快,但带宽需求和多径敏感性通常也会上升 |
rolloff/α \alphaα | RRC 滚降系数 | 0.5 | 取值范围为 0 到 1,影响带宽与时域拖尾 |
本例的每符号采样点数为:
s p s = f s R s = 96000 200 = 480 \mathrm{sps}=\frac{f_s}{R_s}=\frac{96000}{200}=480sps=Rsfs=20096000=480
也就是说,每个 BPSK 符号在离散波形中用 480 个采样点表示。项目会检查这个值是否为整数;不满足时会直接报错,避免生成时间轴不一致的波形。
4. 一段可直接运行的 MATLAB 代码
将下面代码保存为项目根目录下的examples/demo_bpsk_to_wav.m,或直接在命令窗口逐段运行。
%% MATLAB 生成 BPSK 水声通信发射波形,并写入 WAVclear;clc;close all;% 1) 将项目源码加入 MATLAB 路径addpath('src');% 2) 固定随机种子,保证每次生成的比特流可复现rng(2026);numberOfBits=256;bits=randi([01],1,numberOfBits);% 3) 设置发射端参数options=struct(...'sampleRate',96000,...% fs:96 kHz'carrierFrequency',10000,...% fc:10 kHz'symbolRate',200,...% Rs:200 Baud'rolloff',0.5,...% RRC 滚降系数'filterSpan',10,...% 滤波器跨度(符号数)'phaseOffset',0);% 初始载波相位% 4) 比特流 -> RRC 成形 -> BPSK 实值通带波形[waveform,info]=BPSK(bits,options);% 5) 写入标准 WAV 文件outputFile='bpsk_10kHz_200baud.wav';audiowrite(outputFile,waveform,info.sampleRate);% 6) 在命令窗口查看本次生成的信息fprintf('调制方式:%s\n',info.modulation);fprintf('采样率:%.0f Hz\n',info.sampleRate);fprintf('载波频率:%.0f Hz\n',info.carrierFrequency);fprintf('符号率:%.0f Baud\n',info.symbolRate);fprintf('时长:%.3f s\n',info.durationSeconds);fprintf('输出文件:%s\n',outputFile);% 7) 绘制时域波形(展示前 35 ms)t=(0:numel(waveform)-1)/info.sampleRate;figure('Color','w');plot(t*1e3,waveform,'b');xlim([0,min(35,t(end)*1e3)]);grid on;xlabel('时间 / ms');ylabel('幅度');title('BPSK 水声通带波形(前 35 ms)');% 8) 绘制归一化频谱nfft=2^nextpow2(numel(waveform));% 手写 Hann 窗,避免额外工具箱依赖n=0:numel(waveform)-1;window=0.5-0.5*cos(2*pi*n/(numel(waveform)-1));X=fft(waveform.*window,nfft);f=(0:nfft/2)*info.sampleRate/nfft;magdB=20*log10(abs(X(1:nfft/2+1))/max(abs(X))+eps);figure('Color','w');plot(f/1e3,magdB,'LineWidth',1.2);xlim([0,20]);ylim([-100,5]);grid on;xlabel('频率 / kHz');ylabel('归一化幅度 / dB');title('BPSK 水声通带波形频谱');运行后会在当前目录得到:
bpsk_10kHz_200baud.wav该 WAV 的采样率为 96 kHz,样本为已归一化的双精度实值信号,范围在[-1, 1]内。
5. 代码内部实际发生了什么?
项目中的BPSK(bits, options)做了四件事:
- 检查
bits是否仅包含 0 和 1; - 用
2 * bits - 1映射到-1/+1; - 进行 RRC 脉冲成形;
- 乘以复载波并取实部,最后按峰值归一化为实值通带波形。
归一化的作用是把波形峰值控制在[-1,1]:一方面满足audiowrite的常用浮点输入范围,另一方面避免后续写入 DAC 或音频链路时因幅度过大而削顶。注意,归一化不等于完成了硬件幅度标定;真正接功放和换能器时,仍需按设备的满量程、增益和安全声压校准。
6. 波形和频谱应该怎么看?
上图是同一组参数下的教学示意。你运行上一节的 MATLAB 脚本后,会得到由当前比特流和项目 RRC 成形器生成的本机精确波形与频谱。
时域图中能看到 10 kHz 附近的快速振荡,而符号切换处的包络并不是生硬跳变——这是 RRC 脉冲成形带来的结果。频谱图的能量集中在 10 kHz 载波附近。
对滚降系数为α \alphaα的理想升余弦系统,基带单边带宽可用下面的近似关系理解:
B ≈ ( 1 + α ) R s 2 B\approx \frac{(1+\alpha)R_s}{2}B≈2(1+α)Rs
本例R s = 200 R_s=200Rs=200Baud、α = 0.5 \alpha=0.5α=0.5,因此主能量大致围绕 10 kHz 在数百 Hz 的窄带范围内展开。实际频谱还会受到有限长度、窗函数和滤波器截断的影响。
7. 三个高频问题
7.1 为什么sampleRate / symbolRate不能随便设?
该项目的单载波波形按“每符号固定采样点数”进行上采样和脉冲成形。因此sampleRate / symbolRate必须是整数,且至少为 2。例如:
% 合法:96000 / 200 = 480struct('sampleRate',96000,'symbolRate',200)% 不合法:96000 / 333 不是整数struct('sampleRate',96000,'symbolRate',333)如果想把Rs调高,建议优先从能整除fs的值选起,例如在 96 kHz 下尝试 400、600、800、1200 Baud。
7.2 载波频率为什么不能乱设?
最基本的数字信号约束是:
0 < f c < f s 2 0<f_c<\frac{f_s}{2}0<fc<2fs
否则会混叠。但满足奈奎斯特条件只是第一步。水声实验还要检查换能器频响、功放带宽、DAC/ADC 采样率以及水下声道在该频段的衰减。
7.3 为什么不能直接用方波符号上载波?
可以,但频谱旁瓣通常更宽。RRC 脉冲成形的价值在于控制占用带宽,并为后续接收端的匹配滤波和定时恢复保留更规范的接口。对于课程设计或实验记录,它也让波形从“能响”走向“可分析”。
8. 下一步可以怎么扩展?
完成 BPSK 发射端后,可以按下面顺序继续:
- 把
BPSK替换为QPSK,观察每符号 2 bit 时的比特分组约束; - 比较不同
rolloff和symbolRate下的频谱占用; - 使用项目的
OFDM入口生成导频辅助 QPSK-OFDM 发射波形; - 加入预导、同步、信道、多径和接收端解调,形成完整链路。
项目地址再次放在这里:https://github.com/ZoperIOT/underwater-acoustic-modulation。如果你是在做通信原理课程设计,建议先把本节的 BPSK WAV 生成、时域图和频谱图跑通,再往接收端扩展;每一步都会更容易定位问题。
本文代码对应项目的 BPSK 发射端实现。默认参数可在仓库src/+auc/common_options.m中查看;不同硬件条件下,请以实际设备规格为准。
