[英]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.