舰船噪声仿真建模:线谱、连续谱与调制谱的Python合成方法
2026/9/13 15:30:04 网站建设 项目流程

简介:面向舰船噪声仿真与信号处理研究,这份MATLAB源码资源可用于模拟螺旋桨、机械振动及流体动力等典型舰船噪声,支持通过参数调整适配不同工况,适合船舶工程、水声工程及相关方向的初学者和工程师快速入门。压缩包内共1个.m文件,大小约692B,程序以MATLAB函数形式封装,虽为轻量级代码,但涵盖噪声源识别、物理模型构建、滤波与频谱分析、仿真结果可视化等核心环节,结构清晰,便于阅读、调试和二次开发。目前已有568人学习浏览,具有不错的参考价值。读者可获得可直接运行的.m源码及完整的舰船噪声建模思路,帮助理解傅里叶变换、短时傅里叶变换等信号处理方法在噪声分析中的实际应用;程序中预留了参数调整与优化空间,经过测试,可用于舰船设计、噪声控制以及反探测策略研究,为相关实验与工程实践提供数据支撑和灵感。

1. 舰船噪声仿真:ship noise 建模不是把白噪声调大声

做被动声呐算法和声呐仿真平台的人,大概率都遇到过同一个尴尬:实测数据不够。租船、布放水听器、跑不同航速和航道,成本高周期长,很难凑齐低航速、深潜、不同海况的组合。所以绝大多数算法训练集和系统级仿真平台里的舰船噪声,都是建模合成出来的。舰船噪声建模要解决的核心问题不是“像不像噪声”,而是要复现舰船信号在频域和包络域的三类可判别特征:机械线谱、空化连续谱、螺旋桨调制谱。网上流传的 jianchuanzaoshengxinhao.rar 这类舰船噪声仿真资料包,基本就是围绕这三类成分做合成,但固定脚本换不了航速、转速和船型参数。下面这套链路从谱型定义到时域合成再到验证,可以在本地跑通,参数全部可调。

2. 舰船噪声建模的三类频谱成分:线谱、连续谱与调制谱

2.1 机械线谱:轴频、叶频和它们的梳状结构

舰船机械噪声来自主机、辅机、减速齿轮、轴系轴承等旋转与往复部件。这些部件的运动是周期性的,辐射到水里的能量集中在基频和谐波上,表现为功率谱上一根根离散谱峰,也就是线谱。最常用的两个基准频率是轴频和叶频:轴频直接由转速决定,shaft_f = rpm / 60,120 r/min 的主机轴频就是 2 Hz;叶频再乘螺旋桨叶片数,blade_f = blades * shaft_f,五叶桨对应 10 Hz。线谱并不只出现在这两个频率上,齿轮啮合频率、辅机振动频率会在几百赫兹到几千赫兹产生各自的离散谱线,合成后在 LOFAR 图上看到的就是一组等间隔的“梳状”线族。四冲程柴油机发火频率约按N*C/120估算,二冲程按N*C/60,其中 N 是转速、C 是缸数。

实际测量里线谱不是理想无穷窄的。主机转速不稳定、轴系弹性扭转,会让中心频率出现 ±1% 量级的缓慢波动,谱线本身也有一定宽度。工程上习惯用 Q 值描述线谱宽度:Q 等于中心频率除以 3dB 带宽。低频轴频线谱 Q 值可到 100 以上,几百赫兹的机械线谱 Q 值多在 30~80 之间。仿真时如果全部用理想正弦叠加,得到的是无穷窄谱线,一加短时傅里叶窗就会被抹平,和实测对不上。更常见的做法还是用 Lorentz 线型,在频域精确控制带宽:

S(f) = A * (b/2)^2 / ((f - f0)^2 + (b/2)^2),其中b = f0 / Q

注意线谱频率不是固定的。仿真里要保留“真实感”,可以给每根线谱的中心频率加一个低通滤波后的随机游走,让 LOFAR 图上的竖线带一点缓慢漂移,而不是完全笔直。

2.2 螺旋桨空化的连续谱:谱峰位置与高频滚降

螺旋桨在较高转速下叶梢附近压力降低,水汽化形成空泡,空泡破裂产生大量宽带脉冲,这就是空化噪声。它是舰船辐射噪声连续谱的主要来源,覆盖范围可以从几十赫兹一直延伸到几十千赫兹。空化噪声的典型谱型分三段:低频段谱级随频率上升,中频段到达峰值,高频段以接近f^-2的斜率滚降,折算下来大约是每倍频程下降 6 dB。峰值频率大多落在 100 Hz~1 kHz 之间,航速越快峰值越高、整体谱级越高。

