
如果你路过轨道交通研发基地的试验大厅看到有同事在“列车靶场”里循环播放某首歌不要觉得那是在摸鱼。那大概率不是娱乐而是一次车载广播系统的声学验证。列车靶场是轨道交通研发领域对半实物仿真测试环境的通俗叫法和网络安全里的“攻防靶场”逻辑类似在一个可控、可复现的环境里对目标系统进行接近真实工况的测试。把音乐送进列车广播系统听起来很简单背后要验证的其实是音频链路完整性、声场覆盖效果、紧急广播优先级切换以及功放和扬声器在动态音乐信号下的真实表现。这篇文章就把这件事讲透在列车靶场上放音乐到底在放什么、为什么要放、怎么放才能拿到有价值的测试结果以及哪些坑最容易踩。文章会从测试信号原理、环境搭建、测试流程、代码示例到问题排查逐步展开适合轨道交通行业软件测试工程师、PIS系统集成工程师以及所有对车载音频测试感兴趣的开发者阅读。1. 这篇文章真正要解决的问题先说一个常见误区很多人以为在车厢里放音乐就是把音源接上功放听个响能出声就算通过。如果只是这种粒度根本不需要专门搭一个列车靶场。真正要解决的问题有三个层面。第一验证音频链路的完整性。列车广播系统不是一台普通音响它包含音源设备、编码模块、网络传输、功放、扬声器、紧急广播联动等多个环节。任何一个环节故障都可能表现为“有声音但声音不对”或者“有些位置有声音有些位置没有”。第二验证声场覆盖和听感效果。车厢是一个狭长、多反射面的声学空间扬声器的布局、功放功率、音量设置都会影响真实听感。音乐信号因为频谱复杂、动态范围大比单纯的正弦波更容易暴露声场问题。第三验证紧急广播的优先级和打断逻辑。在轨道交通的PIS系统中紧急广播必须能够打断或覆盖背景音乐。这个逻辑如果只靠模拟信号测试很难暴露问题。用真实的音乐流做背景再切入紧急广播才能验证系统的优先级处理是否符合要求。所以在列车靶场上放音乐的本质不是“试听”而是用高动态、宽频谱的复合音频信号对车载广播系统做一次接近真实使用场景的压力验证。2. 列车靶场与车载广播系统先理解测试对象在展开操作之前有必要把几个概念讲清楚否则后面看测试流程容易发晕。2.1 列车靶场是什么“靶场”这个词在轨道交通行业里并没有严格的教科书定义但研发和测试团队经常用它指代那类专门用于系统级验证的试验环境。它的核心特点是环境可控温度、供电、负载都可以按测试需求调整。可复现同一个测试用例可以反复执行结果可以对比。接近真实车辆的网络拓扑、电源环境、设备安装位置尽可能与量产车一致。便于排查所有接口都有测试点出了问题可以快速定位。在列车靶场里你可以把一套完整的PIS系统装上台架接上真实的功放和扬声器模拟列车运行时的各种工况然后在驾驶台或者控制中心触发广播观察整条链路的表现。2.2 车载广播系统在列车里的位置车载广播系统通常属于乘客信息系统的一部分也叫PIS系统。它负责的事情包括到站自动广播司机对乘客的临时广播紧急广播背景音乐播放与车门、火灾报警等系统的联动从音频信号流的角度看一条典型的链路是音源背景音乐文件 / 麦克风 / 紧急广播音频 → 广播控制主机 → 音频编码与分发 → 功率放大器 → 车厢扬声器在这个链路里背景音乐属于相对低优先级的音源而紧急广播拥有最高优先级。测试时需要通过真实的打断操作来确认系统会从“音乐播放状态”切到“紧急广播状态”并在一段时间后能正确恢复。2.3 为什么选音乐而不是只选提示音如果只是为了验证链路通不通用一段“叮咚”提示音就够了。但工程测试需要更严苛的信号。音乐信号的特点是频谱覆盖范围宽、动态范围大、包含瞬态冲击。一首歌里往往同时有低频鼓点、中频人声、高频镲片这些成分叠加在一起对功放的峰值功率、扬声器的失真表现、系统的底噪控制都会形成比单频信号更真实的考验。所以测试团队在车上放音乐本质上是在做“复合信号激励下的系统稳定性验证”。3. 测试信号选择标准信号与音乐信号如何配合在音频测试中标准信号和音乐信号各有各的用途正确做法是配合使用而不是只放音乐。3.1 标准测试信号标准测试信号包括正弦扫频、白噪声、粉红噪声等。它们的特点是频谱成分明确、可重复、便于量化分析。正弦扫频信号频率从低到高连续变化适合测试系统在某个频段是否出现异常谐振或衰减。白噪声功率谱密度在整个频带上基本平坦适合快速检查系统是否存在频响突变。粉红噪声低频能量更多更接近实际听感适合做声压级标定和声场均匀性测试。标准信号的缺点是“太干净”。它们在频域上虽然覆盖全面但在时间域上没有音乐那种突发冲击很难让功放瞬间进入大动态工作状态。3.2 音乐测试信号音乐信号最大的价值是能够同时覆盖“客观指标”和“主观听感”两个维度。从客观角度看音乐信号中的低频峰值可以检验功放在大功率输出时的稳定性高频成分可以检验扬声器是否出现明显衰减人声部分可以检验中频的清晰度。从主观角度看最终乘客听到的就是音乐和广播声。如果测试团队在车间里用耳朵听都觉得声音发闷、发破、发虚那么上车之后效果大概率也不会好。3.3 两者如何配合实际项目中更推荐这种配合方式先用粉红噪声做声压级标定和扬声器一致性检查。再用扫频正弦查找明显的频响异常。最后用音乐片段做整链路的动态验证和主观听感评估。紧急广播测试则单独使用语音广播信号验证优先级和清晰度。只有音乐信号缺了量化指标问题不好定位只有标准信号缺了真实听感问题不好还原。两条腿走路才是工程化的做法。4. 环境准备与测试设备在列车靶场上做音频测试环境准备比想象中复杂。下面列出一个最小可行环境供参考。4.1 硬件环境被测的广播控制主机或PIS系统样机。功率放大器连接方式尽量与量产车一致。扬声器最好安装在台架的模拟车厢结构上或者使用同等规格的扬声器负载。参考麦克风用于采集扬声器输出的声音信号。声级计用于现场声压级测量。音频接口或USB声卡用于将测试电脑的音频信号送入广播主机同时采集参考麦克风信号。测试电脑用于播放测试音频和录制回采信号。4.2 软件环境以本文的Python示例为例建议环境如下Python 3.9 及以上版本。numpy、scipy用于信号生成和分析。sounddevice用于音频播放与录制。wave、struct用于读写WAV文件。ffmpeg用于音频格式转换和简单的文件检查。安装命令pip install numpy scipy sounddevice# 检查Python音频设备 python -m sounddevice执行后终端会列出当前系统的音频输入输出设备编号后面写脚本时要用。4.3 测试前的检查清单在接好设备之后先不要急着播放音乐。按下面的清单检查一遍功放增益是否设置合理有没有开到最大。扬声器接线是否牢固有没有反相。参考麦克风位置是否避开了气流和结构振动。紧急广播触发按钮是否在方便操作的位置。测试电脑音量是否设置在安全的范围内。这一步省不得。很多测试过程中出现的“破音”和“听不清”其实都是接错线、参数设置不当导致的不是被测系统本身的问题。5. 核心测试流程拆解下面给出一个在列车靶场进行音乐播放测试的通用流程每个环节都说明目的和容易出错的地方。5.1 明确测试目标和边界开始之前先问自己三个问题这次测试是为了验证链路是否正常还是为了评估音质是针对某一节车厢还是全列车的广播系统需不需要同时测试紧急广播的打断逻辑目标不同测试音频的选择、播放时长、采集位置都会不一样。如果只是验证链路播放20秒音乐足够如果要做声场均匀性评估可能需要在多个位置分别测量。5.2 准备测试音频文件准备音频文件时要遵循几个原则使用WAV格式避免压缩格式解压带来的不确定性。文件时长控制在30秒到2分钟之间太长影响测试效率太短不利于主观判断。文件内同时包含低频、中频、高频内容尽量选择动态范围大的片段。不要直接使用带DRM保护的在线音乐避免播放环节引入额外变量。如果项目中需要可重复的测试样本建议用程序生成标准信号并混入一段固定音乐作为合成测试样本这样每次测试的输入都是一致的。5.3 接入音频源并播放音频接入方式取决于广播主机的接口。常见的有模拟音频输入、网络音频流、USB播放。推荐优先使用与量产车一致的接入方式避免引入不必要的变量。播放时建议从较低音量开始逐步升到目标音量。注意观察功放的CLIP指示灯或保护状态如果出现频繁的保护动作应该立即停止检查功放和扬声器的配置是否匹配。5.4 同步采集与记录如果测试目标是验证链路完整性建议用参考麦克风同步采集扬声器输出。这样后续可以通过对比原始文件和回采文件判断系统是否存在明显失真、延迟或频响异常。同步采集时注意声道数要与测试信号一致。采样率建议不低于44100 Hz。录音电平不要出现过载否则回采数据本身就失真了。5.5 记录主观听感客观数据不能完全替代人的耳朵。每次测试时至少安排一名测试人员在车厢内的不同位置试听并记录以下内容声音是否清晰有没有破音。中频人声是否自然。高频会不会刺耳。低频有没有明显共振。车厢前中后位置的音量差异是否在可接受范围。主观记录可以用简单的表格也可以录一段现场语音备注。5.6 恢复系统并归档数据测试结束后要将系统恢复到测试前状态包括音量、优先级配置、功放增益等。然后保存原始音频、回采音频、测试记录到统一的归档目录方便版本回溯。6. 完整示例从生成测试音频到自动化验证下面用Python写一套最小可用的音频测试脚本。它包含三个部分生成测试音频、播放并同步录制、回采分析。6.1 生成标准测试音频这个脚本会生成两个文件一个是对数扫频正弦一个是频域法生成的粉红噪声。它们可以作为客观指标测试的输入信号。# 文件路径generate_test_audio.py import numpy as np import wave def write_wav(path, data, sample_rate): data np.clip(data, -1.0, 1.0) pcm (data * 32767).astype(np.int16) with wave.open(path, wb) as wf: wf.setnchannels(1) wf.setsampwidth(2) wf.setframerate(sample_rate) wf.writeframes(pcm.tobytes()) def log_sweep(f0, f1, duration, sample_rate): n int(sample_rate * duration) t np.linspace(0, duration, n, endpointFalse) phase 2 * np.pi * f0 * duration / np.log(f1 / f0) * ( np.exp(t / duration * np.log(f1 / f0)) - 1 ) return np.sin(phase) def pink_noise_fd(duration, sample_rate): n int(sample_rate * duration) spectrum np.random.randn(n // 2 1) 1j * np.random.randn(n // 2 1) freqs np.fft.rfftfreq(n, d1.0 / sample_rate) freqs[0] 1.0 spectrum spectrum / np.sqrt(freqs) spectrum[0] 0.0 sig np.fft.irfft(spectrum, n) return sig / np.max(np.abs(sig)) * 0.5 sample_rate 48000 duration 30 sweep log_sweep(20, 20000, duration, sample_rate) pink pink_noise_fd(duration, sample_rate) write_wav(sweep_20_20k.wav, sweep, sample_rate) write_wav(pink_noise_30s.wav, pink, sample_rate) print(生成测试音频完成)关键点解释对数扫频让每个倍频程的持续时间相同适合检查频响异常。粉红噪声用频域法生成功率谱密度近似1/f更接近真实听感。输出统一为单声道WAV避免多声道文件在回放时出现配置问题。运行方式python generate_test_audio.py生成成功后应该能在当前目录看到两个WAV文件。6.2 播放并同步录制下面这段脚本负责播放测试音频同时通过参考麦克风采集扬声器的输出。使用sounddevice的playrec函数可以做到播放和录制的同步。# 文件路径play_and_record.py import sounddevice as sd import numpy as np import wave def read_wav(path): with wave.open(path, rb) as wf: sample_rate wf.getframerate() data np.frombuffer(wf.readframes(wf.getnframes()), dtypenp.int16) data data.astype(np.float32) / 32768.0 return data, sample_rate def write_wav(path, data, sample_rate): data np.clip(data, -1.0, 1.0) pcm (data * 32767).astype(np.int16) with wave.open(path, wb) as wf: wf.setnchannels(1) wf.setsampwidth(2) wf.setframerate(sample_rate) wf.writeframes(pcm.tobytes()) AUDIO_FILE pink_noise_30s.wav OUTPUT_FILE recorded_output.wav INPUT_DEVICE None # 参考麦克风设备编号先用默认设备 OUTPUT_DEVICE None # 输出设备编号可以用默认设备 audio_data, sample_rate read_wav(AUDIO_FILE) recorded sd.playrec( audio_data, sampleratesample_rate, channels1, input_device_indexINPUT_DEVICE, output_device_indexOUTPUT_DEVICE, ) sd.wait() write_wav(OUTPUT_FILE, recorded[:, 0], sample_rate) print(播放和录制完成输出文件, OUTPUT_FILE)运行前需要先通过python -m sounddevice查看设备编号。测试环境的参考麦克风通常通过USB音频接口接入建议单独指定输入设备编号。这里的“同步”是声音层面的同步播放音频的同时开始录音。最终得到的回采文件在时间轴上对应扬声器输出这段音频的声学信号。6.3 回采分析检测削波和粗略频谱回采数据的主要用途有两个判断系统是否削波失真以及判断频响是否存在明显异常。# 文件路径analyze_recording.py import numpy as np import wave def read_wav(path): with wave.open(path, rb) as wf: sample_rate wf.getframerate() data np.frombuffer(wf.readframes(wf.getnframes()), dtypenp.int16) data data.astype(np.float32) / 32768.0 return data, sample_rate def detect_clipping(signal, threshold0.98): peak np.max(np.abs(signal)) clipped peak threshold return peak, clipped def rms_db(signal): rms np.sqrt(np.mean(signal ** 2) 1e-12) return 20 * np.log10(rms 1e-12) RECORD_FILE recorded_output.wav signal, sr read_wav(RECORD_FILE) peak, clipped detect_clipping(signal) rms_db_val rms_db(signal) print(峰值{:.3f}.format(peak)) print(RMS{:.2f} dBFS.format(rms_db_val)) print(是否接近削波{}.format(是 if clipped else 否)) # 粗略频谱检查用FFT计算平均频谱观察低频段和高频段的能量比例 n len(signal) window np.hanning(n) spectrum np.abs(np.fft.rfft(signal * window)) freqs np.fft.rfftfreq(n, d1.0 / sr) def band_energy(spectrum, freqs, f_low, f_high): mask (freqs f_low) (freqs f_high) return np.sqrt(np.mean(spectrum[mask] ** 2)) low_energy band_energy(spectrum, freqs, 100, 1000) mid_energy band_energy(spectrum, freqs, 1000, 4000) high_energy band_energy(spectrum, freqs, 4000, 12000) print(低频能量{:.3f}.format(low_energy)) print(中频能量{:.3f}.format(mid_energy)) print(高频能量{:.3f}.format(high_energy))这段脚本的价值在于把测试者的耳朵变成可量化的数据。如果一个扬声器在高频段明显衰减high_energy数值会比同型号正常扬声器低很多。如果功放增益设置过高peak值会接近1.0此时就需要考虑降低音量后重新测试。6.4 用ffmpeg做文件检查在播放之前可以用ffmpeg快速确认测试文件没有损坏ffprobe -show_streams -show_format sweep_20_20k.wav如果只需要简单查看时长和格式也可以这样ffprobe -v error -show_entries formatduration:streamcodec_name,sample_rate -of defaultnoprint_wrappers1 sweep_20_20k.wav7. 运行结果与效果验证7.1 如何判断测试音频生成成功运行generate_test_audio.py之后脚本会打印“生成测试音频完成”。更稳妥的验证方式是用播放器打开文件听一下扫频的声音是否从低频平滑过渡到高频粉红噪声是否听起来像持续的“沙沙”声。7.2 如何判断播放和录制链路正常录制完成后先把recorded_output.wav和原始文件简单对比一下。如果录制结果明显偏小或者出现大片削波说明测试系统的电平设置有问题。一个简单的判断方法是看分析脚本的输出检查项正常结果异常结果录制峰值0.3 到 0.9 之间接近1.0说明可能削波录制RMS明显大于0且没有满幅接近0说明信号未采集到频谱能量低中高频段都有能量某个频段接近0需要排查7.3 如何验证紧急广播优先级在播放背景音乐的状态下触发一次紧急广播。需要观察以下几点背景音乐是否被立即切断或明显压低。紧急广播语音是否清晰可懂。紧急广播结束后系统是否按设计恢复背景音乐播放。整个过程中功放是否出现保护动作。这个测试建议至少做三轮音乐正常播放时触发。音乐音量较高时触发。音乐播放和广播操作几乎同时发生时触发。三种情况的时序不同最容易暴露代码里的竞态问题。7.4 测试结论的记录每次测试完建议记录一份结构化的结论至少包含被测系统软件版本。测试音频文件名。功放增益设置。参考麦克风位置。主观听感描述。客观数据峰值、RMS、频段能量。这些信息是后续问题回溯的基础。8. 常见问题与排查思路在列车靶场上做音频测试遇到的问题通常集中在几个区域电平设置、接线方式、扬声器布局、系统优先级逻辑。问题现象可能原因排查方式解决方案播放音乐时扬声器明显破音功放增益过高输出削波查看功放CLIP指示灯检查录制数据峰值降低功放增益留出6dB以上峰值余量车厢后部听不清楚广播声扬声器布局不均或声压级不足在车厢前中后位置分别用声级计测量调整扬声器音量、增加延时或调整扬声器朝向紧急广播无法打断背景音乐音源优先级配置错误查看广播主机优先级配置表重新配置音源优先级紧急广播设为最高优先级录制信号底噪很大接地环路或线缆屏蔽不良断开部分线缆逐一排查使用平衡音频线检查接地避免信号线与电源线并行播放音乐时出现明显延迟网络音频编解码存在缓冲对比原始文件和回采文件的起始时间调整音频缓冲参数检查网络时延功放频繁进入保护状态扬声器负载与功放功率不匹配检查扬声器阻抗和功放输出规格更换匹配的功放或降低测试音量声音一会大一会小音源动态范围过大或自动增益开启检查广播主机是否有AGC设置关闭不必要的自动增益或使用压缩处理后的测试音频这里真正容易踩坑的地方是很多人遇到破音第一反应是换更好的扬声器但更多时候问题出在功放电平设置上。换设备之前先用脚本采集数据确认是不是削波再决定从哪个环节下手。9. 最佳实践与工程建议9.1 把测试当作产品来做一个可重复的音频测试方案不应该依赖某个人“听了一下觉得没问题”。建议把测试音频、播放脚本、分析脚本、测试记录模板都纳入版本管理每次软硬件版本变更之后跑同一套流程对比数据变化。9.2 标准信号和音乐信号分开归档标准信号用于量化对比音乐信号用于主观听感。两者不要混为一谈。归档时建议建立以下目录audio_test/ case/ generate_test_audio.py signals/ sweep_20_20k.wav pink_noise_30s.wav music_sample_a.wav results/ 20250120_ai_build/ recorded_output.wav test_log.md这样的目录结构在项目后期回溯问题时非常有用。9.3 注意紧急广播测试的安全边界紧急广播属于安全相关功能测试时必须在授权环境下进行。在运营线路上随意播放背景音乐或触发紧急广播会造成严重的运营风险。所有测试都应限定在靶场台架或下线车辆上进行并且测试前要确认系统没有接入真实运营网络。9.4 音量标准不要拍脑袋每套车辆技术规范对背景音乐声压级、广播声压级、最大声压级都有具体约定。测试之前先查阅对应车型的技术规范按规范值设定音量而不是凭感觉调到“听着合适”。这样做出来的测试结果才有验收价值。9.5 回采麦克风的位置要固定如果每次测试的麦克风位置不固定回采数据之间就没有可比性。建议在车厢内选择固定的测量点并记录距离地板、侧墙的相对位置。9.6 自动化是未来方向当测试用例数量增加后手动播放和录制会变得繁琐。可以考虑用Python脚本把“生成音频—播放—录制—分析—生成报告”串成一个测试任务接入实验室的自动化测试框架在每次版本构建后自动执行。10. 总结与后续学习方向回到开头的问题在列车靶场上放音乐到底在做什么答案不是“放歌”而是通过高动态、宽频谱的音乐信号对车载广播系统的音频链路、声场覆盖、紧急广播优先级做一次接近真实使用场景的验证。这套流程的价值在于把主观的“听感”和客观的“数据”结合起来既能快速发现问题又能定位问题。如果你想继续深入建议按下面的顺序学习先熟悉信号处理基础FFT、频谱、滤波、声压级计算。再理解PIS系统架构音源如何接入、优先级如何控制、广播如何分发。然后动手写自动化测试脚本把今天的示例扩展成完整的测试工具。最后接触声学测量标准了解声场均匀性、语音可懂度等工程指标。下次再看到有人在列车靶场里放音乐不妨多看一眼测试台架上的声压计读数。那才是这件事真正值得关注的地方。