Live detector working

This commit is contained in:
Jono Targett 2024-05-29 23:15:37 +09:30
parent 7465ef13ea
commit dde00782d4
2 changed files with 41 additions and 15 deletions

View File

@ -2,13 +2,18 @@
import numpy as np import numpy as np
from scipy.signal import butter, lfilter, decimate from scipy.signal import butter, lfilter, decimate
def anti_alias(data, sample_rate, max_frequency): def anti_alias(data, sample_rate, max_frequency, order=5):
FILTER_HEADROOM = 1.2 FILTER_HEADROOM = 1.2
nyquist_rate = 2 * max_frequency nyquist_rate = 2 * max_frequency
downsample_factor = 1 downsample_factor = 1
if sample_rate > nyquist_rate: if sample_rate > nyquist_rate:
filtered_data = lowpass_filter(data, max_frequency * FILTER_HEADROOM, sample_rate) filtered_data = lowpass_filter(
data,
max_frequency * FILTER_HEADROOM,
sample_rate,
order
)
downsample_factor = int(sample_rate / nyquist_rate) downsample_factor = int(sample_rate / nyquist_rate)
filtered_data = decimate(filtered_data, downsample_factor) filtered_data = decimate(filtered_data, downsample_factor)
@ -18,9 +23,9 @@ def anti_alias(data, sample_rate, max_frequency):
return filtered_data, sample_rate, downsample_factor return filtered_data, sample_rate, downsample_factor
def smoothing_filter(data, window_size=256): def smoothing_filter(data, window_size=256, mode='same'):
window = np.ones(window_size) / window_size window = np.ones(window_size) / window_size
return np.convolve(data, window, mode='same') return np.convolve(data, window, mode=mode)
# Stolen from selcald # Stolen from selcald
def note(freq, length, amp=1.0, rate=44100): def note(freq, length, amp=1.0, rate=44100):

View File

@ -5,12 +5,13 @@ import threading
import numpy as np import numpy as np
import signal as sig import signal as sig
from tones import TONES from tones import TONES
from filters import anti_alias, bandpass_filter, note from filters import anti_alias, bandpass_filter, note, smoothing_filter
from scipy import signal from scipy import signal
from scipy.signal import butter, lfilter, decimate from scipy.signal import butter, lfilter, decimate
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtWidgets, mkQApp from pyqtgraph.Qt import QtGui, QtWidgets, mkQApp
import time
keep_running = True keep_running = True
def signal_handler(sig, frame): def signal_handler(sig, frame):
@ -40,11 +41,13 @@ class DetectorGui(QtWidgets.QMainWindow):
self.tone_data = {} self.tone_data = {}
self.tone_lines = {} self.tone_lines = {}
self.tone_pens = {}
for tone,color in zip(TONES.keys(), colors): for tone,color in zip(TONES.keys(), colors):
self.tone_data[tone] = np.zeros(int(10000), dtype=np.float64) #np.array([], dtype=np.float64) self.tone_data[tone] = np.zeros(1000, dtype=np.float64) #np.array([], dtype=np.float64) #np.zeros(int(10000), dtype=np.float64)
self.tone_lines[tone] = self.plot.plot(self.tone_data[tone], pen=pg.mkPen(color=color), name=tone) self.tone_lines[tone] = self.plot.plot(self.tone_data[tone], pen=pg.mkPen(color=color), name=tone)
legend.addItem(self.tone_lines[tone], tone) legend.addItem(self.tone_lines[tone], tone)
self.tone_pens[tone] = pg.mkPen(color=color)
self.plot.setLabel('left', 'Signal Correlation') self.plot.setLabel('left', 'Signal Correlation')
self.plot.setLabel('bottom', 'Time (samples)') self.plot.setLabel('bottom', 'Time (samples)')
@ -64,11 +67,19 @@ class DetectorGui(QtWidgets.QMainWindow):
self.tone_lines[tone].setData(self.tone_data[tone]) self.tone_lines[tone].setData(self.tone_data[tone])
def push_tones(self, tone, values): def push_tones(self, tone, values):
s = time.perf_counter()
#self.tone_data[tone] = np.append(self.tone_data[tone], values) #self.tone_data[tone] = np.append(self.tone_data[tone], values)
a = time.perf_counter()
self.tone_data[tone] = np.roll(self.tone_data[tone], -len(values)) self.tone_data[tone] = np.roll(self.tone_data[tone], -len(values))
self.tone_data[tone][-len(values):] = values self.tone_data[tone][-len(values):] = values
self.tone_lines[tone].setData(self.tone_data[tone]) self.tone_lines[tone].setData(self.tone_data[tone])
#self.tone_lines[tone].setData(values)
g = time.perf_counter()
#print(a-s, g-a)
#self.plot.plot(values, pen=self.tone_pens[tone])
mkQApp("Correlation matrix display") mkQApp("Correlation matrix display")
@ -91,27 +102,37 @@ def read_audio_from_stdin(chunk_size, process_chunk):
process_chunk(audio_chunk) process_chunk(audio_chunk)
sample_rate = 44100 sample_rate = 44100
note_length = 0.1 note_length = 0.5
N = 256
cumsum_convolution = np.ones(N)/N
guard_duration = 0.01
def process_audio_chunk(audio_chunk): def process_audio_chunk(audio_chunk):
global gui global gui
data = audio_chunk data = audio_chunk
sample_rate = 44100 sample_rate = 44100
data, sample_rate, decimation = anti_alias(data, sample_rate, 4800) s = time.perf_counter()
data, sample_rate, decimation = anti_alias(data, sample_rate, 4800, 8)
data = data / (np.max(data) + 0.0001)
pure_signals = {tone:note(freq, note_length, rate=sample_rate) for tone,freq in TONES.items()} pure_signals = {tone:note(freq, note_length, rate=sample_rate) for tone,freq in TONES.items()}
correlations = {tone:np.abs(signal.correlate(data, pure, mode='same')) for tone,pure in pure_signals.items()} aa = time.perf_counter()
massaged = {tone:decimate(np.convolve(correlation, cumsum_convolution, mode='valid'), 4) for tone,correlation in correlations.items()}
print('processing done') correlations = {tone:smoothing_filter(np.abs(signal.correlate(data, pure, mode='same')), 64) for tone,pure in pure_signals.items()}
corr = time.perf_counter()
for tone,massage in massaged.items(): guard_samples = int(guard_duration * sample_rate)
gui.push_tones(tone, massage ) for tone,massage in correlations.items():
#gui.push_tones(tone, massage)
gui.push_tone(tone, np.mean(massage))
gui.push_tones(tone, massage[guard_samples:-guard_samples:100])
draw = time.perf_counter()
#print(aa-s, corr-aa, draw-corr)
if draw - s > 0.1:
print("FAILED")
if __name__ == '__main__': if __name__ == '__main__':
sig.signal(sig.SIGINT, signal_handler) sig.signal(sig.SIGINT, signal_handler)