From 584d21a5336595f23c50add5fb44d6f2051d29cf Mon Sep 17 00:00:00 2001 From: G4IXT Date: Fri, 26 Apr 2024 17:29:38 +0100 Subject: [PATCH] v0.10.3 release CSV import bugfixes Preset marker improvements --- QtTSApreferences.py | 1 + QtTSAprefs.db | Bin 126976 -> 131072 bytes QtTinySA.py | 74 ++++---- QtTinySpectrum.py | 9 +- QtTinySpectrum.ui | 9 +- Sample_preset_markers/TV_channels.csv | 41 +++++ Sample_preset_markers/TV_channels.ods | Bin 0 -> 24949 bytes Sample_preset_markers/TV_channels_test.csv | 3 + Sample_preset_markers/broadcast.csv | 79 +++++++++ Sample_preset_markers/markers.event.2024.csv | 166 ++++++++++++++++++ .../markers.event.2024_subset.csv | 4 + preferences.ui | 6 +- 12 files changed, 350 insertions(+), 42 deletions(-) create mode 100644 Sample_preset_markers/TV_channels.csv create mode 100644 Sample_preset_markers/TV_channels.ods create mode 100644 Sample_preset_markers/TV_channels_test.csv create mode 100644 Sample_preset_markers/broadcast.csv create mode 100644 Sample_preset_markers/markers.event.2024.csv create mode 100644 Sample_preset_markers/markers.event.2024_subset.csv diff --git a/QtTSApreferences.py b/QtTSApreferences.py index 2f0a4f1..02dc0e1 100644 --- a/QtTSApreferences.py +++ b/QtTSApreferences.py @@ -72,6 +72,7 @@ def setupUi(self, Preferences): self.label_12.setObjectName("label_12") self.gridLayout.addWidget(self.label_12, 3, 0, 1, 1) self.filterBox = QtWidgets.QComboBox(self.layoutWidget) + self.filterBox.setEditable(False) self.filterBox.setObjectName("filterBox") self.gridLayout.addWidget(self.filterBox, 3, 1, 1, 1) self.exportButton = QtWidgets.QPushButton(self.layoutWidget) diff --git a/QtTSAprefs.db b/QtTSAprefs.db index b74cccab504ea196fe9fca18c88eff73712da338..3e02207fb2140ad8e9fb536c93ab8eec3c6cff60 100644 GIT binary patch delta 5286 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 diff --git a/QtTinySA.py b/QtTinySA.py index af48354..ff50d3c 100755 --- a/QtTinySA.py +++ b/QtTinySA.py @@ -684,14 +684,14 @@ def updateMarker(self, frequencies, readings, fPeaks): # called by updateGUI() else: self.vline.label.setText(f'M{self.vline.name()} {self.vline.value():.3f}MHz {dBm:.1f}dBm') - def addFreqMarker(self, freq, colour, name): # adds simple frequency marker without full marker capability + def addFreqMarker(self, freq, colour, name, position): # adds simple freq marker without full marker capability if ui.presetLabel.isChecked(): - marker = ui.graphWidget.addLine(freq, 90, pen=pyqtgraph.mkPen(colour, width=0.5, style=QtCore.Qt.DashLine), - label=name, labelOpts={'position': 0.05, 'color': (colour)}) - marker.label.setMovable(True) + self.marker = ui.graphWidget.addLine(freq, 90, pen=pyqtgraph.mkPen(colour, width=0.5, style=QtCore.Qt.DashLine), + label=name, labelOpts={'position': position, 'color': (colour)}) + self.marker.label.setMovable(True) else: - marker = ui.graphWidget.addLine(freq, 90, pen=pyqtgraph.mkPen(colour, width=0.5, style=QtCore.Qt.DashLine)) - self.fifo.put(marker) # store the marker object in a queue + self.marker = ui.graphWidget.addLine(freq, 90, pen=pyqtgraph.mkPen(colour, width=0.5, style=QtCore.Qt.DashLine)) + self.fifo.put(self.marker) # store the marker object in a queue def delFreqMarkers(self): for i in range(0, self.fifo.qsize()): @@ -846,7 +846,7 @@ def readCSV(self, fileName): for row in reader: record = self.tm.record() for key, value in row.items(): - # relational mapping doesn't work for these fields + # don't understand how to make relation work for these fields if key == 'preset': value = presetID(value) if key.lower() == 'colour': @@ -1040,20 +1040,25 @@ def popUp(message, button, icon): def freqMarkers(): + presetmarker.tm.select() S1.delFreqMarkers() S2.delFreqMarkers() - if ui.presetMarker.isChecked(): - for i in range(0, bands.tm.rowCount()): - try: - startF = bands.tm.record(i).value('StartF') - colour = bands.tm.record(i).value('colour') - name = bands.tm.record(i).value('name') - S1.addFreqMarker(startF, colour, name) - stopF = bands.tm.record(i).value('StopF') - if bandstype.tm.record(ui.filterBox.currentIndex()).value('type') == 'band': - S2.addFreqMarker(stopF, colour, '') - except ValueError: - continue + for i in range(0, presetmarker.tm.rowCount()): + try: + startF = presetmarker.tm.record(i).value('StartF') + colour = presetmarker.tm.record(i).value('colour') + name = presetmarker.tm.record(i).value('name') + if ui.presetMarker.isChecked() and presetmarker.tm.record(i).value('visible')\ + and presetmarker.tm.record(i).value('type') != 'band': + S1.addFreqMarker(startF, colour, name, 0.05) + if ui.presetLabel.isChecked() and ui.presetLabel.checkState() == 2: + S1.marker.label.setAngle(90) + if presetmarker.tm.record(i).value('type') == 'band': + stopF = presetmarker.tm.record(i).value('StopF') + S1.addFreqMarker(startF, colour, name, 0.98) + S2.addFreqMarker(stopF, colour, name, 0.98) + except ValueError: + continue def freqMarkerLabel(): @@ -1114,7 +1119,6 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour. ############################################################################### # Instantiate classes - tinySA = analyser() app = QtWidgets.QApplication([]) # create QApplication for the GUI @@ -1149,6 +1153,7 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour. colours = modelView('SVGColour') maps = modelView('mapping') +presetmarker = modelView(('frequencies')) ############################################################################### # GUI settings @@ -1181,7 +1186,6 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour. S4.hline.setMovable(True) S4.hline.label.setFormat("{value:.1f}") - ############################################################################### # Connect signals from buttons and sliders. Connections for freq and rbw boxes are in 'initialise' Fn @@ -1218,9 +1222,10 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour. ui.m4_type.activated.connect(S4.mType) # frequency band markers -ui.presetMarker.stateChanged.connect(freqMarkers) +ui.presetMarker.clicked.connect(freqMarkers) ui.presetLabel.stateChanged.connect(freqMarkerLabel) ui.mToBand.clicked.connect(addBandPressed) +ui.filterBox.currentTextChanged.connect(freqMarkers) # trace checkboxes ui.trace1.stateChanged.connect(S1.tEnable) @@ -1276,30 +1281,32 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour. # table models - read/write views of the configuration data maps.createTableModel() maps.tm.select() -bands.createTableModel() # relational + +bands.createTableModel() bands.tm.setSort(3, QtCore.Qt.AscendingOrder) bands.tm.setHeaderData(5, QtCore.Qt.Horizontal, 'visible') bands.tm.setHeaderData(7, QtCore.Qt.Horizontal, 'LO') - +bands.tm.setEditStrategy(QSqlRelationalTableModel.OnFieldChange) +bands.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'preset')) # set 'type' column to a freq type choice combo box bands.tm.setRelation(5, QSqlRelation('boolean', 'ID', 'value')) # set 'view' column to a True/False choice combo box -boolean = QSqlRelationalDelegate(preferences.freqBands) -preferences.freqBands.setItemDelegate(boolean) - bands.tm.setRelation(6, QSqlRelation('SVGColour', 'ID', 'colour')) # set 'marker' column to a colours choice combo box -colour = QSqlRelationalDelegate(preferences.freqBands) -preferences.freqBands.setItemDelegate(colour) - -bands.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'preset')) # set 'type' column to a freq type choice combo box -preset = QSqlRelationalDelegate(preferences.freqBands) -preferences.freqBands.setItemDelegate(preset) +presets = QSqlRelationalDelegate(preferences.freqBands) +preferences.freqBands.setItemDelegate(presets) colHeader = preferences.freqBands.horizontalHeader() colHeader.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) bandstype.createTableModel() +bandstype.tm.select() + colours.createTableModel() colours.tm.select() +presetmarker.createTableModel() +presetmarker.tm.setRelation(6, QSqlRelation('SVGColour', 'ID', 'colour')) +presetmarker.tm.setRelation(2, QSqlRelation('freqtype', 'ID', 'type')) +presetmarker.tm.select() + # populate the band presets combo box ui.band_box.setModel(bands.tm) ui.band_box.setModelColumn(1) @@ -1310,7 +1317,6 @@ def colourID(shade): # using the QSQLRelation directly doesn't work for colour. preferences.filterBox.setModelColumn(1) ui.filterBox.setModel(bandstype.tm) ui.filterBox.setModelColumn(1) -bandstype.tm.select() # connect the preferences dialogue box freq band table widget to the data model preferences.freqBands.setModel(bands.tm) diff --git a/QtTinySpectrum.py b/QtTinySpectrum.py index 68b4b46..89220d3 100644 --- a/QtTinySpectrum.py +++ b/QtTinySpectrum.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'QtTinySpectrum_small.ui' +# Form implementation generated from reading ui file 'QtTinySpectrum.ui' # # Created by: PyQt5 UI code generator 5.15.10 # @@ -500,6 +500,7 @@ def setupUi(self, MainWindow): font = QtGui.QFont() font.setPointSize(8) self.presetLabel.setFont(font) + self.presetLabel.setTristate(True) self.presetLabel.setObjectName("presetLabel") self.gridLayout_2.addWidget(self.presetLabel, 2, 10, 1, 1) self.marker3 = QtWidgets.QCheckBox(self.ViewNormal) @@ -976,7 +977,7 @@ def retranslateUi(self, MainWindow): self.filterBox.setToolTip(_translate("MainWindow", "Filter preset list")) self.centre_freq.setToolTip(_translate("MainWindow", "Sweep Centre")) self.scan_button.setText(_translate("MainWindow", "Run")) - self.presetMarker.setToolTip(_translate("MainWindow", "Mark preset freqs")) + self.presetMarker.setToolTip(_translate("MainWindow", "Show markers for preset freqs")) self.presetMarker.setText(_translate("MainWindow", "Presets")) self.band_box.setToolTip(_translate("MainWindow", "

