简介面向水声通信研究的水声信道仿真MATLAB程序包主要解决水下声波传播环境复杂、信号易受多径效应与衰落干扰的问题适合水声通信、信号处理领域的科研与工程人员使用也可作为相关课程教学与算法验证的辅助工具。程序包内含4个文件包括3个MATLAB脚本和1个txt说明文档整体仅1KB简洁轻量便于直接查看和修改源码其中脚本分别承担数据参数添加、主仿真执行与返回映射分析功能压缩包还附有使用说明能帮助新手快速理解流程。已有3871人学习下载是同类仿真中较受关注的代码资源。通过输入温度、盐度、深度等环境参数可快速搭建整个仿真流程模拟多径传播并统计SNR、BER等信道指标进而验证均衡、信道估计等算法的有效性为水下通信系统设计提供可靠参考。1. 水声信道仿真程序在仿什么为什么第一版误码率曲线总是不对拿到一版水声信道仿真程序大多数人的第一步是直接把发射信号扔进去然后把信噪比从 0 调到 20 dB等着误码率曲线出来。这个流程在射频无线信道里往往一天就能跑通放到水声信号处理上却常常在前三个小时翻车同样的信号从 2 km 移到 5 km多径时延从几十毫秒跳到上百毫秒把收发深度改几十米冲激响应的路径数量立刻变样再加上海面波浪带来的多普勒扩展均衡器抽头根本追不上。水声信道的本质是 1500 m/s 的低传播速度、强多径、窄可用带宽和快速时变这套组合决定了它的仿真程序和无线信道不是同一套建模逻辑。这篇笔记就按物理模型选型、MATLAB 链路落地、参数调整和避坑的顺序讲清楚一版可复现、能写进项目文档的水声信道仿真该怎么搭以及哪些参数值得花时间去调。2. 水声信道模型选型为什么射线的多径结构比瑞利平坦衰落更关键水声信道仿真程序的核心是信道冲激响应CIR水声信号处理里的时延估计、信道均衡、OFDM 保护间隔设置、水声网络介质访问控制最后都会绕回 CIR。CIR 如果错了后级算法做得再花哨都是白搭。这一章先讲清楚水声信道有哪些量决定仿真结果再说三种建模思路怎么选最后落到 MATLAB 里能跑起来的最小结构。2.1 水声信道的基本物理特征三个决定仿真程序的量第一个量是多径时延。声波在水中的传播速度大约 1500 m/s比无线电慢五个数量级。海面、海底、水层内波都会形成反射路径浅海场景下多径时延达到几十甚至几百毫秒是常态。对比之下一个符号周期只有几百微秒到几毫秒所以水声信道天然是强码间干扰信道。仿真程序如果不把多径结构建出来后面所有均衡和检测算法的验证都没有意义。第二个量是多普勒扩展。水声通信的载频通常在几 kHz 到几十 kHz波长很短平台运动 1 节约 0.5 m/s产生的多普勒频移就有几十赫兹。更麻烦的是海面波浪和浅海内波会让每条路径的到达时间不断抖动仿真出来的接收信号在频谱上会展宽。也就是说水声信道仿真程序里的时变特性不是可选项尤其是做移动平台通信或者 OFDM 子载波间隔设计时多普勒扩展决定了很多参数的上限。第三个量是噪声和可用带宽。水声信道的环境噪声随频率变化很大低频主要是航运和地震噪声高频有风成噪声和热噪声不可能用单一高斯白噪声概括。信道可用带宽也窄一个实际系统往往只有几 kHz 到十几 kHz。把这三个量放到一起看水声信道是一个稀疏、强多径、宽带比例低且时变的信道近似为瑞利平坦衰落只在极少数窄带场景下成立多数情况下仿真程序必须用真实的时延抽头来建模。2.2 射线模型是工程默认值Bellhop 在 MATLAB 里的定位射线模型是水声信道仿真里最常见的确定性建模方式。它的物理基础是声线在分层介质中的折射给定声速剖面、海深、海底底质和收发位置后仿真程序能求出从发射点到接收点的多条本征声线每条声线带到达时间、幅度、相位和到达角。这些本征声线组合起来就是一次射线追踪的 CIR。工程上最常用的工具是 Bellhop。它是独立于 MATLAB 的声传播仿真程序可以读取包含声速剖面、海底参数和环境深度的文件然后计算到达结构许多 MATLAB 水声仿真程序都是先调用 Bellhop 得到信道响应再做通信链路。要注意的是Bellhop 并不内置在 MATLAB 里需要先装好并将可执行文件加入系统路径然后在 MATLAB 里用system调用。% 在MATLAB里调用Bellhop生成并读取信道到达信息 envName shallow; system([bellhop , envName]); % 读取 shallow.env生成 .arr 文件 [t, A] readArrival([envName, .arr]); % 到时时延和复幅度这段代码里的readArrival依赖具体arr文件格式不同版本差异较大但逻辑一致从文本里读时延列和幅度列。t的单位是秒A是复数幅度后续把它们放进 CIR 抽头即可。首次跑通时建议先画一个散点图横轴是时延纵轴是幅度看看多径数量是否符合扬程估计再做链路仿真。为什么射线模型是默认选择因为它可解释、可复现还省硬件实验成本。同一个环境文件在三天后跑出来的 CIR 是硬的结论项目评审时能画路径图能说清楚哪条路径来自海面反射哪条来自海底反射。这一点比纯统计模型更容易落地也更容易说服合作方。相位机制和吸收系数取保守值如果仿真结果和海上实测差距很大通常问题出在环境文件而不是射线追踪算法本身。2.3 什么时候换统计模型时变多径的随机相位实现射线模型在时不变环境下非常稳定但真实水声信道随时间变化。海面波浪周期从零点几秒到十几秒平台运动又带来多普勒如果只拿一组静态 CIR 做全链路仿真误码率通常会比实测乐观。这时可以用统计模型给确定性多径叠加随机扰动。常见做法是把 Bellhop 得到的每条本征声线保留幅度和时延但把相位变成随时间变化的随机量或者给每条路径加一个随机的多普勒频移。这样既保留了浅海环境的多径骨架又引入了时变扩展仿真程序的可信度明显提高。% 把静态CIR改装成时变CIR每条路径乘一个时变相位 function ht timeVaryingCIR(t_delay, A, doppler, ts) ht zeros(size(ts)); for p 1:numel(t_delay) ht ht A(p) .* exp(1j * 2*pi*doppler(p) .* ts); end ht ht / sqrt(sum(abs(A).^2)); % 能量归一化 end这里面doppler(p)是每条路径的多普勒频移单位 Hz正负号代表路径靠近还是远离。工程上不要给所有路径配同一个多普勒那样会把平坦频偏和真正的多普勒扩展弄混。给不同的路径配独立的随机频移才能体现信道的时间选择性。至于要不要换成全随机瑞利信道取决于目标验证同步算法时用确定性多径加扰动更容易复现做系统级误码率上限评估时再考虑全随机模型。3. 用 MATLAB 搭一条可复现的水声信道仿真链路Bellhop 加误码率模型选型定了之后正式进入代码层面。这一章直接搭一条最小可复现链路声速剖面进 MATLAB调用 Bellhop 得到多径冲激响应再把这个 CIR 塞进一个 QPSK 基带收发链路里最后画出误码率曲线。整个链路跑通之后你再往里面加均衡器、OFDM 或者水声网络协议都有地方下手。3.1 声速剖面怎么进 MATLAB从实测点列到环境文件声速剖面SSP是整条仿真链路的物理底层。实测队通常会给出深度和声速的离散点你需要把这些点插值成规则深度网格再写进 Bellhop 的环境文件。这个步骤看起来只是格式转换但深度范围必须覆盖从海面到海底每层深度差不要太大否则射线追踪会漏掉一些弯曲路径。% 用实测离散点插值声速剖面 z_raw [0, 5, 15, 30, 50, 75, 100]; c_raw [1505, 1500, 1493, 1485, 1482, 1480, 1482]; % 实测声速 z (0:1:100); % 规则化深度网格 c interp1(z_raw, c_raw, z, pchip); % PCHIP避免过冲 plot(c, z); set(gca, YDir, reverse); xlabel(声速 m/s); ylabel(深度 m);PCHIP 插值比三次样条更适合声速剖面因为它不会在数据点之间产生过度振荡。插值后建议先画图检查浅海负梯度会让声线往下弯正梯度会让声线往上弯如果曲线出现不合理的拐弯说明原始数据有异常点要回到实测队确认而不是靠 MATLAB 自动修复。写环境文件时注意两点一是海水深度要超过最大声速剖面的深度二是接收深度和发射深度必须落在声速剖面范围内。Bellhop 遇到深度超出范围时经常返回全零到达结构但不会给错误提示这个坑在后面避坑章还会细讲。3.2 搭建最小 QPSK 链路脉冲成型、信道卷积、加噪声和判误码拿到 CIR 之后要在 MATLAB 里搭一条完整的基带链路。下面这段代码以 QPSK 为例核心步骤是调制、上采样、脉冲成型、过信道、加噪、匹配滤波、下采样和判误码。这里不引入均衡器先看裸信道下的表现。% QPSK 基带收发链路复用 3.1 得到的 t 和 A fs 4000; % 基带采样率 4 kHz sps 4; % 每符号抽样数 symRate fs / sps; % 符号率 1 ksymbol/s N 4000; % 仿真符号数 data randi([0 1], N, 1); txSym pskmod(data, 4, pi/4); % QPSK 映射 txUp upsample(txSym, sps); % 上采样 rrc rcosdesign(0.25, 8, sps); % 根升余弦滤波器 txFilt conv(txUp, rrc, same); % 由多径时延构建 CIR 抽头 L ceil(max(t) * fs) 1; h zeros(1, L); for p 1:numel(t) tap round(t(p) * fs) 1; if tap L h(tap) h(tap) A(p); end end h h / sqrt(sum(abs(h).^2)); % 能量归一化 % 过信道并加高斯白噪声 rxFilt conv(txFilt, h, full); rxNoisy awgn(rxFilt, snr_dB, measured); % 匹配滤波与下采样注意同步位置 rxMatch conv(rxNoisy, rrc, same); rxSym rxMatch(1 sps/2 : sps : end); rxSym rxSym(1:N); dataHat pskdemod(rxSym, 4, pi/4); ber mean(dataHat ~ data);这里有几个参数要特别说明。sps的取值影响脉冲成型的频谱占用和后续同步精度取 4 是工程上的保守值仿真速度快如果做精细的多普勒仿真可以考虑 8 或 16。awgn的measured选项会把实际信号能量代入计算这比手动加噪声功率更稳定。下采样时的1 sps/2是匹配滤波延迟的补偿值实际最优采样点受信道时延影响更严谨的做法是先做相关同步这里为了展示链路逻辑直接固定了偏移。3.3 用误码率曲线反向验证 CIR 是否合理链路跑通后不要立刻换参数先扫一组信噪比画误码率曲线。把结果和一条参考线比较如果多径比较弱误码率曲线应该接近理论 QPSK 高斯信道曲线如果多径很强误码率会出现地板高信噪比时不再下降这是码间干扰的表现而不是系统坏了。snrList 0:2:20; berList zeros(size(snrList)); for k 1:numel(snrList) snr_dB snrList(k); % 重跑上面的收发链路记录误码率 berList(k) runLink(h, snr_dB); end semilogy(snrList, berList, o-); grid on; xlabel(SNR dB); ylabel(BER);如果误码率在高信噪比时快速下降说明多径时延扩展很小此时要回去看环境文件是不是写得太理想了。比如发射接收都放在深海声道轴附近多径自然少得到的曲线就会过于乐观。做过水声的人都知道浅海信道里的强反射路径是不能靠提高功率绕过去的误码率地板的出现反而说明 CIR 里多径结构被成功仿真出来了。4. 水声信道仿真参数必调清单声速剖面、收发深度、采样率有人会觉得仿真程序跑通就完事了但水声信道仿真程序真正的工程量在校参。环境参数的小变化会导致信道冲激响应的大变化这一章列出三个最先要校的参数都调对之后仿真结果才敢信。4.1 声速剖面看起来正常结果却错的重灾区声速剖面是水声信道仿真第一参数也是最容易踩坑的参数。常见错误是图省事直接用 1500 m/s 恒速剖面。恒速剖面在深海远距离场景偶尔够用在浅海场景一定会丢失多径结构因为它让声线变成直线只产生一条直达路径和简单的界面反射。这样仿出来的误码率必然过于乐观均衡器算法根本得不到锻炼。判断声速剖面是否合理有个笨办法画出射线路径图数一数路径数。如果直达路径旁边没有海底或海面反射路径多半是剖面太简单或者深度范围没覆盖对。另一个检查点是声速梯度符号声速随深度下降会产生向下弯曲的声线海面附近可能出现声影区这个现象在很多水声教材里都有。4.2 布放深度和水平距离多径结构随距离怎么变发射深度、接收深度和水平距离这三个参数决定了 CIR 的多径时延结构。浅海场景下收发深度靠近海面会增强海面反射路径靠近海底会增强海底反射路径收发深度都在声道轴附近时直达路径占主导多径分量会弱很多。做通信算法验证时不要只取一个位置要把远距离和近距离都扫一遍。我一般会固定海深 100 m分别仿真 500 m、1 km、2 km、5 km 四组距离比较 CIR 的路径数量和最大时延。距离越远反射路径相对直达路径的时延差越大最大多径时延可能从几毫秒涨到几十毫秒。这一步直接影响 OFDM 循环前缀长度的选择如果循环前缀短于最大时延ICI 和 ISI 会同时出现。参数典型取值对 CIR 的影响注意点海深50–200 m决定海底反射路径长度深度小于声速剖面范围会报错或返回空发射深度5–30 m改变直达路径与界面反射的强度比贴近海面时海面反射增强接收深度5–50 m决定多径时延扩展在声道轴附近时多径最少水平距离0.5–5 km直接放大多径时延差距离越长能量衰减越明显4.3 采样率和带宽带通仿真为什么更容易翻车信道仿真程序的采样率决定了 CIR 抽头数量。最大多径时延 100 ms采样率 4 kHzCIR 就有 401 个抽头如果采样率提到 40 kHz抽头数变成 4001信道卷积的计算量和内存占用都会涨一个量级。做基带仿真时采样率只需覆盖信号带宽的四到八倍不必按载频设置。带通仿真看起来更接近真实射频前端但它对采样率的要求极其苛刻。载频 10 kHz、带宽 2 kHz 的系统带通采样率至少 24 kHz计算量比基带高出数倍而且带通信号对相位噪声和载波频偏非常敏感。工程上我一般只在需要验证声呐前端或硬件在环时才做带通仿真验证通信算法一律用基带等效模型仿真速度差一个量级但结论一致。5. 水声信道仿真避坑指南五个常见翻车现场与排查路径水声信道仿真的坑大多是环境文件参数和归一化方式导致下面这五个现象是项目里最容易遇到的每条按现象、原因、解决三步展开。5.1 现象Bellhop 生成的冲激响应全是 NaN 或空数组原因发射深度、接收深度超出海水深度或者声速剖面数据里有 NaN。Bellhop 对越界深度不报错只是输出空到达文件导致读取时出现空数组。另一个常见原因是环境文件里频率、水深等字段格式不对程序直接终止但没写日志。解决先用一个最简单的环境文件跑通再逐步增加声速剖面细节。读取到达文件后立刻判断数组是否为空空则抛错并打印收发深度和海水深度避免静默失败。if isempty(t) error(Bellhop 返回空到达数据检查深度和频率参数); end5.2 现象误码率曲线比理论瑞利下限还低结果过于乐观原因CIR 能量没有归一化或者每次重跑链路时给符号乘以了复数增益但没有等效地提高信号能量。最常见的是把 Bellhop 输出的声压幅度当成信道冲激响应直接卷积没有做单位化处理。能量不归一化的结果是某些仿真点等效信噪比比设定值高好几 dB。解决在 CIR 进入收发链路前统一做能量归一化。归一化不是简单取最大路径为 1而是让所有抽头幅度平方和等于 1这样 AWGN 功率才能和 SNR 对应。h h / sqrt(sum(abs(h).^2));5.3 现象多普勒扩展和预设值差很大频谱展宽异常原因把多普勒简单加到载波频率上却忽略了每条路径的多普勒频移不同。平坦频移只会让星座整体旋转不产生频谱扩展真正的多普勒扩展来自不同路径的随机频移分量。仿真代码里如果没有对每条路径独立加频移观察到的频谱自然很窄。解决在时变 CIR 构造中对每条路径各乘一个独立的复指数频移按路径到达角计算而不是全信道共用一个频偏。5.4 现象同一份代码两次运行误码率结果不一样原因至少一个随机源没固定种子。通信链路里的高斯噪声、统计模型里的随机多径相位、随机数据序列都是随机源。水声仿真跑一次信噪比点往往要几十秒如果不固定种子最终曲线的抖动幅度会大得没法看。解决在链路开头设置全局随机种子。rng(2026); % 固定随机种子保存结果便于复现5.5 现象仿真一个信噪比点要跑几分钟没法扫参原因CIR 抽头太多还用了高倍上采样和长序列。特别是把脉冲成型滤波器设在 symbol 级而不是在系统采样率级时卷积长度会被拉得很长MATLAB 的conv在长序列下效率很低。解决先缩短符号数跑通逻辑再逐步增加或者把 CIR 抽头截断到有效多径范围过长时延的微幅度路径可以直接丢弃。如果均衡器抽头数多考虑把conv换成fftfilt并用 GPU 加速。6. 把信噪比拟合当作验证手段用固定 CIR 快照做回归测试水声信道仿真程序最容易出现的隐性问题是环境文件改了一次CIR 变了结果也变了但没人知道是环境变了对还是代码改错了。我的做法是给每一版环境文件生成一个固定 CIR 快照保存成.mat文件并附带路径数、最大时延、能量三个摘要字段。每次改算法前先跑一个回归脚本确认 CIR 没有被动过。% 保存CIR快照附带摘要信息 snap.cir h; snap.maxDelay max(t); snap.numPaths numel(t); snap.kFactor 10*log10(max(abs(A))^2 / sum(abs(A(2:end)).^2)); save(sprintf(cir_%s.mat, envName), -struct, snap);cir_xxx.mat文件名里带环境代号回归脚本只读取快照不重新跑 Bellhop。这样即使 Bellhop 环境变量或系统路径出了问题也能在链路层面先把问题隔离出来。验证时用一个单音信号过一遍 CIR观察时延和幅度是否符合摘要再叠加噪声算一次接收 SNR确认链路底噪正确。这个方法很多做水声的人都这么用相当于给每一次系统仿真留了一段最小化回归基线。早期我也嫌这个步骤麻烦直接拿 Bellhop 跑完就接均衡器结果有两周时间一直在追一个“均衡器收敛慢”的假问题最后发现是环境文件里海底声速被不小心改成了海面值。现在无论多忙我都会在环境文件定稿后马上生成 CIR 快照再开始优化算法。这个习惯帮我省下的排错时间远比多写几个脚本的时间多。希望帮到你。本文还有配套的精品资源点击获取