1. 水声信号处理与Python环境搭建

水声信号处理是研究声波在水中产生、传播、接收与信息提取的技术学科。它的核心任务,是把水听器或声呐基阵采集到的原始电信号,经过放大、滤波、采样、变换与检测,最终转化为可判读的目标信息——目标是否存在、方位多少、距离多远、速度几何、属于哪一类。与雷达在电磁介质中工作不同,水声信道是一个带宽有限、传播损失大、多途严重、环境噪声复杂的信道,因此水声信号处理在算法设计上更依赖对信道特性的建模与对噪声统计特性的估计。

从信号链角度看,一次完整的水声处理流程通常包含:换能器接收 → 前置放大与调理 → 抗混叠滤波 → A/D采样 → 数字滤波与波束形成 → 频谱/时频分析 → 检测与参数估计 → 目标识别与显示。本课程后续章节将围绕这条链路逐步展开,而本章要解决的是最基础也最关键的一步:把处理工具准备好,并跑通第一个可复现的信号生成与绘图任务。

典型应用场景

水声信号处理的应用面很宽,理解场景有助于后续选择算法。常见方向包括:被动声呐探测,通过分析目标辐射噪声的连续谱与线谱特征判断目标存在;主动声呐回波处理,利用匹配滤波(相关处理)在噪声背景中提取回波时延,进而换算距离;水下目标方位估计,用线列阵或圆阵做波束形成,通过空间谱峰值确定来波方向;水声通信,在强多途、大多普勒的信道中完成均衡与解调;海洋环境噪声监测与舰船辐射噪声分析,用于航道监测与目标分类。这些场景的共同点是:输入都是时间序列(或多通道时间序列),输出都是统计量、谱、时频图或检测判决。

Python科学计算生态

本课程选用Python,原因在于其科学计算栈完整覆盖了水声处理的全部需求。NumPy提供ndarray多维数组与向量化运算,是采样序列、矩阵运算、FFT的基础;SciPy的scipy.signal提供滤波器设计(butter、cheby1)、卷积与相关(convolve、correlate)、重采样与谱估计(welch)等直接对应水声算法的函数;Matplotlib负责时域波形、频谱、语谱图(specgram)与波束图的绘制。三者构成“数据—算法—可视化”的闭环。

推荐使用Anaconda或Miniconda创建独立环境,避免包版本冲突。安装命令如下:

conda create -n underwater python=3.11 -y
conda activate underwater
conda install numpy scipy matplotlib jupyter -y
# 或使用 pip
pip install numpy scipy matplotlib jupyter

安装完成后应验证版本与基本功能:

import numpy as np, scipy, matplotlib
print(np.__version__, scipy.__version__, matplotlib.__version__)
print(np.fft.fft(np.ones(8)))   # 应输出 [8.+0.j 0.+0.j ...]

若在无图形界面的服务器上绘图,需将后端设为Agg:在脚本开头加import matplotlib; matplotlib.use("Agg"),否则可能报显示错误。中文字体缺失时,可设置plt.rcParams["font.sans-serif"]=["SimHei"]与plt.rcParams["axes.unicode_minus"]=False。

Jupyter Notebook使用要点

Jupyter适合边写边看结果,尤其适合信号处理这类“改一个参数、立刻看图”的工作。启动方式为在终端执行jupyter notebook,浏览器打开后新建Python 3笔记本。几个实用习惯:用%matplotlib inline让图内嵌显示;用%timeit快速比较两种实现耗时;把采样率、脉宽、信噪比等参数集中写在首个单元格,便于整篇重跑;绘图后调用plt.tight_layout()避免标签被裁切。注意Notebook中变量常驻内存,修改参数后应重新执行相关单元格,避免用到旧变量。

第一个水声信号生成与绘图任务

下面构造一个教学示例:模拟主动声呐发射的线性调频(LFM)脉冲,叠加高斯白噪声,并观察其时域波形与频谱。参数为合理假设:采样率fs=48000 Hz,脉宽T=0.02 s,带宽B=8000 Hz,中心频率f0=12000 Hz,信噪比约0 dB。

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

fs, T, B, f0 = 48000, 0.02, 8000, 12000
t = np.arange(int(fs*T)) / fs
# 线性调频:瞬时频率从 f0-B/2 线性升到 f0+B/2
k = B / T
phase = 2*np.pi*((f0 - B/2)*t + 0.5*k*t**2)
s = np.cos(phase)
# 加高斯白噪声,按目标信噪比定标
rng = np.random.default_rng(0)
noise = rng.normal(0, 1, s.size)
noise *= np.sqrt(np.mean(s**2) / 10**(0/10)) / np.std(noise)
x = s + noise

fig, ax = plt.subplots(2, 1, figsize=(8, 5))
ax[0].plot(t*1000, x, lw=0.8); ax[0].set_xlabel("时间 / ms")
ax[0].set_ylabel("幅度"); ax[0].set_title("含噪LFM回波(示例)")
f, P = signal.welch(x, fs, nperseg=1024)
ax[1].plot(f/1000, 10*np.log10(P+1e-12)); ax[1].set_xlabel("频率 / kHz")
ax[1].set_ylabel("功率谱 / dB"); ax[1].set_title("Welch功率谱(示例)")
plt.tight_layout(); plt.show()

结果判读:时域上应看到一段约20 ms的振荡包络,被噪声明显污染;功率谱应在约8~16 kHz区间形成平台状隆起,峰值中心接近12 kHz,这正是LFM带宽B的体现。若谱峰位置明显偏离,应检查k与f0的定义是否一致;若时域完全看不出信号,多半是噪声定标公式写错或信噪比设得过低。这个任务虽小,却完整走通了“参数定义—信号建模—噪声叠加—谱估计—图形判读”的闭环,后续的匹配滤波、波束形成都将在此基础上扩展。

水声信号处理链路与Python工具映射 换能器接收 声→电 放大与调理 抗混叠滤波 A/D采样 fs=48 kHz 数字滤波 带通/去噪 波束形成 方位估计 检测 判决 Python科学计算生态对应关系 NumPy ndarray / 向量化 np.fft 频谱计算 SciPy.signal butter / correlate welch / spectrogram Matplotlib plot / specgram 时域·频域·时频图 示例:LFM脉冲(fs=48 kHz, T=20 ms, B=8 kHz, f0=12 kHz) t=0 t=20 ms 8 kHz 16 kHz 频率 / kHz

环境搭好、第一个信号跑通之后,后续所有算法都可以在同一套参数体系下迭代验证。建议把本章的示例代码保存为ch01_demo.ipynb,作为整门课程的可运行基线。