题目这是我困惑比较久的问题,最近看了几个论文,再重写一下,另外感觉人这个信号与系统设计的还是比较有意思的。
播放白噪声并没有让环境噪声真的变小;它通过“掩蔽效应 + 动态范围重分配 + 预测性削弱”让我们的的大脑感知到的对比度下降,于是主观感觉更安静。
假设环境中有:空调声(低频),键盘敲击(中频),远处说话(随机频率);这些声音都是“非平稳”的,有突发变化。
当播放白噪声:
总声压:
环境声的“相对起伏”变小:
对比度
底噪提高了,但波动幅度相对变小,大脑更敏感的是变化而不是绝对值。耳蜗 + 听神经对:突发变化,调制,瞬态极其敏感;白噪声是统计平稳的:没有可预测结构,没有突变特征,因此它“占据频带”但不触发警觉。
在听觉科学里有一个重要概念:
Masking(掩蔽)
如果一个频段已经有噪声能量,另一个较小声音会被听觉阈值覆盖。
掩蔽阈值:
环境小噪声低于阈值 → 大脑忽略,这在 MP3 编码里广泛利用。
当我们持续听白噪声:听神经放电率适应,大脑预测模型认为“这是背景”,皮层抑制增强,神经系统降低对它的响应;但突发的环境噪声若被白噪声覆盖,就更难触发“变化检测”,人脑主观“安静”并不等于“能量低”。
它更接近:
安静感低可检测变化
当环境是:
滴答——空调——脚步——说话
这些变化不断刺激。
加入白噪声后:
~~~~~~滴答~~~~脚步~~~~
滴答的对比度下降,大脑不再不断触发警觉;大脑对“不可预测变化”敏感,白噪声是完全不可预测但统计稳定的。
预测模型很快认为:
这是常态,不需要响应。
但突发环境声被掩蔽。所以更容易入睡。
环境里有“结构化噪声”(嗡嗡声 + 突发点击),当加入白噪声后:整体 RMS(能量)变大(物理上更“吵”),但环境噪声的“突发/结构”在时间与频率上都被掩蔽,所以主观感觉“更安静”。



橙色(mix)整体更高,说明 声压能量确实变大;但橙色的“峰-谷差”变小:说明 突发变化被淹没,大脑更敏感的是“变化”,不是绝对 RMS,所以主观更安静。

({(0, 200): np.float64(1.3109000256884267),
(200, 800): np.float64(622984448.0573497),
(800, 1500): np.float64(7952438578190.224)},
{(0, 200): np.float64(0.7866683487914412),
(200, 800): np.float64(1.635405155778864),
(800, 1500): np.float64(1.7369150824489732)})
看最后这个图用了一个很粗但直观的指标:
:能量时间序列的 95 分位(代表“突发时更大”)
:50 分位(代表“背景底”)
加白噪声后,背景底 被抬高,而突发并没有同比例增加,于是 contrast 掉下来,这就对应“听起来突发没那么明显”。
解读四个图的作用:
其实就是和我们的嗅觉差不多,你闻到一个味道一开始有很强的感觉,但是过段时间就闻不到了。
当一个持续声音存在时:听神经刚开始发放频率很高,几百毫秒后发放率下降,进入稳态
这叫:
firing rate adaptation(发放率适应)
设神经元发放率:
输入声音强度:
适应变量:
模型:
r 是当前响应,a 是慢变量(适应);当 r 增大,a 逐渐增大,a 抑制 r。
白噪声持续存在:r 初始高,a 慢慢上升,最终 r 被压低;于是:
大脑对持续噪声的响应降低。
但如果有突发声音:s 突然升高,r 突然大于 a,产生瞬时响应。
很多感觉系统接近高通结构,可以用差分模型近似:
频域:
低频:
说明:
对低频成分抑制,对变化敏感。
白噪声是统计平稳的,长期均值稳定 → 被削弱。
当然了大脑不是简单滤波器,它在做:
如果一个声音是稳定的:大脑内部模型预测它,预测误差趋近 0,神经响应下降;白噪声虽然随机,但统计结构稳定:均值恒定,功率恒定,无显著模式变化;预测模型很快把它视为“背景”。环境噪声通常有周期结构,有节律,有调制;例如说话声:有 4–8 Hz 调制,有音节结构
这些结构:不符合白噪声统计,会产生预测误差,更容易引起注意。
输入:
神经响应:
适应:
预测误差:
预测更新:
白噪声时: 迅速学习统计结构,e 减小,r 减小;突发事件时:e 突然大,r 增大,引发警觉。
白噪声让神经系统进入“适应稳态”,环境噪声被淹没后:
预测误差减少,变化检测减弱,于是主观更安静。

