Pythonを使用してオンラインでデジタル信号をリアルタイムでフィルタリングする


7

現在、バンドパスフィルターを信号にリアルタイムで適用しようとしています。一定のサンプリングレートで入力されるサンプルがあり、対応するバンドパスフィルター処理された信号を計算したいと思います。

これを行う最善の方法は何でしょうか?いくつかの新しいサンプルが入ってくるたびに信号全体(または少なくとも巨大なビット)をフィルタリングする必要があるか、またはフィルタリングされた新しい部分を効率的に決定できる方法(スライディングDFTなど)があるか信号?

バターワースフィルターを使用したい(オフライン分析のために、現在scipyのバターとlfilterを使用しています)。この関数がフィルター遅延を返すことができることは知っていますが、一定の信号を取得するためにそれを使用する方法がわかりません。

回答:


1

X-windowsベースの汎用PCプラットフォームでリアルタイムデジタルオーディオ処理を実行する基本的なメカニズムは、ダブルバッファリングファミリのアーキテクチャを使用することに基づいています。

このアーキテクチャでは、マイク/ライン入力を介して送られるサウンドは、まずサウンドカードADCを介してサンプルに変換され、次にユーザーが選択したサンプリングレートFsで入力バッファーに入力されます。このバッファがいっぱいになると、最初にサウンドカードハードウェアがオペレーティングシステムに通知し、次にオペレーティングシステムがプログラムに通知します。その後、プログラムはブロックにアクセスして、そのブロック内のサンプルの処理を開始できます。

ただし、現在のブロックでビジーであると同時に、プログラムは、以前に満たされたバッファーの処理中に到着するサンプルを、オーディオカードによって満たされる別の(2番目の)バッファーを既に提供しています。現在使用可能なこのバッファーが完全に処理されたら、遅延なしですぐに次のバッファーの処理を開始する必要があります。これは、クリックのないスムーズなオーディオ再生に不可欠です。このダブルバッファリングの方法では、グリッチやクラックのないスムーズなオーディオ処理を作成することができます。

また、FIRまたはIIRベースのフィルタリングを行うかどうかにかかわらず、FIRの場合のようにバッファー全体を一度にフィルターするか、IIRの場合はサンプルごとに再帰的にサンプリングできます。

バッファのサイズは、処理の初期遅延にとって重要です。したがって、大きすぎると、両方のバッファがいっぱいになってから何も出力されなくなるまで待つ必要があります。もう一方の手では、バッファを短くしすぎると、システムは着信割り込みに圧倒されます。

最適な選択は、128〜1024サンプルです。これらのバッファー長は、後のFFTタイプの処理に適しています。また、バッファの数を増やして、さまざまなシステム負荷条件下でより堅牢なスループットを実現できます。ただし、少なくとも2つのバッファーが必要です。


2
私は脳波信号処理を行っていますが、これを完全に適用することができます、ありがとう!
BStadlbauer 2016

1
ちなみに、これはまさにGNU Radioのカスケードバッファアーキテクチャの説明です。
マーカス・ミュラー

1
私は私の回答の拡張である@ Fat32であなたの投稿に対処しました。よろしくお願いします:)
MarcusMüller

@MarcusMüller; ご協力ありがとうございます。私は感謝します;)
Fat32

5

いくつかの新しいサンプルが入ってくるたびに信号全体(または少なくとも巨大なビット)をフィルタリングする必要があるか、またはフィルタリングされた新しい部分を効率的に決定できる方法(スライディングDFTなど)があるか信号?

デジタルフィルターはそのようには機能しません。基本的に、従来のFIRまたはIIRはすべての新しいサンプルで機能します。これらのフィルターとは何か、そして人々がそれらをどのようにモデル化するかを実際に読んでください。

バターワースフィルターを使用したい

まあ、そこにはたくさんの実装があります。

私は現在scipyのバターとlfilterを使用しています

あなたはすでにそれを知っています!

さて、バターワースフィルターは再帰的なものであるため、サンプリングされた信号の次の部分を計算するには、最後の状態が必要になります。これは、「フィルター遅延状態zi」でlfilterあり、ziパラメーターとして次の呼び出しで戻ります。

しかし、それを使用して一定の信号を取得する方法がわかりません。

「継続的なフィルタリングを実現する」という意味だと思います。

さて、言われているように、重要なのは、独自のストリーミングアーキテクチャを作成するための準備をしているということです。私はそれをしません。既存のフレームワークを使用します。たとえば、Pythonで信号処理フローグラフを定義できるGNUラジオがあり、本質的にマルチスレッド化され、高度に最適化されたアルゴリズム実装を使用し、多くの入出力機能を備え、信号処理ブロックの巨大なライブラリが付属しています必要に応じて、PythonまたはC ++で記述できます。

たとえば、サウンドカードからサンプルを取り込み、バターワースフィルター処理してファイルに書き込むフローグラフは次のとおりです。

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
##################################################
# GNU Radio Python Flow Graph
# Title: Butterworth Test
# Generated: Mon Feb  8 16:17:18 2016
##################################################

from gnuradio import audio
from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import filter
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser


class butterworth_test(gr.top_block):

    def __init__(self):
        gr.top_block.__init__(self, "Butterworth Test")

        ##################################################
        # Variables
        ##################################################
        self.samp_rate = samp_rate = 48000

        ##################################################
        # Blocks
        ##################################################
        # taps from scipy.butter!
        self.iir_filter_xxx_0 = filter.iir_filter_ffd(([1.0952627450621233e-05, 0.00013143152940745496, 0.0007228734117410033, 0.0024095780391366808, 0.005421550588057537, 0.008674480940892064, 0.010120227764374086, 0.008674480940892081, 0.005421550588057554, 0.0024095780391366955, 0.0007228734117410089, 0.00013143152940745594, 1.0952627450621367e-05]), ([1.0, -4.4363862740719835, 10.215121830052535, -15.374408118154847, 16.57333784740102, -13.325056987818655, 8.133543488903097, -3.77641064765334, 1.3181452681671835, -0.3361758629961047, 0.05930166356243964, -0.0064815521348275, 0.00033130678123743994]), False)
        self.blocks_file_sink_0 = blocks.file_sink(gr.sizeof_float*1, "", False)
        self.blocks_file_sink_0.set_unbuffered(False)
        self.audio_source_0 = audio.source(samp_rate, "", True)

        ##################################################
        # Connections
        ##################################################
        self.connect((self.audio_source_0, 0), (self.iir_filter_xxx_0, 0))    
        self.connect((self.iir_filter_xxx_0, 0), (self.blocks_file_sink_0, 0))    

def main(top_block_cls=butterworth_test, options=None):

    tb = top_block_cls()
    tb.start()
    try:
        raw_input('Press Enter to quit: ')
    except EOFError:
        pass
    tb.stop()
    tb.wait()


if __name__ == '__main__':
    main()

このコードは、gnuradio-companionプログラムを使用して一緒にクリックしたグラフィカルフローグラフから自動生成されたことに注意してください。

GRCで設計されたフローグラフ

Pythonで信号処理フローグラフを実装する方法について詳しく知りたい場合は、GNU Radio Guided Tutorialsにアクセスし てください

編集:私は@ Fat32の答えがかなり好きでした!彼がダブルバッファリングアーキテクチャとして説明していることは、GNU Radioが行うこととかなり似ています。

上流ブロックは、任意のサイズのサンプルチャンクでサンプルを生成し、それらを出力リングバッファー(上の図では矢印で表されています)に書き込み、新しいデータがあることを下流ブロックに通知します。

ダウンストリームブロックは通知を受け、入力リングバッファー(アップストリームブロックの出力バッファーと同じ)にあるサンプルを処理するのに十分なスペースが出力バッファーにあるかどうかを確認し、これらを処理します。完了すると、入力リングバッファーを使い果たしたことをアップストリームブロックに通知し(アップストリームブロックは出力として再利用できます)、ダウンストリームブロックは新しいサンプルが利用可能であることを通知します。

現在、GNU Radioはマルチスレッド化されており、上流のブロックはすでにサンプルを再び生成している可能性があります。通常のGNUラジオアプリケーションでは、ほぼすべてのブロックが同時に「アクティブ」になり、マルチCPUマシン上でかなり拡張できます。

したがって、GNU Radioの主な仕事は、このバッファインフラストラクチャ、通知とスレッドのハウスキーピング、明確な信号処理ブロックAPI、およびすべての接続方法を定義するものを提供することです。そのため、Fat32で記述されている内容を自分で書く必要はありません。自分を投稿してください!サンプルストリームのマーシャリングを行うのは適切に行うのは簡単ではないことに注意してください。GNURadioはその硬度を取り除き、やりたいことに集中できます:DSP。


ありがとうございました!私はGNUラジオを調べましたが、EEG信号を処理するため、フローグラフを使用するために独自のモジュールを構築する必要があります。すべてのサンプルには、フィルタリングプロセス全体で追跡可能なタイムスタンプがあるためです。
BStadlbauer 2016

そのためのブロックは必要ありません。サンプルが連続している、固定サンプリングレートで、時間は、現在のサンプルレートとして直接利用可能である
マーカスミュラー

@MarcusMüller; あなたが説明するこのGNU Radioアーキテクチャは、現代の哲学が実際に提供するものです。柔軟性、コーディングの容易さ、そして最も重要なことは、複雑な低レベルの詳細を使用してそれを達成する方法ではなく、Win32 API呼び出しを使用してダブルバッファリングテクニックを実装しようとすると何が起こるかではなく、コアの目的(DSP処理)に集中できること!)
Fat32、2016

@ Fat32マーケティングスタイルをトーンダウンする必要がありますが、確かに、効率的なゼロコピーリングバッファーアーキテクチャと、x86で手動で最適化されたコードを使用する広範なブロックライブラリを提供することで、MMX、SSE、 SSE2、該当使ってAVX拡張およびARMのNEON VOLKカーネルのベクトル最適化されたライブラリを:)
マーカス・ミュラー

@MarcusMüller昨日は少し暇だったので、GNU Radioをさらに詳しく調べてみたところ、それはかなり役立つように見えました。ハードウェアデバイスからのオーディオソース用に作成されました。サンプルをチェーンに手動でプッシュするためのトゥロリアルなどがどこにあるのか、たまたま知りませんか?PS EEGサンプルは特別なレイヤー(
LSL-
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.