深度影响的是空化起始条件。水深增加,静水压升高,螺旋桨要在更高转速下才开始空化,所以同一条船、同一个航速下,深潜时连续谱级通常低于浅航。工程上常用两个简化趋势:航速每倍增,宽带总声级上升约 6~9 dB;深度每增加一个量级,连续谱级下降若干 dB。整理成表格如下。

频谱成分频域特征关键参数对应物理源
机械线谱离散峰,Q 值 30~100+轴频、叶频、谐波数主机、辅机、齿轮、轴系
空化连续谱带通形状,高频约 f⁻² 滚降峰值频率、滚降斜率、谱级螺旋桨空泡破裂
调制谱包络谱上离散峰叶频、谐波、调制深度叶片周期切割空化区

空化连续谱与实际信号的差别主要在低频段。低速航行时,因船体结构辐射和推进器脉动,低频段往往叠加了 1/f 型能量,谱级并不是单调下降的。仿真时不必追求一个复杂半经验公式,把“上升—峰值—滚降”三段趋势表达清楚,比套一个无法调参的全频带公式更实用。

2.3 叶片周期调制:调制谱和 DEMON 谱的关系

空化噪声的幅度并不平稳。螺旋桨每转一圈,叶片依次扫过相同角度位置,空化强度和辐射条件周期性变化,宽带噪声的包络就被“捏”出周期起伏,这就是螺旋桨调制。包络基频是叶频,通常还带二三次谐波。这个调制在普通功率谱里看不出来,必须用幅度解调后再做谱分析,也就是 DEMON 谱分析。

这里必须分清两个容易混淆的概念:叶频处既可能有一条真正的线谱,也可能有宽带噪声包络的调制峰。前者在时域信号的直接 FFT 功率谱上可见;后者出现在包络的谱分析结果里,两者物理意义完全不同。仿真时线谱和连续谱要分开构造,调制只加在连续谱分量上,否则后续做目标识别特征提取时,会把线谱特征和调制特征搅在一起。

调制深度 m 也不是全频带一致的。空化充分的高频段调制深,低频段调制浅;同一根轴上,带通滤波取不同频带,DEMON 峰的高度会明显不同。这解释了为什么后面验证 DEMON 时要选带通频段,而不是直接分析全频带信号。

3. 用 Python 合成舰船噪声仿真信号:频域构造加 IFFT

3.1 直接构造 PSD 比滤波合成更可控

常见时域合成是白噪声过 FIR/IIR 滤波器成形,好处是实时性高,但舰船线谱带宽窄、Q 值高,滤波器阶数不够时线谱会被明显抹平,调阶数又会拖慢运算。离线仿真更常用的做法是频域法:把目标 PSD 按离散频率点算好,乘随机相位后做 IFFT 得到时域信号。频域法能精确控制每个频点功率,窄带线谱不会因滤波器瞬态失真;换一组随机种子就能得到同谱型的新样本,适合批量生成训练数据。

虽然频域法要一次性做整段傅里叶变换,但 60 秒 20 kHz 采样率的双精度数据不过百万级点数,内存完全不是问题。这个思路和很多舰船噪声仿真资料包里预生成信号的做法一致:先定谱型,再反变换出时域。

3.2 连续谱与线谱的频域构造代码

下面是一个完整可运行的最小实现。连续谱和线谱分别构造 PSD,分别做 IFFT,最后在时域对连续谱叠加调制,再和线谱相加。

