Skip to content

Commit

Permalink
add support for already demodulated signals (#780)
Browse files Browse the repository at this point in the history
Treat single channel wav files as already demodulated data.
  • Loading branch information
jopohl committed May 28, 2020
1 parent 1d3981c commit c1ed0ef
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 13 deletions.
1 change: 1 addition & 0 deletions data/azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
python -m pip install --upgrade pip twine
pip install -r data/requirements.txt
sudo apt-get install libhackrf-dev librtlsdr-dev xvfb libxkbcommon-x11-0 x11-utils
pip install PyVirtualDisplay!=1.0,!=1.1
pip install twine setuptools wheel pytest pytest-xvfb pytest-cov pytest-faulthandler
python -c "import tempfile, os; open(os.path.join(tempfile.gettempdir(), 'urh_releasing'), 'w').close()"
displayName: 'Install dependencies'
Expand Down
3 changes: 2 additions & 1 deletion src/urh/controller/MainController.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ def add_signal(self, signal, group_id=0, index=-1):
if self.ui.actionAuto_detect_new_signals.isChecked() and not has_entry and not signal.changed:
sig_frame.ui.stackedWidget.setCurrentWidget(sig_frame.ui.pageLoading)
qApp.processEvents()
signal.auto_detect(detect_modulation=True, detect_noise=False)
if not signal.already_demodulated:
signal.auto_detect(detect_modulation=True, detect_noise=False)
sig_frame.ui.stackedWidget.setCurrentWidget(sig_frame.ui.pageSignal)

signal.blockSignals(False)
Expand Down
47 changes: 36 additions & 11 deletions src/urh/controller/widgets/SignalFrame.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,22 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, pro
self.configure_filter_action.triggered.connect(self.on_configure_filter_action_triggered)
self.ui.btnFilter.setMenu(self.filter_menu)

self.auto_detect_menu = QMenu()
self.detect_noise_action = self.auto_detect_menu.addAction(self.tr("Additionally detect noise"))
self.detect_noise_action.setCheckable(True)
self.detect_noise_action.setChecked(False)
self.detect_modulation_action = self.auto_detect_menu.addAction(self.tr("Additionally detect modulation"))
self.detect_modulation_action.setCheckable(True)
self.detect_modulation_action.setChecked(False)
self.ui.btnAutoDetect.setMenu(self.auto_detect_menu)
if not self.signal.already_demodulated:
self.auto_detect_menu = QMenu()
self.detect_noise_action = self.auto_detect_menu.addAction(self.tr("Additionally detect noise"))
self.detect_noise_action.setCheckable(True)
self.detect_noise_action.setChecked(False)
self.detect_modulation_action = self.auto_detect_menu.addAction(self.tr("Additionally detect modulation"))
self.detect_modulation_action.setCheckable(True)
self.detect_modulation_action.setChecked(False)
self.ui.btnAutoDetect.setMenu(self.auto_detect_menu)


if self.signal.wav_mode:
self.ui.lSignalTyp.setText("Signal (*.wav)")
if self.signal.already_demodulated:
self.ui.lSignalTyp.setText("Demodulated (1-channel *.wav)")
else:
self.ui.lSignalTyp.setText("Signal (*.wav)")
else:
self.ui.lSignalTyp.setText("Complex Signal")

Expand Down Expand Up @@ -149,6 +154,16 @@ def __init__(self, proto_analyzer: ProtocolAnalyzer, undo_stack: QUndoStack, pro

self.show_protocol(refresh=False)

if self.signal.already_demodulated:
self.ui.cbModulationType.hide()
self.ui.labelModulation.hide()
self.ui.labelNoise.hide()
self.ui.spinBoxNoiseTreshold.hide()
self.ui.btnAutoDetect.hide()
self.ui.cbSignalView.setCurrentIndex(1)
self.ui.cbSignalView.hide()
self.ui.lSignalViewText.hide()

else:
self.ui.lSignalTyp.setText("Protocol")
self.set_empty_frame_visibilities()
Expand Down Expand Up @@ -748,8 +763,18 @@ def on_cb_signal_view_index_changed(self):
def on_btn_autodetect_clicked(self):
self.ui.btnAutoDetect.setEnabled(False)
self.setCursor(Qt.WaitCursor)
success = self.signal.auto_detect(detect_modulation=self.detect_modulation_action.isChecked(),
detect_noise=self.detect_noise_action.isChecked())

try:
detect_modulation = self.detect_modulation_action.isChecked()
except AttributeError:
detect_modulation = False

try:
detect_noise = self.detect_noise_action.isChecked()
except AttributeError:
detect_noise = False
success = self.signal.auto_detect(detect_modulation=detect_modulation, detect_noise=detect_noise)

self.ui.btnAutoDetect.setEnabled(True)
self.unsetCursor()
if not success:
Expand Down
12 changes: 11 additions & 1 deletion src/urh/signalprocessing/Signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def __init__(self, filename: str, name="Signal", modulation: str = None, sample_

self.__parameter_cache = {mod: {"center": None, "samples_per_symbol": None} for mod in self.MODULATION_TYPES}

self.__already_demodulated = False

if len(filename) > 0:
if self.wav_mode:
self.__load_wav_file(filename)
Expand Down Expand Up @@ -110,6 +112,7 @@ def __load_wav_file(self, filename: str):
self.iq_array = IQArray(None, np.float32, n=num_frames)
if num_channels == 1:
self.iq_array.real = np.multiply(1 / params["max"], np.subtract(data, params["center"]))
self.__already_demodulated = True
elif num_channels == 2:
self.iq_array.real = np.multiply(1 / params["max"], np.subtract(data[0::2], params["center"]))
self.iq_array.imag = np.multiply(1 / params["max"], np.subtract(data[1::2], params["center"]))
Expand All @@ -128,6 +131,10 @@ def __load_compressed_complex(self, filename: str):
self.__load_complex_file(extracted_filename)
os.remove(extracted_filename)

@property
def already_demodulated(self) -> bool:
return self.__already_demodulated

@property
def sample_rate(self):
return self.__sample_rate
Expand Down Expand Up @@ -313,7 +320,10 @@ def noise_threshold_relative(self, value: float):
@property
def qad(self):
if self._qad is None:
self._qad = self.quad_demod()
if self.already_demodulated:
self._qad = np.ascontiguousarray(self.real_plot_data, dtype=self.real_plot_data.dtype)
else:
self._qad = self.quad_demod()

return self._qad

Expand Down
Binary file added tests/data/demodulated.wav
Binary file not shown.
11 changes: 11 additions & 0 deletions tests/test_signal_tab_GUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@ def test_context_menu_text_edit_protocol_view(self):
menu = text_edit.create_context_menu()
self.assertEqual(len([action for action in menu.actions() if action.text() == "Participant"]), 1)

def test_load_already_demodulated(self):
self.add_signal_to_form("demodulated.wav")
assert isinstance(self.form, MainController)

sig_frame = self.form.signal_tab_controller.signal_frames[0]
sig_frame.ui.cbProtoView.setCurrentText("Hex")
sig_frame.ui.spinBoxCenterOffset.setValue(0.0459)
sig_frame.ui.spinBoxCenterOffset.editingFinished.emit()

self.assertTrue(sig_frame.ui.txtEdProto.toPlainText().startswith("abcd"))

def test_export_demodulated(self):
self.add_signal_to_form("esaver.complex16s")
assert isinstance(self.form, MainController)
Expand Down

0 comments on commit c1ed0ef

Please sign in to comment.