Muss ich das gesamte Signal (oder zumindest ein großes Stück) jedes Mal filtern, wenn ein paar neue Samples eingehen, oder gibt es eine Möglichkeit (wie die gleitende DFT), den neuen Teil des gefilterten Signals effizient zu bestimmen? Signal?
Digitale Filter funktionieren nicht so - im Grunde können klassische FIR oder IIR für jedes einzelne neue Sample funktionieren . Sie sollten sich wirklich darüber informieren, was diese Filter sind und wie die Leute sie modellieren.
Ich möchte einen Butterworth-Filter verwenden
Nun, es gibt viele Implementierungen davon da draußen,
Ich benutze derzeit Scipys Butter und Filter
von denen du schon einen kennst!
Jetzt ist ein Butterworth-Filter eine rekursive Sache. Um den nächsten Teil Ihres abgetasteten Signals zu berechnen, benötigen Sie den letzten Zustand. Das ist genau der "Filterverzögerungszustand zi", der lfilter
zurückkehrt und beim nächsten Aufruf als zi
Parameter aufgenommen werden kann.
aber ich weiß nicht, wie ich damit ein konstantes Signal erhalten soll.
Ich denke, Sie meinen "kontinuierliche Filterung erreichen".
Der Punkt ist jedoch, dass Sie sich darauf einstellen, Ihre eigene Streaming-Architektur zu schreiben. Das würde ich nicht tun. Verwenden Sie ein vorhandenes Framework. Zum Beispiel gibt es GNU Radio, mit dem Sie Flussdiagramme für die Signalverarbeitung in Python definieren können. Außerdem ist es von Natur aus multithreaded, verwendet hochoptimierte Algorithmusimplementierungen, verfügt über zahlreiche Ein- und Ausgabefunktionen und verfügt über eine große Bibliothek von Signalverarbeitungsblöcken , die in Python oder C ++ geschrieben werden kann, wenn Sie dies tun müssen.
Ein Flussdiagramm, das Samples von einer Soundkarte aufnimmt, sie butterworth filtert und in eine Datei schreibt, lautet beispielsweise:
#!/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()
Beachten Sie, dass dieser Code automatisch aus einem grafischen Flussdiagramm generiert wurde, das ich gerade mit dem gnuradio-companion
Programm zusammengeklickt habe:
Wenn Sie mehr über die Implementierung von Flussdiagrammen für die Signalverarbeitung in Python erfahren möchten, lesen Sie die GNU Radio Guided Tutorials .
EDIT : Ich mochte die Antwort von @ Fat32 ziemlich! Was er als Doppelpufferarchitektur beschreibt, kommt dem, was GNU Radio tut, ziemlich nahe:
Ein Upstream-Block erzeugt Samples in Sample-Chunks beliebiger Größe, schreibt sie in den Ausgangsringpuffer (der im obigen Bild als Pfeil dargestellt ist) und benachrichtigt seine Downstream-Blöcke über neue Daten.
Der Downstream-Block wird benachrichtigt, prüft, ob in seinem Ausgabepuffer genügend Speicherplatz vorhanden ist, um die Samples zu verarbeiten, die sich in seinem Eingangsringpuffer befinden (der mit dem Ausgabepuffer des Upstream-Blocks identisch ist), und verarbeitet diese. Wenn der Vorgang abgeschlossen ist, werden die Upstream-Blöcke darüber informiert, dass sie den Eingangsringpuffer (der dann von den Upstream-Blöcken als Ausgang wiederverwendet werden kann) verbraucht haben, und die Downstream-Blöcke darüber, dass neue Abtastwerte verfügbar sind.
Da GNU Radio jetzt Multithreading ist, produziert der Upstream-Block möglicherweise bereits wieder Samples. In einer normalen GNU Radio-Anwendung sind fast alle Blöcke gleichzeitig "aktiv" und die Skalierung auf Computern mit mehreren CPUs ist recht gut.
Die Hauptaufgabe von GNU Radio besteht also darin, Ihnen diese Pufferinfrastruktur, die Benachrichtigungs- und Thread-Verwaltung, die eindeutige Signalverarbeitungsblock-API und etwas zu geben, um zu definieren, wie alles verbunden ist, sodass Sie nicht schreiben müssen, was Fat32 in ihr beschreibt poste dich! Beachten Sie, dass das Marshalling von Sample-Streams nicht so einfach ist, und GNU Radio nimmt die Härte heraus und lässt Sie sich auf das konzentrieren, was Sie tun möchten: DSP.