import numpy as np def lorentz(f, f0, A, Q): # Lorentz 峰形:A 控制相对强度,Q 控制 3dB 带宽 b = f0 / Q return A * (b / 2) ** 2 / ((f - f0) ** 2 + (b / 2) ** 2) def cont_shape(f, f_low, f_peak, gamma): # 低频以 f^2 上升,越过 f_peak 后按 f^-gamma 滚降 y = (f / f_low) ** 2 / (1 + (f / f_low) ** 2) y *= 1.0 / (1 + (f / f_peak) ** gamma) return y def make_ship_noise(fs=20000, dur=60, rpm=120, blades=5, speed=12, depth=50, amp_cont=1.0, seed=42): rng = np.random.default_rng(seed) nfft = int(fs * dur) freqs = np.fft.rfftfreq(nfft, 1 / fs) # 空化连续谱,归一化后按航速和深度调谱级 psd_cont = cont_shape(freqs, f_low=30, f_peak=400, gamma=2.0) psd_cont /= np.max(psd_cont) psd_cont *= amp_cont psd_cont *= 10 ** (0.1 * ( 20 * np.log10(speed / 10) - 10 * np.log10(1 + depth / 20))) # 线谱:轴频、倍轴频、叶频、倍叶频,另加两条固定工频 shaft_f = rpm / 60.0 blade_f = shaft_f * blades lines = [ (shaft_f, 1.0, 80), (2 * shaft_f, 0.5, 60), (blade_f, 0.8, 50), (2 * blade_f, 0.35, 40), (50.0, 0.4, 100), (100.0, 0.25, 80), ] psd_lines = np.zeros_like(freqs) for f0, A, Q in lines: psd_lines += lorentz(freqs, f0, A, Q) # 线谱和连续谱分别加随机相位、分别 IFFT spec_lines = np.sqrt(psd_lines) * np.exp(1j * rng.uniform(0, 2*np.pi, len(freqs))) sig_lines = np.fft.irfft(spec_lines, n=nfft) spec_cont = np.sqrt(psd_cont) * np.exp(1j * rng.uniform(0, 2*np.pi, len(freqs))) sig_cont = np.fft.irfft(spec_cont, n=nfft) # 对连续谱叠加叶片调制,调制深度随航速增大 t = np.arange(nfft) / fs m = np.clip(0.2 + 0.03 * (speed - 8), 0.2, 0.7) env = 1 + m * np.sin(2 * np.pi * blade_f * t) sig_cont *= env sig = sig_lines + sig_cont sig = sig / (np.max(np.abs(sig)) + 1e-12) return sig, fs, psd_cont, psd_lines, freqs

3.3 代码里每个参数对应什么

cont_shape函数用两个一阶环节组合出带通形状:(f/f_low)^2 / (1 + (f/f_low)^2)让谱级以每倍频程 12 dB 的斜率上升,到 f_low 附近转平;1 / (1 + (f/f_peak)^gamma)在超过 f_peak 后制造滚降,gamma 取 2 就是约 6 dB/oct。实际使用中可以先把f_low设在 20~50 Hz、f_peak设在 300~600 Hz,再根据目标船的实测曲线微调。

航速项的20 * np.log10(speed / 10)表示航速从 10 节升到 20 节时谱级增加约 6 dB,取的是工程经验下界;希望模拟高航速下空化加剧,可以把这个系数改成 25~30。深度项-10 * np.log10(1 + depth / 20)做的是线性水深近似,200 米比 20 米大约低 4.6 dB,和静压升高抑制空化的趋势一致。

线谱部分如果 Q 值低于 30,Lorentz 峰会展得很宽,容易盖住旁边的连续谱;Q 值高于 200 时,一旦nperseg对应的频率分辨率不够,峰又会被窗口抹平。推荐先按表格里的区间试,再对着 LOFAR 图调。调制深度m被限制在 0.2~0.7,8 节时约 0.2,20 节时约 0.56,模拟空化增强后包络起伏变大的趋势。需要更真实时可以加二次谐波:把 env 改成1 + m1*np.sin(2*np.pi*blade_f*t) + m2*np.sin(2*np.pi*2*blade_f*t + phase),m2 一般取 m1 的一半左右。

4. 舰船噪声仿真参数表与 LOFAR/DEMON 验证

4.1 六个最常动的参数与推荐取值

参数调优全部围绕这个表展开,表里给的是大多数中小型舰船的通用水准。

参数推荐取值对频谱和包络谱的影响
采样率 fs20~50 kHz决定最高可分析频率;DEMON 常用 100~3000 Hz 频带
时长 dur30~120 s频率分辨率等于 1/dur,太短低频线谱无法分离
转速 rpm90~200直接决定轴频和叶频位置,影响整个梳状结构
叶片数 blades4~7叶频 = rpm/60 × blades,决定调制基频
航速 speed6~20 kn主控连续谱级,约每倍增 6~9 dB,并增大调制深度
水深 depth10~200 m越深空化越弱,连续谱级越低,线谱相对越突出

4.2 用 Welch PSD 和 LOFAR 谱图验证线谱稳定性

生成信号后第一件事是看功率谱。用 Welch 平均做频谱估计,nperseg 取 4 秒以上,这样 0.25 Hz 的频率分辨率至少能看清 2 Hz 的轴频基波。

from scipy.signal import welch, spectrogram f, psd = welch(sig, fs, nperseg=fs*4, noverlap=fs*2) # 对数坐标看:连续谱包络 + 离散线谱 f_t, t_t, Sxx = spectrogram(sig, fs, nperseg=4096, noverlap=2048) # LOFAR 图横轴时间、纵轴频率、颜色为谱级

