[英]Signal detection algorithm in the frequency domain
我想检测频域中的信号。 也就是说,拥有一个频谱图,可以自动确定其中的信号(它的频率和带宽)。 我尝试应用此处描述的算法Peak signal detection in realtime timeseries data ,但我得到不正确的数据(检测到噪声和不正确的信号值)。 我使用的频谱图示例在图片中。 宽带信号和频率调制信号的检测特别有趣。 也许有人会在 python 中建议类似的实现。 先感谢您。 这就是我处理频谱的方式:
self.L = 15 # L-point filter
self.b = (np.ones(self.L)) / self.L # numerator co-effs of filter transfer function
self.a = np.ones(1) # denominator co-effs of filter transfer function
fft_data = np.fft.fft(balanced_signal, n=self.fft_size) / self.fft_size
_fft_log = (np.abs(np.fft.fftshift(fft_data)))
_fft_log = ss.lfilter(self.b, self.a, _fft_log)
spectrum = savgol_filter(_fft_log, 100, 5,mode='nearest')
然后我将此数据传递给信号检测 function 期望在有信号的地方得到 1,在有矿井信号的噪声值频谱的地方得到 0:
lag = 30
threshold = 5
influence = 0
def thresholding_algo(self,y, lag, threshold, influence):
signals = np.zeros(len(y))
filteredY = np.array(y)
avgFilter = [0] * len(y)
stdFilter = [0] * len(y)
avgFilter[lag - 1] = np.mean(y[0:lag])
stdFilter[lag - 1] = np.std(y[0:lag])
for i in range(lag, len(y)):
if abs(y[i] - avgFilter[i - 1]) > threshold * stdFilter[i - 1]:
if y[i] > avgFilter[i - 1]:
signals[i] = 1
else:
signals[i] = -1
filteredY[i] = influence * y[i] + (1 - influence) * filteredY[i - 1]
avgFilter[i] = np.mean(filteredY[(i - lag + 1):i + 1])
stdFilter[i] = np.std(filteredY[(i - lag + 1):i + 1])
else:
signals[i] = 0
filteredY[i] = y[i]
avgFilter[i] = np.mean(filteredY[(i - lag + 1):i + 1])
stdFilter[i] = np.std(filteredY[(i - lag + 1):i + 1])
return dict(signals=np.asarray(signals),
avgFilter=np.asarray(avgFilter),
stdFilter=np.asarray(stdFilter))
但我得到了检测到的噪音。 一旦我将阈值提高到 6,我就根本没有检测到。
对于像这样的嘈杂信号,最好使用滑动平均值和阈值,这取决于您想要实现的目标以及您认为有用的信号,因此:
if ( abs(signal - sliding_average(signal)) >= positive_threshold ) this_is_signal;
或者
if ( sliding_average(signal) <= negative_threshold ) this_is_signal;
请注意,您的值是负数,这就是我在第二个示例中使用负阈值和<=
的原因。
我也希望频谱是功率谱(您知道 FFT 会产生复杂的域结果,因此您必须先转换为实域或使用不同的频域转换,如带通滤波器 DCT 或 DST 才能使用实域方法)
在您的情况下(带有“基线”的信号)我将使用第二个选项...不是 python 编码器,但我在 C++/VCL 中尝试了它,滑动平均 window 大小为 11 个样本,阈值为-117.0
结果:
黄色是您的“原始”输入(从图像中提取),滑动平均值为水色,阈值为深绿色,阈值结果为绿色。
在这里,我使用 C++/VCL 代码执行此操作:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
int xs,ys;
Graphics::TBitmap *bmp;
float *data_in=NULL,*data_out=NULL;
int n;
//---------------------------------------------------------------------------
float* load_graph(int &size,float y0,float y1,AnsiString filename)
{
int x,y,xs,ys;
DWORD **pyx,c;
float a,my,*data=NULL;
Graphics::TBitmap *bmp;
bmp=new Graphics::TBitmap;
bmp->LoadFromFile(filename);
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
xs=bmp->Width;
ys=bmp->Height;
size=xs;
data=new float[size];
pyx=new DWORD*[ys];
for (y=0;y<ys;y++) pyx[y]=(DWORD*)bmp->ScanLine[y];
my=(y1-y0)/float(ys-1);
for (x=0;x<xs;x++)
for (data[x]=y0,y=0;y<ys;y++)
if ((pyx[y][x]&0x00FFFFFF)==0x00FFFF00)
{
a=y0+(float(ys-1-y)*my);
data[x]=a;
break;
}
delete[] pyx;
delete bmp;
return data;
}
//---------------------------------------------------------------------------
void draw()
{
int i;
float x,y,dx,y0,y1,dy;
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
y0=-123.0;
y1= -70.0;
dx=float(xs)/float(n);
dy=float(ys)/float(y1-y0);
// render input data
bmp->Canvas->Pen->Color=TColor(0x00008080); // yellow
for (x=0.0,i=0;i<n;i++,x+=dx)
{
y=(y1-data_in[i])*dy;
if (!i) bmp->Canvas->MoveTo(x,y);
else bmp->Canvas->LineTo(x,y);
}
// render output data
bmp->Canvas->Pen->Color=TColor(0x00F0F000); // aqua
for (x=0.0,i=0;i<n;i++,x+=dx)
{
y=(y1-data_out[i])*dy;
if (!i) bmp->Canvas->MoveTo(x,y);
else bmp->Canvas->LineTo(x,y);
}
// render threshold
float thr=-117.0;
bmp->Canvas->Pen->Color=TColor(0x00008000); // dark green
y=(y1-thr)*dy;
bmp->Canvas->MoveTo(0,y);
bmp->Canvas->LineTo(xs-1,y);
bmp->Canvas->Pen->Color=TColor(0x0000F000); // green
for (x=0.0,i=0;i<n;i++,x+=dx)
{
y=ys>>3;
// if (fabs(data_in[i]-data_out[i])>=5.0) y-=ys>>4;
if (fabs(data_out[i])<=-thr) y-=ys>>4;
if (!i) bmp->Canvas->MoveTo(x,y);
else bmp->Canvas->LineTo(x,y);
}
Form1->Canvas->Draw(0,0,bmp);
bmp->SaveToFile("out.bmp");
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
bmp=new Graphics::TBitmap;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
data_in=load_graph(n,-123.2,-70.0,"noise.bmp");
data_out=new float[n];
int i,j,k,m=5; // sliding average
float a;
for (i=0;i<n;i++)
{
for (a=0.0,j=i-m;j<=i+m;j++)
{
k=j;
if (k< 0) k=0;
if (k>=n) k=n-1;
a+=data_in[k];
}
data_out[i]=a/float(m+m+1);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete[] data_in;
delete[] data_out;
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
xs=ClientWidth;
ys=ClientHeight;
bmp->Width=xs;
bmp->Height=ys;
draw();
}
//-------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
draw();
}
//---------------------------------------------------------------------------
并输入我用于数据提取的图像:
大多数代码并不重要,只需查看标有这些注释的内容即可:
// render threshold
// sliding average
data_in data_in[]
是您的输入数据, data_out[]
是滑动平均值(以m
作为其一半强度), thr
是阈值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.