Files
urh/tests/test_spectrogram.py
Johannes Pohl e633a788ad Enhance accuracy of automatic interpretation (#550)
* rename signalFunctions -> signal_functions

* basic methods for auto interpretation

* cythonize k means

* reorder tests

* remove check and update gitignore

* estimate tolerance and implement score for choosing modulation type

* use absdiff

* remove comment

* cythonize messsage segmentation

* improve message segementation and add test for xavax

* integrate OOK special case

* add check if psk is possible

* integrate xavax and improve score

* improve noise detection

* add test for noise detection multiple messages

* improve noise detection

* homematic fix: use percetange of signal length instead of num flanks

* homematic has some trash at start of messages, which counts as flanks
* additonally set score to 0 if found only one bit length lower 5

* calculate minimum bit length from tolerance

* improve noise noise detection

* refactor limit and propose new limit calculation

* improve minimum bit length penalty

* only increase score for mod_type if bit length surpasses a minimum
* this way scoring loop later becomes easier and
* score is more accurate as there is no division needed which does
  not scale well with the length of message vectors

* remove demodulated complex files and demod live in tests

* remove enocean.coco

* add a new check to prevent PSK misclassification

* add tolerance unit test
* use z=2 for finding outlier free max in tolerance estimation

* prevent numpy warnings

* adapt threshold of unit test

* normalize the score by dividing by plateau vector length

* improve OOK segmentation:

Use minimum pulse length instead pause length for reference

* use 50 percentile for detecting n_digits in plateau rounding

* add elektromaten integration test

* improve center detection to deal with varying signal power levels
* use 10% clustering for rect signal
* calculate min and max of each cluster
* return max(minima) + min(maxima) / 2

* improve the center aggregation, separate between modulation types

* add validity checks if message can be ASK or FSK modulated

* use a weighted mean for center estimation: 60/40 for high/low

* improve bit length estimation: use decimal deviation for filtering

* add scislo test

* improve tolerance estimation: use 50 percentile + revert to normal mean for bitlength estimation

* add haar wavelet transform

* add median filter

* rename to Wavelet

* add signal generation with configurable snr for lab test

* add method for testdata generation

* prepare fsk test: generate messages and estimate parameters

* improve performance of plateau length filtering

* remove unused import

* improve robustness

* improve robustness

* add fsk error plot

* only append bit length if it surpasses minimum

* fix plot title

* improve noise level detection, prevent it from being too low

* integrate all modulations to test

* increase pause threshold for ook

* improve tolerance estimation

* improve noise detection: take maximum of all maxima of noise clusters

* improve scoring algorithm to prevent PSK misclassify as FSK

* use histogram based approach for center detection

* modulation detection with wavelets

* fix median filter when at end of data

* integrate modulation detection with wavelets

* improve robustness

* improve psk parameters

* improve psk threshold

* improve robustness

* swap psk angles for easier demod

* better xticks

* add message segmentation test and fix noise generation snr

* add error print

* update audi test

* fix runtime warning

* improve accuracy of center detection

* avoid warning

* remove unused functions

* fine tune fsk fft threshold

* update esaver test

* improve fsk fft threshold

* change test order

* update enocean test signal

* update enocean test signal

* enhance bit length estimation: use a threshold divisor histogram

* improve noise estimation: round to fourth digit

* update enocean signal

* consider special case if message pause is 0

* remove unused

* improve noise detection

* improve center detection

* improve center detection

* prevent warning

* refactor

* cythonize get_plateau_lengths

* improve syntax

* use c++ sort

* optimize PSK threshold

* optimize coverage

* fix buffer types

* integrate new auto detection routine

* update test

* remove unused stuff

* fix tests

* backward compat

* backward compat

* update test

* add threshold for large signals for performance

* update changelog

* make algorithm more robust against short bit length outliers

* make multi button for selecting auto detect options

* update unittest
2018-10-18 18:59:04 +02:00

90 lines
4.5 KiB
Python

from PyQt5.QtCore import QTimer
from tests.QtTestCase import QtTestCase
from urh import colormaps
from urh.signalprocessing.Signal import Signal
from urh.signalprocessing.Spectrogram import Spectrogram
class TestSpectrogram(QtTestCase):
def setUp(self):
self.signal = Signal(self.get_path_for_filename("two_participants.coco"), "test")
self.spectrogram = Spectrogram(self.signal.data)
def test_create_spectrogram_image(self):
image = self.spectrogram.create_spectrogram_image()
self.assertEqual(image.width(), self.spectrogram.time_bins - 2)
self.assertEqual(image.height(), self.spectrogram.freq_bins)
def test_create_colormap_image(self):
image = self.spectrogram.create_colormap_image("magma", height=42)
self.assertEqual(image.height(), 42)
self.assertEqual(image.width(), len(colormaps.chosen_colormap_numpy_bgra))
def test_channel_separation_with_negative_frequency(self):
super().setUp()
self.add_signal_to_form("three_channels.complex")
self.assertEqual(self.form.signal_tab_controller.num_frames, 1)
signal_frame = self.form.signal_tab_controller.signal_frames[0]
self.__prepare_channel_separation(signal_frame)
self.__test_extract_channel(signal_frame, freq1=650, freq2=850, bandwidth="195,312kHz", target_bits="11001101", center=0.1)
self.__test_extract_channel(signal_frame, freq1=500, freq2=620, bandwidth="117,188kHz", target_bits="10101001", center=0.1)
self.__test_extract_channel(signal_frame, freq1=217, freq2=324, bandwidth="104,492kHz", target_bits="10010111", center=0.1)
def test_cancel_filtering(self):
super().setUp()
self.add_signal_to_form("two_participants.coco")
signal_frame = self.form.signal_tab_controller.signal_frames[0]
signal_frame.ui.cbSignalView.setCurrentIndex(2)
signal_frame.ui.spinBoxSelectionStart.setValue(100)
signal_frame.ui.spinBoxSelectionEnd.setValue(200)
menu = signal_frame.ui.gvSpectrogram.create_context_menu()
create_action = next(action for action in menu.actions() if "bandpass filter" in action.text())
timer = QTimer(self.form)
timer.setSingleShot(True)
timer.timeout.connect(self.form.cancel_action.trigger)
timer.start(1)
create_action.trigger()
self.assertTrue(signal_frame.filter_abort_wanted)
self.assertEqual(self.form.signal_tab_controller.num_frames, 1)
def __prepare_channel_separation(self, signal_frame):
self.assertEqual(self.form.signal_tab_controller.num_frames, 1)
signal_frame = self.form.signal_tab_controller.signal_frames[0]
signal_frame.ui.spinBoxNoiseTreshold.setValue(0)
signal_frame.ui.spinBoxNoiseTreshold.editingFinished.emit()
self.assertEqual(signal_frame.signal.num_samples, 800)
signal_frame.ui.cbSignalView.setCurrentIndex(2)
self.assertTrue(signal_frame.spectrogram_is_active)
def __test_extract_channel(self, signal_frame, freq1, freq2, bandwidth: str, target_bits: str, center=None):
num_frames = self.form.signal_tab_controller.num_frames
signal_frame.ui.spinBoxSelectionStart.setValue(freq1)
signal_frame.ui.spinBoxSelectionEnd.setValue(freq2 - 1)
signal_frame.ui.spinBoxSelectionEnd.setValue(freq2)
self.assertEqual(signal_frame.ui.lNumSelectedSamples.text(), str(freq2 - freq1))
self.assertEqual(signal_frame.ui.lDuration.text().replace(".", ","), bandwidth)
menu = signal_frame.ui.gvSpectrogram.create_context_menu()
create_action = next(action for action in menu.actions() if "bandpass filter" in action.text())
create_action.trigger()
self.assertEqual(self.form.signal_tab_controller.num_frames, num_frames + 1)
filtered_frame = self.form.signal_tab_controller.signal_frames[1]
filtered_frame.ui.cbModulationType.setCurrentText("ASK")
filtered_frame.ui.spinBoxNoiseTreshold.setValue(0)
filtered_frame.ui.spinBoxNoiseTreshold.editingFinished.emit()
filtered_frame.ui.spinBoxInfoLen.setValue(100)
filtered_frame.ui.spinBoxInfoLen.editingFinished.emit()
if center is not None:
filtered_frame.ui.spinBoxCenterOffset.setValue(center)
filtered_frame.ui.spinBoxCenterOffset.editingFinished.emit()
self.assertEqual(len(filtered_frame.proto_analyzer.plain_bits_str), 1)
self.assertEqual(filtered_frame.proto_analyzer.plain_bits_str[0], target_bits)