From af54095d199dc481d071c2944a88c92ba2929312 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 11 Nov 2018 12:58:17 +0100 Subject: [PATCH] Add modulation filter algorithm --- download_window.py | 6 +- main.py | 65 +++++++++++++++++++-- main_window.ui | 140 ++++++++++++++++++++++++++++++++++++++++++++- threads.py | 18 +++--- utilities.py | 10 ++++ 5 files changed, 220 insertions(+), 19 deletions(-) diff --git a/download_window.py b/download_window.py index 764de5d..9ba58e7 100644 --- a/download_window.py +++ b/download_window.py @@ -59,11 +59,11 @@ class DownloadWindow(QWidget, Ui_Download_window): @pyqtSlot() def wait_close(self): - if self.download_thread.status == ThreadStatus.ok: + if self.download_thread.status == ThreadStatus.OK: self.close() - elif self.download_thread.status == ThreadStatus.no_connection_err: + elif self.download_thread.status == ThreadStatus.NO_CONNECTION_ERR: self.show_no_connection_warning() - elif self.download_thread.status == ThreadStatus.bad_download_err: + elif self.download_thread.status == ThreadStatus.BAD_DOWNLOAD_ERR: self.show_bad_download_warning else: self.close() diff --git a/main.py b/main.py index 9423216..8c6c90f 100644 --- a/main.py +++ b/main.py @@ -10,8 +10,10 @@ from PyQt5.QtWidgets import (QMainWindow, QMessageBox, qApp, QDesktopWidget, - QListWidgetItem,) -from PyQt5.QtGui import QPixmap + QListWidgetItem, + QTreeView, + QTreeWidgetItem) +from PyQt5.QtGui import QPixmap, QStandardItemModel, QStandardItem from PyQt5 import uic from PyQt5.QtCore import (QFileInfo, QSize, @@ -35,7 +37,6 @@ class MyApp(QMainWindow, Ui_MainWindow): self.download_window = DownloadWindow() self.actionExit.triggered.connect(qApp.quit) self.action_update_database.triggered.connect(self.download_db) - self.db_version = None self.db = None self.current_signal_name = '' self.signal_names = [] @@ -267,6 +268,17 @@ class MyApp(QMainWindow, Ui_MainWindow): self.url_button.clicked.connect(self.go_to_web_page_signal) + # Set modulation TreeView + + self.set_mode_tree_widget() + self.mode_tree_widget.itemSelectionChanged.connect(self.manage_mode_selections) + self.reset_mode_filters_btn.clicked.connect(self.reset_mode_filters) + self.apply_remove_mode_filter_btn.set_texts("Apply", "Remove") + self.apply_remove_mode_filter_btn.set_slave_filters([self.mode_tree_widget]) + self.apply_remove_mode_filter_btn.clicked.connect(self.display_signals) + self.reset_mode_filters_btn.clicked.connect(self.reset_mode_filters) + +# ########################################################################################## self.show() self.load_db() @@ -279,7 +291,7 @@ class MyApp(QMainWindow, Ui_MainWindow): self.volume, self.audio_progress, Constants.data_folder, - Constants.audio_folder) + Constants.audio_folder) # Da togliere///////////////// BandLabel = namedtuple("BandLabel", ["left", "center", "right"]) self.band_labels = [ @@ -296,6 +308,24 @@ class MyApp(QMainWindow, Ui_MainWindow): BandLabel(self.ehf_left, self.ehf, self.ehf_right), ] + def set_mode_tree_widget(self): + for parent, children in Constants.modes.items(): + iparent = QTreeWidgetItem([parent]) + self.mode_tree_widget.addTopLevelItem(iparent) + for child in children: + ichild = QTreeWidgetItem([child]) + iparent.addChild(ichild) + self.mode_tree_widget.expandAll() + + def manage_mode_selections(self): + selected_items = self.mode_tree_widget.selectedItems() + parents = Constants.modes.keys() + for parent in parents: + for item in selected_items: + if parent == item.text(0): + for i in range(len(Constants.modes[parent])): + item.child(i).setSelected(True) + def set_initial_size(self): """ Function to handle high resolution screens. The function sets bigger sizes @@ -494,7 +524,8 @@ class MyApp(QMainWindow, Ui_MainWindow): if text.lower() in signal.lower() and \ self.frequency_filters_ok(signal) and \ self.band_filters_ok(signal) and \ - self.category_filters_ok(signal): + self.category_filters_ok(signal) and \ + self.mode_filters_ok(signal): self.result_list.addItem(signal) available_signals += 1 self.update_status_tip(available_signals) @@ -552,6 +583,13 @@ class MyApp(QMainWindow, Ui_MainWindow): f.setChecked(False) if f.isChecked() else None self.cat_at_least_one.setChecked(True) + def reset_mode_filters(self): + if self.apply_remove_mode_filter_btn.isChecked(): + self.apply_remove_mode_filter_btn.setChecked(False) + self.apply_remove_mode_filter_btn.clicked.emit() + for item in self.mode_tree_widget.selectedItems(): + item.setSelected(False) + def frequency_filters_ok(self, signal_name): if not self.apply_remove_freq_filter_btn.isChecked(): return True @@ -632,6 +670,22 @@ class MyApp(QMainWindow, Ui_MainWindow): else: return cat_checked == positive_cases and cat_checked > 0 + def mode_filters_ok(self, signal_name): + if not self.apply_remove_mode_filter_btn.isChecked(): + return True + selected_items = [item for item in self.mode_tree_widget.selectedItems()] + selected_items_text = [i.text(0) for i in selected_items] + parents = [item for item in selected_items_text if item in Constants.modes.keys()] + children = [item for item in selected_items_text if item not in parents] + signal_mode = self.db.at[signal_name, "mode"] + ok = [] + for item in selected_items: + if item.text(0) in parents: + ok.append(item.text(0) in signal_mode) + elif not item.parent().isSelected(): + ok.append(item.text(0) == signal_mode) + return any(ok) + @staticmethod def filters_ok(spinbox, filter_unit, confidence, sign = 1): band_filter = spinbox.value() * Constants.conversion_factors[filter_unit.currentText()] @@ -779,6 +833,7 @@ class MyApp(QMainWindow, Ui_MainWindow): self.reset_frequency_filters_btn.clicked.emit() self.reset_band_filters_btn.clicked.emit() self.reset_cat_filters_btn.clicked.emit() + self.reset_mode_filters_btn.clicked.emit() @pyqtSlot() def go_to_web_page_signal(self): diff --git a/main_window.ui b/main_window.ui index 32fcc1d..aaae821 100644 --- a/main_window.ui +++ b/main_window.ui @@ -323,7 +323,7 @@ QPushButton:!enabled { QTabWidget::Rounded - 0 + 1 true @@ -1962,7 +1962,7 @@ QPushButton:checked { - 0 + 3 true @@ -3691,6 +3691,142 @@ Inactive Mode + + + + + QWidget#mode_filter_container { + border: 1px solid gray; + border-radius: 15px; +} + +QWidget#FM_container, QWidget#SK_container, QWidget#SB_container{ + border: 1px solid gray; + border-radius: 10px; +} + +QWidget#xFM_container, QWidget#xSK_container, QWidget#xSB_container{ + border: 1px solid gray; + border-radius: 8px; +} + + + + + + + 12 + 75 + true + + + + Include unknown modulations + + + true + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 12 + 75 + true + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::MultiSelection + + + QAbstractItemView::SelectItems + + + true + + + true + + + 1 + + + + 1 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 12 + 75 + true + + + + Apply + + + true + + + + + + + + 12 + 75 + true + + + + Reset + + + + diff --git a/threads.py b/threads.py index 86596a0..99db647 100644 --- a/threads.py +++ b/threads.py @@ -9,15 +9,15 @@ from PyQt5.QtCore import QThread from utilities import checksum_ok, Constants class ThreadStatus(Enum): - ok = auto() - no_connection_err = auto() - no_file_err = auto() - bad_download_err = auto() + OK = auto() + NO_CONNECTION_ERR = auto() + UNKNOWN_ERR = auto() + BAD_DOWNLOAD_ERR = auto() class DownloadThread(QThread): def __init__(self): super().__init__() - self.__status = ThreadStatus.ok + self.__status = ThreadStatus.OK self.reason = 0 @property @@ -34,14 +34,14 @@ class DownloadThread(QThread): # db = urllib.request.urlopen(Constants.db_location) # raise urllib.error.URLError('Test') except urllib3.exceptions.MaxRetryError: # No internet connection. - self.__status = ThreadStatus.no_connection_err + self.__status = ThreadStatus.NO_CONNECTION_ERR return if db.status != 200: self.reason = db.reason - self.__status = ThreadStatus.bad_download_err + self.__status = ThreadStatus.BAD_DOWNLOAD_ERR return if not checksum_ok(db.data, "folder"): - self.__status = ThreadStatus.bad_download_err + self.__status = ThreadStatus.BAD_DOWNLOAD_ERR return if os.path.exists(Constants.data_folder): rmtree(Constants.data_folder) @@ -50,4 +50,4 @@ class DownloadThread(QThread): with ZipFile(BytesIO(db.data)) as zipped: zipped.extractall() except: - self.__status = ThreadStatus.bad_file_err + self.__status = ThreadStatus.UNKNOWN_ERR diff --git a/utilities.py b/utilities.py index a787a69..4196783 100644 --- a/utilities.py +++ b/utilities.py @@ -36,6 +36,16 @@ class Constants(object): active_color = _ReadOnlyProperty("#39eaff") inactive_color = _ReadOnlyProperty("#9f9f9f") conversion_factors = _ReadOnlyProperty({"Hz":1, "kHz":1000, "MHz":1000000, "GHz":1000000000}) + modes = _ReadOnlyProperty({"FM": ["NFM", "WFM"], + "AM": [], + "CW": [], + "SK": ["FSK", "PSK", "MSK"], + "SB": ["LSB", "USB", "DSB"], + "Chirp Spread Spectrum": [], + "FHSS-TDM": [], + "RAW": [], + "SC-FDMA": [],} + ) def checksum_ok(data, what):