关键词MATLAB 8PSK、水声通信仿真、8PSK 星座图、PSK 调制、WAV 文件、采样率、载波频率、符号率、通信原理课程设计前面已经写过 BPSK 和 QPSK。BPSK 每个符号携带 1 bitQPSK 每个符号携带 2 bit。这篇继续往上扩展用 MATLAB 生成 8PSK 水声通信发射波形。8PSK 的核心变化是每 3 个 bit 组成 1 个符号用 8 个不同相位表示信息。在相同符号率下8PSK 的理论比特率是 BPSK 的 3 倍是 QPSK 的 1.5 倍。本文配套项目ZoperIOT/underwater-acoustic-modulation1. 8PSK 在水声通信里做什么8PSK全称 8 Phase Shift Keying意思是用 8 个不同相位表示数字信息。它可以看作 QPSK 的进一步扩展调制方式星座点数每符号携带 bit 数BPSK21QPSK428PSK838PSK 的符号可以写成s k e j ( ϕ 0 2 π m k / 8 ) s_k e^{j(\phi_0 2\pi m_k/8)}skej(ϕ02πmk/8)其中m k m_kmk是每 3 bit 转成的整数取值为 0 到 7ϕ 0 \phi_0ϕ0是初始相位偏移每个s k s_ksk是单位圆上的一个复数星座点。在本文使用的项目中8PSK 发射波形由pad_8PSK函数生成。这个函数名看起来有点特别是项目保留的历史命名实际功能就是生成 8PSK 发射端通带波形。2. 8PSK 发射端流程8PSK 的发射端可以拆成下面几步生成 0/1 比特流每 3 bit 分成一组将000到111映射到 8 个相位点对复基带符号进行 RRC 脉冲成形上变频到声学载波频率取实部得到实值通带波形归一化并写入 WAV 文件。对应到项目接口就是[waveform,info]pad_8PSK(bits,options);也可以用统一入口[waveform,info]generate_signal(8psk,bits,options);如果是写教程或课程设计我更建议直接使用pad_8PSK因为读者能更清楚地看到当前调用的是哪一种调制方式。3. 参数设置fs、fc、Rs 和 samplesPerSymbol本文继续使用一组适合先跑通的参数参数含义本文取值说明sampleRate采样率96000 HzWAV 文件采样率也是离散仿真采样率carrierFrequency载波频率10000 Hz实值通带信号中心频率symbolRate符号率200 Baud每秒发送 200 个 8PSK 符号rolloffRRC 滚降系数0.5控制频谱占用和时域拖尾filterSpanRRC 滤波器跨度10单位为符号数phaseOffset初始相位08PSK 星座整体旋转角度每符号采样点数为s p s f s R s 96000 200 480 \mathrm{sps}\frac{f_s}{R_s}\frac{96000}{200}480spsRsfs20096000480也就是说每个 8PSK 符号在离散波形里由 480 个采样点表示。注意项目会检查sampleRate / symbolRate是否为整数。如果不是整数说明每个符号无法对应固定采样点数程序会直接报错。4. 一段可以直接运行的 MATLAB 代码建议保存为examples/demo_8psk_to_wav.m代码如下%% MATLAB 生成 8PSK 水声通信发射波形并写入 WAVclear;clc;close all;% 1) 加入项目源码路径addpath(src);% 2) 固定随机种子保证结果可复现rng(2026);% 8PSK 每 3 bit 映射成 1 个符号所以 bit 数必须能被 3 整除numberOfBits300;bitsrandi([01],1,numberOfBits);% 3) 设置发射参数optionsstruct(...sampleRate,96000,...% fs96 kHzcarrierFrequency,10000,...% fc10 kHzsymbolRate,200,...% Rs200 Baudrolloff,0.5,...% RRC 滚降系数filterSpan,10,...% 滤波器跨度单位为符号数phaseOffset,0);% 初始相位% 4) 比特流 - 8PSK 星座映射 - RRC 成形 - 实值通带波形[waveform,info]pad_8PSK(bits,options);% 5) 写入 WAV 文件outputFile8psk_10kHz_200baud.wav;audiowrite(outputFile,waveform,info.sampleRate);% 6) 打印基本信息fprintf(调制方式%s\n,info.modulation);fprintf(输入 bit 数%d\n,numel(info.inputBits));fprintf(8PSK 符号数%d\n,numel(info.symbols));fprintf(采样率%.0f Hz\n,info.sampleRate);fprintf(载波频率%.0f Hz\n,info.carrierFrequency);fprintf(符号率%.0f Baud\n,info.symbolRate);fprintf(每符号采样点数%.0f\n,info.sampleRate/info.symbolRate);fprintf(时长%.3f s\n,info.durationSeconds);fprintf(输出文件%s\n,outputFile);% 7) 绘制星座图figure(Color,w);plot(real(info.symbols),imag(info.symbols),o,...MarkerFaceColor,[0.450.251],...MarkerEdgeColor,[0.450.251]);axis equal;grid on;xlabel(I 路);ylabel(Q 路);title(8PSK 星座图);% 8) 绘制时域波形展示前 40 mst(0:numel(waveform)-1)/info.sampleRate;figure(Color,w);plot(t*1e3,waveform,b);xlim([0,min(40,t(end)*1e3)]);grid on;xlabel(时间 / ms);ylabel(归一化幅度);title(8PSK 实值通带波形);% 9) 绘制频谱nfft2^nextpow2(numel(waveform));n0:numel(waveform)-1;window0.5-0.5*cos(2*pi*n/(numel(waveform)-1));spectrumfft(waveform(:)..*window,nfft);spectrumabs(spectrum(1:nfft/21));spectrumDb20*log10(spectrum/max(spectrum)1e-8);f(0:nfft/2)*info.sampleRate/nfft;figure(Color,w);plot(f/1000,spectrumDb,LineWidth,1.2);xline(info.carrierFrequency/1000,--r,10 kHz carrier);grid on;xlim([0,20]);ylim([-80,5]);xlabel(频率 / kHz);ylabel(归一化幅度 / dB);title(8PSK 发射波形频谱);运行后会得到8psk_10kHz_200baud.wav这就是一段可以保存、播放或送入后续仿真链路的 8PSK 实值通带波形。5. 8PSK 的比特率怎么理解8PSK 每个符号携带 3 bit因此R b 3 R s R_b 3R_sRb3Rs本文设置Rs 200 Baud所以理论比特率为Rb 3 × 200 600 bit/s和 BPSK、QPSK 放在一起对比调制方式每符号 bit 数符号率理论比特率BPSK1200 Baud200 bit/sQPSK2200 Baud400 bit/s8PSK3200 Baud600 bit/s这里的理论比特率只考虑调制映射不包括帧头、导频、纠错编码、保护间隔等开销。6. 8PSK 比 QPSK 更好吗不一定。8PSK 的优点是频谱效率更高同样的符号率下它能携带更多 bit。但代价也很明显星座点之间的相位间隔变小了。QPSK 相邻星座点相差 90°8PSK 相邻星座点只相差 45°。这意味着接收端更容易因为噪声、相位偏差、多普勒或同步误差而判错。所以在水声通信里调制阶数不是越高越好。实际选择通常要看水声信道信噪比多径扩展程度多普勒变化换能器可用带宽接收端同步和均衡能力。如果只是课程设计或入门仿真推荐顺序是BPSK → QPSK → 8PSK → QAM → OFDM7. 常见问题7.1 为什么 bit 数必须能被 3 整除因为 8PSK 每 3 bit 组成 1 个符号。例如000 001 010 011 100 101 110 111这些都可以映射到完整的 8PSK 星座点。但如果输入 bit 数不是 3 的整数倍最后一组就凑不齐 3 bit。项目底层函数会检查这个条件并报错Input length must be divisible by 3.解决方法生成随机 bit 时把数量设为 300、600、900 这类 3 的倍数对真实数据末尾补零在接收端根据原始长度去掉补零。7.2pad_8PSK这个名字是什么意思这里的pad_8PSK是项目保留的历史函数名。它实际生成的是 8PSK 发射波形。如果你不想在文章里解释函数名也可以使用统一入口[waveform,info]generate_signal(8psk,bits,options);但从可读性来说本文仍然直接调用pad_8PSK这样更贴近仓库源码。7.3 为什么频谱集中在 10 kHz 附近因为本文设置了carrierFrequency,10000复基带 8PSK 信号经过上变频后主要能量会搬移到 10 kHz 附近。这也是发射到声学换能器前常见的处理方式先在基带完成调制再搬移到设备可工作的频段。7.4 为什么要归一化WAV 文件通常希望样本幅度落在[-1, 1]内。项目在passband阶段会对输出波形做峰值归一化避免写 WAV 或播放时出现削波。如果后续你叠加前导、静音段或多个波形建议写文件前再检查max(abs(waveform))8. 可以继续扩展什么这篇只完成 8PSK 发射端波形生成。后续可以继续做对比 QPSK 和 8PSK 的星座点间距加入 AWGN 噪声观察星座点扩散加入多径信道观察 8PSK 的相位扰动写 8PSK 相干解调统计不同 SNR 下的 BER比较 BPSK、QPSK、8PSK 在相同符号率下的比特率。如果用作课程设计可以写成基于 MATLAB 的 8PSK 水声通信发射波形生成与频谱分析9. 项目链接本文配套项目https://github.com/ZoperIOT/underwater-acoustic-modulation项目只覆盖发射端波形生成不包含完整接收机。也就是说本文讨论的是“如何生成可以写入 WAV 的 8PSK 水声发射信号”同步、解调、信道估计和 BER 分析可以作为后续扩展。
MATLAB生成8PSK水声通信发射波形:3比特映射、星座图与WAV文件导出
发布时间:2026/6/27 17:07:12
关键词MATLAB 8PSK、水声通信仿真、8PSK 星座图、PSK 调制、WAV 文件、采样率、载波频率、符号率、通信原理课程设计前面已经写过 BPSK 和 QPSK。BPSK 每个符号携带 1 bitQPSK 每个符号携带 2 bit。这篇继续往上扩展用 MATLAB 生成 8PSK 水声通信发射波形。8PSK 的核心变化是每 3 个 bit 组成 1 个符号用 8 个不同相位表示信息。在相同符号率下8PSK 的理论比特率是 BPSK 的 3 倍是 QPSK 的 1.5 倍。本文配套项目ZoperIOT/underwater-acoustic-modulation1. 8PSK 在水声通信里做什么8PSK全称 8 Phase Shift Keying意思是用 8 个不同相位表示数字信息。它可以看作 QPSK 的进一步扩展调制方式星座点数每符号携带 bit 数BPSK21QPSK428PSK838PSK 的符号可以写成s k e j ( ϕ 0 2 π m k / 8 ) s_k e^{j(\phi_0 2\pi m_k/8)}skej(ϕ02πmk/8)其中m k m_kmk是每 3 bit 转成的整数取值为 0 到 7ϕ 0 \phi_0ϕ0是初始相位偏移每个s k s_ksk是单位圆上的一个复数星座点。在本文使用的项目中8PSK 发射波形由pad_8PSK函数生成。这个函数名看起来有点特别是项目保留的历史命名实际功能就是生成 8PSK 发射端通带波形。2. 8PSK 发射端流程8PSK 的发射端可以拆成下面几步生成 0/1 比特流每 3 bit 分成一组将000到111映射到 8 个相位点对复基带符号进行 RRC 脉冲成形上变频到声学载波频率取实部得到实值通带波形归一化并写入 WAV 文件。对应到项目接口就是[waveform,info]pad_8PSK(bits,options);也可以用统一入口[waveform,info]generate_signal(8psk,bits,options);如果是写教程或课程设计我更建议直接使用pad_8PSK因为读者能更清楚地看到当前调用的是哪一种调制方式。3. 参数设置fs、fc、Rs 和 samplesPerSymbol本文继续使用一组适合先跑通的参数参数含义本文取值说明sampleRate采样率96000 HzWAV 文件采样率也是离散仿真采样率carrierFrequency载波频率10000 Hz实值通带信号中心频率symbolRate符号率200 Baud每秒发送 200 个 8PSK 符号rolloffRRC 滚降系数0.5控制频谱占用和时域拖尾filterSpanRRC 滤波器跨度10单位为符号数phaseOffset初始相位08PSK 星座整体旋转角度每符号采样点数为s p s f s R s 96000 200 480 \mathrm{sps}\frac{f_s}{R_s}\frac{96000}{200}480spsRsfs20096000480也就是说每个 8PSK 符号在离散波形里由 480 个采样点表示。注意项目会检查sampleRate / symbolRate是否为整数。如果不是整数说明每个符号无法对应固定采样点数程序会直接报错。4. 一段可以直接运行的 MATLAB 代码建议保存为examples/demo_8psk_to_wav.m代码如下%% MATLAB 生成 8PSK 水声通信发射波形并写入 WAVclear;clc;close all;% 1) 加入项目源码路径addpath(src);% 2) 固定随机种子保证结果可复现rng(2026);% 8PSK 每 3 bit 映射成 1 个符号所以 bit 数必须能被 3 整除numberOfBits300;bitsrandi([01],1,numberOfBits);% 3) 设置发射参数optionsstruct(...sampleRate,96000,...% fs96 kHzcarrierFrequency,10000,...% fc10 kHzsymbolRate,200,...% Rs200 Baudrolloff,0.5,...% RRC 滚降系数filterSpan,10,...% 滤波器跨度单位为符号数phaseOffset,0);% 初始相位% 4) 比特流 - 8PSK 星座映射 - RRC 成形 - 实值通带波形[waveform,info]pad_8PSK(bits,options);% 5) 写入 WAV 文件outputFile8psk_10kHz_200baud.wav;audiowrite(outputFile,waveform,info.sampleRate);% 6) 打印基本信息fprintf(调制方式%s\n,info.modulation);fprintf(输入 bit 数%d\n,numel(info.inputBits));fprintf(8PSK 符号数%d\n,numel(info.symbols));fprintf(采样率%.0f Hz\n,info.sampleRate);fprintf(载波频率%.0f Hz\n,info.carrierFrequency);fprintf(符号率%.0f Baud\n,info.symbolRate);fprintf(每符号采样点数%.0f\n,info.sampleRate/info.symbolRate);fprintf(时长%.3f s\n,info.durationSeconds);fprintf(输出文件%s\n,outputFile);% 7) 绘制星座图figure(Color,w);plot(real(info.symbols),imag(info.symbols),o,...MarkerFaceColor,[0.450.251],...MarkerEdgeColor,[0.450.251]);axis equal;grid on;xlabel(I 路);ylabel(Q 路);title(8PSK 星座图);% 8) 绘制时域波形展示前 40 mst(0:numel(waveform)-1)/info.sampleRate;figure(Color,w);plot(t*1e3,waveform,b);xlim([0,min(40,t(end)*1e3)]);grid on;xlabel(时间 / ms);ylabel(归一化幅度);title(8PSK 实值通带波形);% 9) 绘制频谱nfft2^nextpow2(numel(waveform));n0:numel(waveform)-1;window0.5-0.5*cos(2*pi*n/(numel(waveform)-1));spectrumfft(waveform(:)..*window,nfft);spectrumabs(spectrum(1:nfft/21));spectrumDb20*log10(spectrum/max(spectrum)1e-8);f(0:nfft/2)*info.sampleRate/nfft;figure(Color,w);plot(f/1000,spectrumDb,LineWidth,1.2);xline(info.carrierFrequency/1000,--r,10 kHz carrier);grid on;xlim([0,20]);ylim([-80,5]);xlabel(频率 / kHz);ylabel(归一化幅度 / dB);title(8PSK 发射波形频谱);运行后会得到8psk_10kHz_200baud.wav这就是一段可以保存、播放或送入后续仿真链路的 8PSK 实值通带波形。5. 8PSK 的比特率怎么理解8PSK 每个符号携带 3 bit因此R b 3 R s R_b 3R_sRb3Rs本文设置Rs 200 Baud所以理论比特率为Rb 3 × 200 600 bit/s和 BPSK、QPSK 放在一起对比调制方式每符号 bit 数符号率理论比特率BPSK1200 Baud200 bit/sQPSK2200 Baud400 bit/s8PSK3200 Baud600 bit/s这里的理论比特率只考虑调制映射不包括帧头、导频、纠错编码、保护间隔等开销。6. 8PSK 比 QPSK 更好吗不一定。8PSK 的优点是频谱效率更高同样的符号率下它能携带更多 bit。但代价也很明显星座点之间的相位间隔变小了。QPSK 相邻星座点相差 90°8PSK 相邻星座点只相差 45°。这意味着接收端更容易因为噪声、相位偏差、多普勒或同步误差而判错。所以在水声通信里调制阶数不是越高越好。实际选择通常要看水声信道信噪比多径扩展程度多普勒变化换能器可用带宽接收端同步和均衡能力。如果只是课程设计或入门仿真推荐顺序是BPSK → QPSK → 8PSK → QAM → OFDM7. 常见问题7.1 为什么 bit 数必须能被 3 整除因为 8PSK 每 3 bit 组成 1 个符号。例如000 001 010 011 100 101 110 111这些都可以映射到完整的 8PSK 星座点。但如果输入 bit 数不是 3 的整数倍最后一组就凑不齐 3 bit。项目底层函数会检查这个条件并报错Input length must be divisible by 3.解决方法生成随机 bit 时把数量设为 300、600、900 这类 3 的倍数对真实数据末尾补零在接收端根据原始长度去掉补零。7.2pad_8PSK这个名字是什么意思这里的pad_8PSK是项目保留的历史函数名。它实际生成的是 8PSK 发射波形。如果你不想在文章里解释函数名也可以使用统一入口[waveform,info]generate_signal(8psk,bits,options);但从可读性来说本文仍然直接调用pad_8PSK这样更贴近仓库源码。7.3 为什么频谱集中在 10 kHz 附近因为本文设置了carrierFrequency,10000复基带 8PSK 信号经过上变频后主要能量会搬移到 10 kHz 附近。这也是发射到声学换能器前常见的处理方式先在基带完成调制再搬移到设备可工作的频段。7.4 为什么要归一化WAV 文件通常希望样本幅度落在[-1, 1]内。项目在passband阶段会对输出波形做峰值归一化避免写 WAV 或播放时出现削波。如果后续你叠加前导、静音段或多个波形建议写文件前再检查max(abs(waveform))8. 可以继续扩展什么这篇只完成 8PSK 发射端波形生成。后续可以继续做对比 QPSK 和 8PSK 的星座点间距加入 AWGN 噪声观察星座点扩散加入多径信道观察 8PSK 的相位扰动写 8PSK 相干解调统计不同 SNR 下的 BER比较 BPSK、QPSK、8PSK 在相同符号率下的比特率。如果用作课程设计可以写成基于 MATLAB 的 8PSK 水声通信发射波形生成与频谱分析9. 项目链接本文配套项目https://github.com/ZoperIOT/underwater-acoustic-modulation项目只覆盖发射端波形生成不包含完整接收机。也就是说本文讨论的是“如何生成可以写入 WAV 的 8PSK 水声发射信号”同步、解调、信道估计和 BER 分析可以作为后续扩展。