如何从噪声中检测信号?
我以前也处理过类似的问题。您可能首先需要知道的是噪声频谱的样子。
第一种方法(主要是经验性的):我看到您感兴趣的信号(SoI)是一串矩形脉冲,因此主要频率成分在直流附近。您可以对其进行低通滤波以去除主要噪声分量(可能使用移动平均滤波器)。然后将检测阈值(根据经验)设置为过滤后的 SoI 将始终超过的值,而过滤后的噪声很少或永远不会超过该值。
第二种方法(主要是理论上的):检查频域中的噪声分量(应用 FFT)。如果噪声从 DC 到几乎平坦,可以对这个检测问题应用最优解,就是实现一个能量检测器,如下:
假设我们存在(零均值)高斯噪声,估计它的统计数据(噪声方差会做)。
怎么做? 由于您的 SoI 是一列矩形脉冲,因此其主要频率分量在 DC 附近。您可以对其进行高通滤波以去除 SoI。如果滤波器的截止频率足够低,则滤波后的噪声将在滤波后保持相似的噪声方差。否则,将过滤后方差乘以, 在哪里是滤波器的带宽,并且是采样率。
应用最佳阈值来检测 AWGN 中的信号:
是噪声方差,是信号长度(滑动缓冲区的样本数,见步骤3),是设计误报概率(即,您承认触发误报的可能性有多大)。
使用滑动缓冲区逐段分析整个信号,以及您需要比较的内容是包含在这样一个缓冲区中的能量:
可以在此处找到有关第二种方法的更多详细信息,例如:
[1] S. Atapattu、C. Tellambura 和 H.Jiang,认知无线电频谱传感的能量检测,Springer 2014。第 2 章:常规能量检测器。
我真的坐在一个热带岛屿上,一只手拿着电话,请原谅我的简短:
是的,像往常一样,感兴趣的信号类型非常重要!
检测 OFDM 是一项艰巨的任务,因为 OFDM 信号对于(非同步的)观察者来说实际上是带宽受限的白噪声。
因此,许多基于 SoI 的频谱特性与背景噪声不同的方法将简单地下降,以免您有很多无关的带宽可以使用(使用 20 或 40 MHz 的 WiFi 带宽在计算上会相当不错)只是为了做无聊的检测而昂贵)。尤其是在另一个答案中概述的传统检测器在不太理想的噪声场景中效果不佳。
实际的 OFDM 系统具有一个特性,即使在负 SNR 场景中也很容易检测到:
在大多数情况下(尤其是 WiFi),OFDM 是 CP-OFDM。这意味着,出于同步和均衡的目的,每个 OFDM 符号都从其自身末端的“副本”开始,移到前面。(如果你没有听说过,你会发现它在每本介绍 OFDM 的教科书中都有介绍,你应该明确地阅读它。给你一个想法:OFDM 基于离散傅里叶变换,这使得传输信号与信道脉冲响应的卷积是乘法,当且仅当该卷积一开始看起来像一个循环卷积;通过使用 CP,您可以通过现实世界的线性卷积模拟一个循环卷积。)
您可以通过在恰好符号长度处查找接收信号自相关中的峰值来利用 CP。由于您真的不关心任何其他延迟,您只需计算信号的 CP 长度部分与延迟 OFDM 符号长度的信号的点积。如果那里有一个高峰,你可能找到了一个CP。为了允许一个恒定的阈值,只需将相关系数除以两个部分的幂乘积即可。
OFDM 符号长度和 CP 长度均由 WiFi 标准定义。
关于你正在做的整体事情的评论:你最终可能永远找不到一个好的阈值。那是因为 WiFi 处于 ISM 频段并且依赖于 CSMA-CA,并且您会遇到经典的隐藏站问题。只要您很好地记录了这一点并给出了充分的理由,那么选择一个仅凭经验为您提供固定检测概率的阈值绝对是合法的。请注意,由于上述属性,很难从 SINR 中区分 SNR。
我认为检测噪声/方差水平最直接的基本方法是:
高通 -> 整流(或平方) -> 低通
有许多类型的“高通”或“低通”,如操作/过滤器,您可以根据您的应用程序进行选择和调整。下面我diff
有效地使用(例如导数)作为高通滤波器,并为低通部分使用几个滚动分位数滤波器。然后我使用 round 来离散级别。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Generate test signal
np.random.seed(2)
PN = 100 # Min points per pulse (i.e. min points expected for detection)
N = 1000 # Total number of points for simulation
x = np.linspace(0,N/PN,N)
noiseLevel = 1+x.astype(int)%2+x.astype(int)%3; # Fake function te generate various levels
ynoise = (np.random.normal(0,.5,*x.shape)+2)*noiseLevel # Normally distributed noise
#ynoise = (np.random.random(*x.shape)*2-1 +2)*noiseLevel # Uniform distributed noise
# Retrieve desired signal through rectification and filtering.
yfilt = np.abs(np.diff(ynoise, prepend=ynoise[1])) # diff (i.e. high pass filter), then rectify
yfiltR = yfilt.copy()
yfilt = pd.Series(yfilt).rolling(window=PN//5, center = True).quantile(.88)
yfilt = pd.Series(yfilt).rolling(window=PN, center = True).quantile(.5)
yfilt = np.round(yfilt)
# Plot
plt.figure(1); plt.clf()
plt.subplot(4,1,1)
plt.plot(x, noiseLevel)
plt.ylabel('Generated signal')
plt.subplot(4,1,2)
plt.plot(x, ynoise)
plt.ylabel('Raw Noise signal')
plt.subplot(4,1,3)
plt.plot(x, yfiltR)
plt.ylabel('Rectified signal')
plt.subplot(4,1,4)
plt.plot(x, noiseLevel, label = 'True')
plt.plot(x, yfilt, label = 'Filtered')
plt.legend()
plt.ylabel('Filterd signal')
plt.show()
注 1:具有小窗口的滚动平均值,然后是具有较大窗口的滚动最大值,其行为与第一个滚动分位数相似。第二个分位数只是一个中值滤波器。使用有效的均值/中值/最大值滤波器(例如bottleneck.move_median
)可能会快得多。
注意 2:根据噪声的分布方式(幅度和频率),您需要调整分位数阈值和窗口大小。