273 lines
11 KiB
Python
273 lines
11 KiB
Python
import sys
|
|
import os
|
|
import webbrowser
|
|
from collections import namedtuple
|
|
|
|
from pandas import read_csv
|
|
from PyQt5.QtWidgets import (QMainWindow,
|
|
QApplication,
|
|
QMessageBox,
|
|
qApp,)
|
|
from PyQt5.QtGui import QPixmap
|
|
from PyQt5 import uic
|
|
from PyQt5.QtCore import QFileInfo, QSize
|
|
|
|
from audio_player import AudioPlayer
|
|
|
|
qt_creator_file = "main_window.ui"
|
|
|
|
Ui_MainWindow, _ = uic.loadUiType(qt_creator_file)
|
|
|
|
class MyApp(QMainWindow, Ui_MainWindow):
|
|
Band = namedtuple("Band", ["lower", "upper"])
|
|
ELF = Band(3, 30)
|
|
SLF = Band(30, 300)
|
|
ULF = Band(300, 3000)
|
|
VLF = Band(3000, 30000)
|
|
LF = Band(30 * 10**3, 300 * 10**3)
|
|
MF = Band(300 * 10 ** 3, 3000 * 10**3)
|
|
HF = Band(3 * 10**6, 30 * 10**6)
|
|
VHF = Band(30 * 10**6, 300 * 10**6)
|
|
UHF = Band(300 * 10**6, 3000 * 10**6)
|
|
SHF = Band(3 * 10**9, 30 * 10**9)
|
|
EHF = Band(30 * 10**9, 300 * 10**9)
|
|
bands = ELF, SLF, ULF, VLF, LF, MF, HF, VHF, UHF, SHF, EHF
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.setupUi(self)
|
|
self.show()
|
|
self.actionExit.triggered.connect(qApp.quit)
|
|
self.db_version = None
|
|
self.db = None
|
|
self.current_signal_name = ''
|
|
self.signal_names = []
|
|
self.category_labels = [self.cat_mil,
|
|
self.cat_rad,
|
|
self.cat_active,
|
|
self.cat_inactive,
|
|
self.cat_ham,
|
|
self.cat_comm,
|
|
self.cat_avi,
|
|
self.cat_mar,
|
|
self.cat_ana,
|
|
self.cat_dig,
|
|
self.cat_trunked,
|
|
self.cat_utility,
|
|
self.cat_sat,
|
|
self.cat_navi,
|
|
self.cat_interf,
|
|
self.cat_num_stat,
|
|
self.cat_time_sig,]
|
|
|
|
self.property_labels = [self.name_lab,
|
|
self.freq_lab,
|
|
self.band_lab,
|
|
self.mode_lab,
|
|
self.modul_lab,
|
|
self.loc_lab,
|
|
self.acf_lab,
|
|
self.description_text,]
|
|
|
|
self.url_button.clicked.connect(self.go_to_web_page_signal)
|
|
self.load_db()
|
|
self.display_signals()
|
|
self.search_bar.textChanged.connect(self.display_signals)
|
|
self.result_list.currentItemChanged.connect(self.display_specs)
|
|
self.audio_widget = AudioPlayer(self.play,
|
|
self.pause,
|
|
self.stop,
|
|
self.volume,
|
|
self.audio_progress)
|
|
|
|
self.band_labels = [
|
|
[self.elf, self.elf_s1, self.elf_s2],
|
|
[self.slf, self.slf_s1, self.slf_s2],
|
|
[self.ulf, self.ulf_s1, self.ulf_s2],
|
|
[self.vlf, self.vlf_s1, self.vlf_s2],
|
|
[self.lf , self.lf_s1 , self.lf_s2],
|
|
[self.mf , self.mf_s1 , self.mf_s2],
|
|
[self.hf , self.hf_s1 , self.hf_s2],
|
|
[self.vhf, self.vhf_s1, self.vhf_s2],
|
|
[self.uhf, self.uhf_s1, self.uhf_s2],
|
|
[self.shf, self.shf_s1, self.shf_s2],
|
|
[self.ehf, None, None],
|
|
]
|
|
|
|
def load_db(self):
|
|
try:
|
|
self.db = read_csv(os.path.join('Data', 'db.csv'),
|
|
sep = '*',
|
|
header = None,
|
|
index_col = 0,
|
|
dtype = {'inf_freq': str,
|
|
'sup_freq': str,
|
|
'mode': str,
|
|
'inf_band': str,
|
|
'sup_band': str,
|
|
'category_code': str,},
|
|
names = ["name",
|
|
"inf_freq",
|
|
"sup_freq",
|
|
"mode",
|
|
"inf_band",
|
|
"sup_band",
|
|
"location",
|
|
"url",
|
|
"description",
|
|
"modulation",
|
|
"category_code",
|
|
"acf",],
|
|
)
|
|
self.db.fillna("N/A", inplace = True)
|
|
except FileNotFoundError:
|
|
self.search_bar.setDisabled(True)
|
|
box = QMessageBox(self)
|
|
box.setWindowTitle("No database")
|
|
box.setText("No database available.\n"
|
|
"Go to Updates->Download database.")
|
|
box.show()
|
|
else:
|
|
self.signal_names = self.db.index
|
|
|
|
try:
|
|
with open(os.path.join('Data', 'verdb.ini'), 'r') as dbver:
|
|
self.db_version = int(dbver.read())
|
|
except (FileNotFoundError, ValueError):
|
|
box = QMessageBox(self)
|
|
box.setWindowTitle("No database version")
|
|
box.setText("Unable to detect database version.\n"
|
|
"Possible data curruption.\n"
|
|
"Go to Updates->Force Download.")
|
|
box.show()
|
|
self.setStatusTip("Database version: undefined.")
|
|
else:
|
|
self.setStatusTip(f"Database version: {self.db_version}")
|
|
|
|
|
|
def display_signals(self):
|
|
self.result_list.clear()
|
|
for signal in self.signal_names:
|
|
if self.search_bar.text().lower() in signal.lower():
|
|
self.result_list.addItem(signal)
|
|
|
|
def display_specs(self):
|
|
self.display_spectrogram()
|
|
item = self.result_list.currentItem()
|
|
if item:
|
|
self.url_button.setEnabled(True)
|
|
self.url_button.setStyleSheet("color: #4c75ff;")
|
|
self.current_signal_name = item.text()
|
|
words = self.current_signal_name.split(' ')
|
|
if len(words) > 3:
|
|
words_per_row = len(words) // 2
|
|
words = ' '.join(words[:words_per_row]) \
|
|
+ "\n" + ' '.join(words[words_per_row:])
|
|
else:
|
|
words = self.current_signal_name
|
|
self.name_lab.setText(words)
|
|
current_signal = self.db.loc[self.current_signal_name]
|
|
print(current_signal.loc["inf_band"], current_signal.loc["sup_band"])
|
|
category_code = current_signal.loc["category_code"]
|
|
self.freq_lab.setText(self.format_numbers(
|
|
current_signal.loc["inf_freq"],
|
|
current_signal.loc["sup_freq"])
|
|
)
|
|
self.band_lab.setText(self.format_numbers(
|
|
current_signal.loc["inf_band"],
|
|
current_signal.loc["sup_band"])
|
|
)
|
|
self.mode_lab.setText(current_signal.loc["mode"])
|
|
self.modul_lab.setText(current_signal.loc["modulation"])
|
|
self.loc_lab.setText(current_signal.loc["location"])
|
|
self.acf_lab.setText(current_signal.loc["acf"])
|
|
self.description_text.setText(current_signal.loc["description"])
|
|
for cat, cat_lab in zip(category_code, self.category_labels):
|
|
if cat == '0':
|
|
cat_lab.setStyleSheet("color: #9f9f9f;")
|
|
elif cat == '1':
|
|
cat_lab.setStyleSheet("color: #39eaff;")
|
|
self.set_band_range(current_signal)
|
|
self.audio_widget.set_audio_player(self.current_signal_name)
|
|
else:
|
|
self.url_button.setEnabled(False)
|
|
self.url_button.setStyleSheet("color: #898989;")
|
|
self.current_signal_name = ''
|
|
for lab in self.property_labels:
|
|
lab.setText("N/A")
|
|
for lab in self.category_labels:
|
|
lab.setStyleSheet("""color: #9f9f9f;""")
|
|
self.set_band_range()
|
|
self.audio_widget.set_audio_player()
|
|
|
|
@classmethod
|
|
def format_numbers(cls, lower, upper):
|
|
units = {1: 'Hz', 1000: 'kHz', 10**6: 'MHz', 10**9: 'GHz'}
|
|
lower_factor = cls.change_unit(lower)
|
|
upper_factor = cls.change_unit(upper)
|
|
if lower != upper:
|
|
lower = int(lower) / lower_factor
|
|
upper = int(upper) / upper_factor
|
|
return f"{lower} {units[lower_factor]} - {upper} {units[upper_factor]}"
|
|
else:
|
|
lower = int(lower) / lower_factor
|
|
return f"{lower} {units[lower_factor]}"
|
|
|
|
@staticmethod
|
|
def change_unit(num):
|
|
digits = len(num)
|
|
if digits < 4:
|
|
return 1
|
|
elif digits < 7:
|
|
return 1000
|
|
elif digits < 10:
|
|
return 10**6
|
|
else:
|
|
return 10**9
|
|
|
|
def display_spectrogram(self):
|
|
default_pic = os.path.join("icons_imgs", "image_not_found.png")
|
|
item = self.result_list.currentItem()
|
|
if item:
|
|
spectrogram_name = item.text()
|
|
path_spectr = os.path.join("Data", "Spectra", spectrogram_name + ".jpg")
|
|
if not QFileInfo(path_spectr).exists():
|
|
path_spectr = default_pic
|
|
else:
|
|
path_spectr = default_pic
|
|
self.spectrogram.setPixmap(QPixmap(path_spectr))
|
|
|
|
def set_band_range(self, current_signal = None):
|
|
# How to deal with one-frequency signals?
|
|
if current_signal is not None:
|
|
inf_band = int(current_signal.loc["inf_freq"])
|
|
sup_band = int(current_signal.loc["sup_freq"])
|
|
for band, band_label in zip(self.bands, self.band_labels):
|
|
delta = (band.upper - band.lower) // 2 + band.lower
|
|
if inf_band <= band.lower and sup_band > band.lower:
|
|
band_label[0].setStyleSheet("color: #39eaff;")
|
|
else:
|
|
band_label[0].setStyleSheet("color: #9f9f9f;")
|
|
if band_label[1]:
|
|
if inf_band <= delta and sup_band >= delta:
|
|
band_label[1].setStyleSheet("color: #39eaff;")
|
|
else:
|
|
band_label[1].setStyleSheet("color: #9f9f9f;")
|
|
if band_label[2]:
|
|
if inf_band <= band.upper and sup_band > band.upper:
|
|
band_label[2].setStyleSheet("color: #39eaff;")
|
|
else:
|
|
band_label[2].setStyleSheet("color: #9f9f9f;")
|
|
else:
|
|
[label.setStyleSheet("color: #9f9f9f;") for labels in self.band_labels for label in labels if label]
|
|
|
|
def go_to_web_page_signal(self):
|
|
if self.current_signal_name:
|
|
webbrowser.open(self.db.loc[self.current_signal_name].loc["url"])
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
my_app = QApplication(sys.argv)
|
|
w = MyApp()
|
|
sys.exit(my_app.exec_()) |