簡體   English   中英

頻域信號檢測算法

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM