Files
urh/tests/test_plugins.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

150 lines
6.3 KiB
Python

import math
from PyQt5.QtTest import QTest
from PyQt5.QtWidgets import QApplication
from tests.QtTestCase import QtTestCase
from urh.plugins.MessageBreak.MessageBreakPlugin import MessageBreakPlugin
from urh.plugins.NetworkSDRInterface.NetworkSDRInterfacePlugin import NetworkSDRInterfacePlugin
from urh.plugins.ZeroHide.ZeroHidePlugin import ZeroHidePlugin
from urh.ui.views.ZoomableGraphicView import ZoomableGraphicView
from urh.util.Formatter import Formatter
class TestPlugins(QtTestCase):
def setUp(self):
super().setUp()
self.add_signal_to_form("esaver.coco")
self.sframe = self.form.signal_tab_controller.signal_frames[0]
self.cframe = self.form.compare_frame_controller
self.form.ui.tabWidget.setCurrentIndex(1)
self.assertEqual(self.cframe.protocol_model.row_count, 3)
def test_message_break_plugin(self):
bp = MessageBreakPlugin()
action = bp.get_action(self.cframe.ui.tblViewProtocol, self.cframe.protocol_undo_stack,
(1, 1, 4, 4), self.cframe.proto_analyzer, 0)
self.assertEqual(self.cframe.protocol_model.row_count, 3)
action.trigger()
self.assertEqual(self.cframe.protocol_model.row_count, 4)
self.cframe.protocol_undo_stack.undo()
self.assertEqual(self.cframe.protocol_model.row_count, 3)
def test_zero_hide_plugin_gui(self):
self.assertEqual(len(self.cframe.proto_analyzer.decoded_proto_bits_str[0]), 331)
zh = ZeroHidePlugin()
zh.following_zeros = 158
action = zh.get_action(self.cframe.ui.tblViewProtocol, self.cframe.protocol_undo_stack, (),
self.cframe.proto_analyzer, 0)
action.trigger()
self.assertEqual(len(self.cframe.proto_analyzer.decoded_proto_bits_str[0]), 331 - 158)
self.cframe.protocol_undo_stack.undo()
self.assertEqual(len(self.cframe.proto_analyzer.decoded_proto_bits_str[0]), 331)
def test_zero_hide_plugin_function(self):
zh = ZeroHidePlugin()
zh.following_zeros = 3
self.add_signal_to_form("ask.complex")
self.form.ui.tabWidget.setCurrentIndex(1)
test_bits = "1011001001011011011011011011011011001000000"
self.assertEqual(self.cframe.proto_analyzer.decoded_proto_bits_str[3], test_bits)
action = zh.get_action(self.cframe.ui.tblViewProtocol, self.cframe.protocol_undo_stack, (),
self.cframe.proto_analyzer, 0)
action.trigger()
self.assertEqual(self.cframe.proto_analyzer.decoded_proto_bits_str[3], "1011001001011011011011011011011011001")
def test_sdr_interface_plugin(self):
si = NetworkSDRInterfacePlugin(resume_on_full_receive_buffer=True)
test_bits = [
"10101011111",
"1010100011000111110001011001010101010101",
"1010100011000111110001011001010100100",
"1101010101011000011",
"11010101010110000110",
"11100010101001110000",
"111100000011011101010101010000101010101010100001010011010101010011"
]
for bits in test_bits:
byte_vals = si.bit_str_to_bytearray(bits)
self.assertEqual(len(byte_vals), int(math.ceil(len(bits) / 8)), msg=bits)
recalculated = si.bytearray_to_bit_str(byte_vals)
if len(bits) % 8 == 0:
self.assertEqual(bits, recalculated)
elif bits.endswith("1"):
self.assertEqual(bits, recalculated.rstrip("0"))
else:
self.assertTrue(recalculated.startswith(bits))
def test_insert_sine_plugin(self):
insert_sine_plugin = self.sframe.ui.gvSignal.insert_sine_plugin
num_samples = 10000
dialog = insert_sine_plugin.get_insert_sine_dialog(original_data=self.sframe.signal.data,
position=2000,
sample_rate=self.sframe.signal.sample_rate,
num_samples=num_samples)
graphics_view = dialog.graphicsViewSineWave # type: ZoomableGraphicView
while not dialog.doubleSpinBoxAmplitude.isEnabled():
QApplication.instance().processEvents()
QTest.qWait(10)
self.assertEqual(int(graphics_view.sceneRect().width()), self.sframe.signal.num_samples + num_samples)
self.assertEqual(insert_sine_plugin.insert_indicator.rect().width(), num_samples)
self.assertEqual(insert_sine_plugin.insert_indicator.rect().x(), 2000)
dialog.doubleSpinBoxAmplitude.setValue(0.1)
dialog.doubleSpinBoxAmplitude.editingFinished.emit()
self.assertEqual(insert_sine_plugin.amplitude, 0.1)
while not dialog.doubleSpinBoxAmplitude.isEnabled():
self.app.processEvents()
QTest.qWait(10)
dialog.doubleSpinBoxFrequency.setValue(1e6)
dialog.doubleSpinBoxFrequency.editingFinished.emit()
self.assertEqual(insert_sine_plugin.frequency, 1e6)
while not dialog.doubleSpinBoxAmplitude.isEnabled():
self.app.processEvents()
QTest.qWait(10)
dialog.doubleSpinBoxPhase.setValue(100)
dialog.doubleSpinBoxPhase.editingFinished.emit()
self.assertEqual(insert_sine_plugin.phase, 100)
while not dialog.doubleSpinBoxAmplitude.isEnabled():
self.app.processEvents()
QTest.qWait(10)
dialog.doubleSpinBoxSampleRate.setValue(2e6)
dialog.doubleSpinBoxSampleRate.editingFinished.emit()
self.assertEqual(insert_sine_plugin.sample_rate, 2e6)
while not dialog.doubleSpinBoxAmplitude.isEnabled():
self.app.processEvents()
QTest.qWait(10)
dialog.doubleSpinBoxNSamples.setValue(0.5e6)
dialog.doubleSpinBoxNSamples.editingFinished.emit()
self.assertEqual(insert_sine_plugin.num_samples, 0.5e6)
while not dialog.doubleSpinBoxAmplitude.isEnabled():
self.app.processEvents()
QTest.qWait(10)
sep = Formatter.local_decimal_seperator()
self.assertEqual(dialog.lineEditTime.text(), "250" + sep + "000m")
# Close the dialog via finished
dialog.finished.emit(0)
QApplication.instance().processEvents()
QTest.qWait(self.CLOSE_TIMEOUT)