刚开始响应很高(瞬时反应),很快下降到一个稳定水平,后续对白噪声只保持低幅波动;这说明:神经元初始检测到“有声音”,慢变量 a(t) 上升,抑制 r(t),进入稳态。
数学上就是:
这就是:
背景噪声被神经系统“解释掉”。

在 2 秒处出现强烈峰值,背景响应几乎被压低,突发结束后迅速恢复;背景白噪声已经被适应机制抑制,突发刺激 s 突然远大于 a,产生巨大误差信号,r(t) 强烈上升;这正是“注意被抓住”的神经基础。
这个系统等价于:输入 → 高通滤波 + 自适应基线 → 输;白噪声:高频随机,均值稳定,等着神经系统基线学会它,而突发现象是违反基线被突出。
为什么白噪声助眠?因为:它稳定,它可预测(统计上),适应后神经响应低,掩蔽了突发环境声,结果就是:
大脑的“变化检测回路”安静下来。
而且白噪声没有让世界变安静,它只是:
把环境噪声变成了统计平稳背景, 降低了大脑对“变化”的敏感度。
# 神经适应模型仿真:白噪声 vs 突发声
# 使用简单的双状态模型:
# dr/dt = (-r + relu(s - a)) / tau_r
# da/dt = (-a + beta * r) / tau_a
import numpy as np
import matplotlib.pyplot as plt
# --------------------------
# 仿真参数
# --------------------------
dt = 0.001
T = 5.0
t = np.arange(0, T, dt)
tau_r = 0.02 # 快响应时间常数(20 ms)
tau_a = 0.5 # 慢适应时间常数(500 ms)
beta = 0.8
rng = np.random.default_rng(0)
# --------------------------
# 输入1:持续白噪声
# --------------------------
white_noise = 0.5 + 0.3 * rng.normal(size=len(t))
# --------------------------
# 输入2:白噪声 + 突发脉冲
# --------------------------
burst = np.zeros_like(t)
burst_start = int(2.0 / dt)
burst_end = int(2.2 / dt)
burst[burst_start:burst_end] = 2.0
stim_burst = white_noise + burst
# --------------------------
# 神经动力学函数
# --------------------------
def simulate(stim):
r = np.zeros_like(stim)
a = np.zeros_like(stim)
for i in range(1, len(stim)):
input_effective = max(stim[i] - a[i-1], 0) # ReLU
dr = (-r[i-1] + input_effective) / tau_r
da = (-a[i-1] + beta * r[i-1]) / tau_a
r[i] = r[i-1] + dt * dr
a[i] = a[i-1] + dt * da
return r, a
# 运行仿真
r_white, a_white = simulate(white_noise)
r_burst, a_burst = simulate(stim_burst)
# --------------------------
# 绘图 1:白噪声输入与神经响应
# --------------------------
plt.figure()
plt.plot(t, white_noise)
plt.title("White noise stimulus")
plt.xlabel("Time (s)")
plt.ylabel("Stimulus")
plt.grid()
plt.show()
plt.figure()
plt.plot(t, r_white)
plt.title("Neural response to white noise (with adaptation)")
plt.xlabel("Time (s)")
plt.ylabel("Firing rate r(t)")
plt.grid()
plt.show()
# --------------------------
# 绘图 2:突发刺激与神经响应
# --------------------------
plt.figure()
plt.plot(t, stim_burst)
plt.title("White noise + burst stimulus")
plt.xlabel("Time (s)")
plt.ylabel("Stimulus")
plt.grid()
plt.show()
plt.figure()
plt.plot(t, r_burst)
plt.title("Neural response to burst (adaptation suppresses background)")
plt.xlabel("Time (s)")
plt.ylabel("Firing rate r(t)")
plt.grid()
plt.show()
import numpy as np
import matplotlib.pyplot as plt
# -----------------------------
# 1) Generate a toy "environment" audio-like signal
# -----------------------------
fs = 2000 # Hz (kept small for quick simulation)
T = 6.0 # seconds
t = np.arange(0, T, 1/fs)
rng = np.random.default_rng(0)
# Background low-frequency hum + some random bursts (like keyboard clicks)
hum = 0.15*np.sin(2*np.pi*120*t) + 0.08*np.sin(2*np.pi*60*t)
# Random burst events
env = hum.copy()
num_bursts = 18
burst_times = rng.uniform(0.3, T-0.3, size=num_bursts)
for bt in burst_times:
center = int(bt*fs)
width = int(rng.uniform(0.01, 0.04)*fs) # 10-40 ms
burst = np.zeros_like(t)
idx = slice(max(0, center-width), min(len(t), center+width))
# short "click": band-limited noise windowed
n = rng.normal(0, 1, (idx.stop-idx.start))
w = np.hanning(idx.stop-idx.start)
burst[idx] = 0.55*n*w
env += burst
# -----------------------------
# 2) Add white noise "masker"
# -----------------------------
masker_rms = 0.22
masker = rng.normal(0, masker_rms, size=len(t))
mix = env + masker
# -----------------------------
# 3) Frame-based STFT-like analysis (simple)
# -----------------------------
win_len = int(0.200*fs) # 200 ms
hop = int(0.050*fs) # 50 ms hop
win = np.hanning(win_len)
nfft = 2048
def frame_rms(x):
# returns RMS per frame, aligned to hop centers
frames = []
centers = []
for start in range(0, len(x)-win_len+1, hop):
seg = x[start:start+win_len]
frames.append(np.sqrt(np.mean(seg**2)))
centers.append((start + win_len//2)/fs)
return np.array(centers), np.array(frames)
centers, env_r = frame_rms(env)
_, mix_r = frame_rms(mix)
# Spectral magnitude per frame at a few bands for a "detectability proxy"
freqs = np.fft.rfftfreq(nfft, 1/fs)
def band_energy(seg, f1, f2):
X = np.fft.rfft(seg*win, nfft)
mag2 = (np.abs(X)**2)
band = (freqs>=f1) & (freqs<f2)
return mag2[band].mean()
bands = [(0,200),(200,800),(800,1500)]
env_band = {b:[] for b in bands}
mix_band = {b:[] for b in bands}
for start in range(0, len(env)-win_len+1, hop):
e = env[start:start+win_len]
m = mix[start:start+win_len]
for b in bands:
env_band[b].append(band_energy(e, b[0], b[1]))
mix_band[b].append(band_energy(m, b[0], b[1]))
for b in bands:
env_band[b] = np.array(env_band[b])
mix_band[b] = np.array(mix_band[b])
# "Contrast" proxy: peakiness in each band over time
def contrast(x):
return (np.percentile(x, 95) - np.percentile(x, 50)) / (np.percentile(x, 50) + 1e-12)
contrast_env = {b: contrast(env_band[b]) for b in bands}
contrast_mix = {b: contrast(mix_band[b]) for b in bands}
# -----------------------------
# 4) Plot: time waveform + RMS envelope + simple "contrast" summary
# -----------------------------
plt.figure(figsize=(11,4))
plt.plot(t, env, linewidth=0.7)
plt.title("Toy environment waveform (hum + bursts)")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.grid()
plt.tight_layout()
plt.show()
plt.figure(figsize=(11,4))
plt.plot(t, mix, linewidth=0.7)
plt.title("Environment + white-noise masker waveform")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.grid()
plt.tight_layout()
plt.show()
plt.figure(figsize=(11,4))
plt.plot(centers, env_r, label="Env RMS (200 ms)")
plt.plot(centers, mix_r, label="Mix RMS (200 ms)")
plt.title("Frame RMS envelope: adding noise raises floor and reduces relative burst prominence")
plt.xlabel("Time (s)")
plt.ylabel("RMS")
plt.grid()
plt.legend()
plt.tight_layout()
plt.show()
# Contrast bar chart
labels = [f"{b[0]}–{b[1]} Hz" for b in bands]
env_vals = [contrast_env[b] for b in bands]
mix_vals = [contrast_mix[b] for b in bands]
x = np.arange(len(bands))
width = 0.35
plt.figure(figsize=(9,4))
plt.bar(x - width/2, env_vals, width, label="Env")
plt.bar(x + width/2, mix_vals, width, label="Env + masker")
plt.xticks(x, labels)
plt.ylabel("Contrast proxy (95th-50th)/50th")
plt.title("Spectral 'contrast' drops after adding white noise (masking effect proxy)")
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
contrast_env, contrast_mix