LOFAR 图上应该看到两类结构:宽带连续谱作为背景,稳定的窄带线谱作为贯穿全图的细线。轴频和叶频是判断转速设得对不对的直接依据;如果 50 Hz 以下原本该有梳状结构却看不到,先查durnperseg是否够长,再查线谱 Q 值是否被设得过低。

4.3 用 DEMON 谱验证包络调制

普通功率谱无法确认调制是否生效,要用解调分析。常用做法是带通滤波、Hilbert 取包络、再去直流做 Welch 谱:

from scipy.signal import butter, filtfilt, hilbert b, a = butter(4, [100, 3000], btype='band', fs=fs) bp = filtfilt(b, a, sig) env = np.abs(hilbert(bp)) f_d, psd_d = welch(env - env.mean(), fs=fs, nperseg=fs*8) # 在 f_d 约等于轴频、叶频的位置找峰

带通范围不能随意选。低频段调制浅,直接分析全带信号会把 DEMON 峰淹没;100~3000 Hz 是空化噪声占主导的频段,调制深度高,峰最明显。env - env.mean()是为了去掉包络里的直流分量,否则 0 Hz 附近一大团能量会压住低频峰。如果 DEMON 谱上只有轴频没有叶频,先查叶片数是否参与计算;若一个峰都没有,大概率调制 m 为 0 或调制被加到了线谱分量上。

4.4 三个典型问题与修正

  • 线谱在 LOFAR 图上完全笔直。实测中主机转速有慢漂移,笔直线谱反而不真实。给每条线谱中心频率叠加一个低通随机游走,频偏控制在 ±1% 内,Q 值不变。
  • 线谱找得到位置但幅度比连续谱低太多。Lorentz 的 A 参数和psd_cont不在同一量纲体系,需要先对连续谱归一化,再用“线谱峰值高出连续谱 5~20 dB”这个经验值去对齐。不要直接沿用代码里的相对值。
  • DEMON 谱分辨率不够。舰船轴频只有几赫兹,调制谱峰挨得很近。nperseg=fs*8起步,不够就加时长和窗长,否则叶频和轴频峰重叠分不开。

5. 用 1/3 倍频程谱级和宽带总声级做仿真信号出厂校验

5.1 由 Welch PSD 计算 1/3 倍频程谱级

功率谱和 LOFAR 确认的是“细节像不像”,交付前还要确认“总体能量分布像不像”。声学工程里最常用的总体指标是 1/3 倍频程谱级,它把连续谱和线谱积分到固定频带里,便于和实测报告直接对比。实现如下:

def third_oct_levels(freqs, psd, ref=1.0): fcs = 1000 * (2 ** (np.arange(-16, 8) / 3.0)) levels = [] valid = [] for fc in fcs: f1 = fc * 2 ** (-1/6) f2 = fc * 2 ** (1/6) idx = (freqs >= f1) & (freqs < f2) if idx.sum() > 0: levels.append(10 * np.log10(np.trapz(psd[idx], freqs[idx]) / ref)) valid.append(fc) return np.array(valid), np.array(levels) f_c, lev = third_oct_levels(f, psd) # 画半对数曲线,横轴中心频率,纵轴谱级

各频带内 PSF 已经由 Welch 得到,np.trapz按实际频率间隔做积分,结果就是该频带的声压级。对比实测曲线时重点看两点:峰值频带是否在同一 1/3 倍频程内;高频段滚降的斜率是否一致。若中频出现凹陷或高频段比实测陡太多,优先怀疑f_peakgamma设置。

5.2 宽带总声级随航速斜率检查

把同一组参数在不同航速下各生成 30 秒以上信号,计算宽带总声级随航速的变化,这也是一个体面的自检:

def broadband_level(sig, fs): ff, pp = welch(sig, fs, nperseg=int(fs*2)) return 10 * np.log10(np.trapz(pp, ff)) for sp in [6, 10, 16, 20]: s, _, _, _, _ = make_ship_noise(speed=sp, depth=50) print(sp, broadband_level(s, fs))

按经验,航速每倍增总声级应上升约 6~9 dB,如果拟合斜率低于 5 dB,说明连续谱的航速项20 * np.log10(speed / 10)权重不够;高于 10 dB 则要反过来降权重。深度不变时低频线谱带走的能量基本固定,斜率主要由空化连续谱贡献,这个指标也能顺带检查调制是否把宽带能量过度分散到包络频带上。数值曲线和实测值对不上时,优先微调f_peak和航速系数,不要先动线谱位置。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询