Preset Frequency list

")) self.m4_type.setToolTip(_translate("MainWindow", "Marker Type")) @@ -985,8 +986,8 @@ def retranslateUi(self, MainWindow): self.m3_type.setToolTip(_translate("MainWindow", "Marker type")) self.marker4.setText(_translate("MainWindow", "M4")) self.start_freq.setToolTip(_translate("MainWindow", "Sweep Start")) - self.presetLabel.setToolTip(_translate("MainWindow", "Label preset freqs")) - self.presetLabel.setText(_translate("MainWindow", "Labels")) + self.presetLabel.setToolTip(_translate("MainWindow", "Show/hide/rotate preset marker labels")) + self.presetLabel.setText(_translate("MainWindow", "Label")) self.marker3.setText(_translate("MainWindow", "M3")) self.timeSpectrum.setToolTip(_translate("MainWindow", "3D spectrum")) self.timeSpectrum.setText(_translate("MainWindow", "3D")) diff --git a/QtTinySpectrum.ui b/QtTinySpectrum.ui index cad2e7f..b7814d7 100644 --- a/QtTinySpectrum.ui +++ b/QtTinySpectrum.ui @@ -848,7 +848,7 @@ - Mark preset freqs + Show markers for preset freqs Presets @@ -1065,10 +1065,13 @@ - Label preset freqs + Show/hide/rotate preset marker labels - Labels + Label + + + true diff --git a/Sample_preset_markers/TV_channels.csv b/Sample_preset_markers/TV_channels.csv new file mode 100644 index 0000000..65a5b0a --- /dev/null +++ b/Sample_preset_markers/TV_channels.csv @@ -0,0 +1,41 @@ +name,preset,startF,stopF,value,colour +21,marker,474,,TRUE,orange +22,marker,482,,TRUE,orange +23,marker,490,,TRUE,orange +24,marker,498,,TRUE,orange +25,marker,506,,TRUE,orange +26,marker,514,,TRUE,orange +27,marker,522,,TRUE,orange +28,marker,530,,TRUE,orange +29,marker,538,,TRUE,orange +30,marker,546,,TRUE,orange +31,marker,554,,TRUE,orange +32,marker,562,,TRUE,orange +33,marker,570,,TRUE,orange +34,marker,578,,TRUE,orange +35,marker,586,,TRUE,orange +36,marker,594,,TRUE,orange +37,marker,602,,TRUE,orange +38,marker,610,,TRUE,orange +39,marker,618,,TRUE,orange +40,marker,626,,TRUE,orange +41,marker,634,,TRUE,orange +42,marker,642,,TRUE,orange +43,marker,650,,TRUE,orange +44,marker,658,,TRUE,orange +45,marker,666,,TRUE,orange +46,marker,674,,TRUE,orange +47,marker,682,,TRUE,orange +48,marker,690,,TRUE,orange +49,marker,698,,TRUE,orange +50,marker,706,,TRUE,orange +51,marker,714,,TRUE,orange +52,marker,722,,TRUE,orange +53,marker,730,,TRUE,orange +54,marker,738,,TRUE,orange +55,marker,746,,TRUE,orange +56,marker,754,,TRUE,orange +57,marker,762,,TRUE,orange +58,marker,770,,TRUE,orange +59,marker,778,,TRUE,orange +60,marker,786,,TRUE,orange diff --git a/Sample_preset_markers/TV_channels.ods b/Sample_preset_markers/TV_channels.ods new file mode 100644 index 0000000000000000000000000000000000000000..7ffaac266c115c56b999a86df9c71f446febf268 GIT binary patch literal 24949 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 - + + + false + +