有限信号先验信息下的SNR估计方法咨询
问题
需要确定接收信号的SNR,但仅掌握有限先验信息:
- 未知信号频率,但频率保持恒定;
- 信号被划分为块(symbol),任意两块之间的相位差为0°或180°,各信号块幅值相近,块间差异仅来自相位和叠加的噪声;
- 噪声以AWGN为主,还可能存在与信号同频的ISI。
已知可通过采样点逐点加减判断块间相位差:若相加结果的幅值小于相减结果,则两块相位差为180°,否则为0°,进而得到含不同噪声的同源信号块。请问在此前提下如何估计SNR?
附原始信号生成代码:
from plotly.subplots import make_subplots import plotly.graph_objs as go import numpy as np fs = 12000 t = 505/fs f = 500 samples = np.arange(t * fs) / fs signal = np.sin(2 * np.pi * f * samples) prevSig = signal currSig = signal*-1 # 180 degree phase shift fig = make_subplots(rows=2, cols=1) fig.add_trace(go.Scatter(y=list(prevSig), mode='lines+markers', name='prevSig'), row=1, col=1) fig.add_trace(go.Scatter(y=list(currSig), mode='lines+markers', name='currSig'), row=2, col=1) fig.update_layout(dict(title=dict(text='Signals before noise'))) fig.show() #calculate power of signal before noise sigPower = np.mean(signal**2) targetSNR = 5 #Calculate noise prevNoise = np.random.normal(0, sigPower/targetSNR, len(signal)) currNoise = np.random.normal(0, sigPower/targetSNR, len(signal)) fig = make_subplots(rows=2, cols=1) fig.add_trace(go.Scatter(y=list(prevSig+prevNoise), mode='lines+markers', name='prevSigNoisy'), row=1, col=1) fig.add_trace(go.Scatter(y=list(currSig+currNoise), mode='lines+markers', name='currSigNoisy'), row=2, col=1) fig.update_layout(dict(title=dict(text='Signals with noise'))) fig.show()
SNR估计方案
核心逻辑
利用相邻信号块的相位特性,通过逐点加减操作分离出信号和噪声的功率估计值,进而计算SNR。
具体步骤
判断相位差
取相邻两个含噪信号块$x_1[n]$和$x_2[n]$,计算逐点相加结果$S_{add}[n] = x_1[n] + x_2[n]$、逐点相减结果$S_{sub}[n] = x_1[n] - x_2[n]$:- 若相加结果的平均功率小于相减结果的平均功率,说明两块相位差为180°;
- 否则相位差为0°。
计算信号与噪声功率
设纯净信号为$s[n]$,功率为$P_s$;两个块的噪声分别为独立AWGN$w_1[n]$、$w_2[n]$,功率均为$P_w$:- 相位差0°时:
$S_{add}$的功率 = $4P_s + 2P_w$(信号叠加,噪声相加);
$S_{sub}$的功率 = $2P_w$(信号抵消,噪声相减后功率叠加);
由此算出:$P_s = (P_{add} - P_{sub})/4$,$P_w = P_{sub}/2$。 - 相位差180°时:
$S_{add}$的功率 = $2P_w$(信号抵消,噪声相加);
$S_{sub}$的功率 = $4P_s + 2P_w$(信号叠加,噪声相减后功率叠加);
由此算出:$P_s = (P_{sub} - P_{add})/4$,$P_w = P_{add}/2$。
- 相位差0°时:
计算SNR
SNR的线性值为$P_s / P_w$,转换为dB则是$10\log_{10}(P_s / P_w)$。
误差优化
- 如果存在同频ISI,由于ISI和信号相关,单次估计会有误差,可多取几组相邻块的估计结果求平均来降低偏差;
- 信号块长度越长,功率估计的统计误差越小,结果越准确。
验证代码
下面是加入SNR估计逻辑的完整代码,可直接运行验证:
from plotly.subplots import make_subplots import plotly.graph_objs as go import numpy as np fs = 12000 t = 505/fs f = 500 samples = np.arange(t * fs) / fs signal = np.sin(2 * np.pi * f * samples) prevSig = signal currSig = signal * -1 # 可改为signal验证0度相位差情况 fig = make_subplots(rows=2, cols=1) fig.add_trace(go.Scatter(y=list(prevSig), mode='lines+markers', name='prevSig'), row=1, col=1) fig.add_trace(go.Scatter(y=list(currSig), mode='lines+markers', name='currSig'), row=2, col=1) fig.update_layout(title='无噪声信号') fig.show() # 原始信号功率 sigPower = np.mean(signal**2) targetSNR = 5 # 目标线性SNR # 添加AWGN噪声 prevNoise = np.random.normal(0, np.sqrt(sigPower / targetSNR), len(signal)) currNoise = np.random.normal(0, np.sqrt(sigPower / targetSNR), len(signal)) prevSigNoisy = prevSig + prevNoise currSigNoisy = currSig + currNoise fig = make_subplots(rows=2, cols=1) fig.add_trace(go.Scatter(y=list(prevSigNoisy), mode='lines+markers', name='prevSigNoisy'), row=1, col=1) fig.add_trace(go.Scatter(y=list(currSigNoisy), mode='lines+markers', name='currSigNoisy'), row=2, col=1) fig.update_layout(title='含噪声信号') fig.show() # 执行SNR估计 S_add = prevSigNoisy + currSigNoisy S_sub = prevSigNoisy - currSigNoisy power_add = np.mean(S_add ** 2) power_sub = np.mean(S_sub ** 2) if power_add < power_sub: # 相位差180度 P_w = power_add / 2 P_s = (power_sub - power_add) / 4 else: # 相位差0度 P_w = power_sub / 2 P_s = (power_add - power_sub) / 4 estimated_SNR_linear = P_s / P_w estimated_SNR_dB = 10 * np.log10(estimated_SNR_linear) print(f"目标线性SNR: {targetSNR:.2f}") print(f"估计线性SNR: {estimated_SNR_linear:.2f}") print(f"估计SNR(dB): {estimated_SNR_dB:.2f}")
内容的提问来源于stack exchange,提问作者gerrgheiser
相关产品推荐
相关产品推荐

