繁体   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