Skip to content

Commit

Permalink
v0.10.3 release
Browse files Browse the repository at this point in the history
CSV import bugfixes
Preset marker improvements
  • Loading branch information
g4ixt committed Apr 26, 2024
1 parent f56aff0 commit 145af45
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 90 deletions.
1 change: 1 addition & 0 deletions QtTSApreferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Binary file modified QtTSAprefs.db
Binary file not shown.
181 changes: 99 additions & 82 deletions QtTinySA.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def restoreSettings(self):
self.freq_changed(False) # start/stop mode
pointsChanged()
ui.graphWidget.setXRange(ui.start_freq.value(), ui.stop_freq.value())
logging.info(f'restoreSettings(): band = {numbers.tm.record(0).value("band")}')
logging.debug(f'restoreSettings(): band = {numbers.tm.record(0).value("band")}')

# update trace and marker settings from the database. 1 = last saved (default) settings
S1.dLoad(1)
Expand Down Expand Up @@ -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()):
Expand Down Expand Up @@ -794,9 +794,11 @@ def createTableModel(self):
self.dwm.setModel(self.tm)
self.dwm.setSubmitPolicy(QDataWidgetMapper.AutoSubmit)

def addRow(self): # adds a blank row to the frequency bands table widget
self.tm.insertRow(self.currentRow + 1)
self.currentRow += 1
def addRow(self): # adds a blank row to the frequency bands table widget above current row
if self.currentRow == 0:
self.tm.insertRow(0)
else:
self.tm.insertRow(self.currentRow)
preferences.freqBands.selectRow(self.currentRow)

def saveChanges(self):
Expand All @@ -816,20 +818,11 @@ def tableClicked(self):
self.currentRow = preferences.freqBands.currentIndex().row() # the row index from the QModelIndexObject
logging.debug(f'row {self.currentRow} clicked')

def insertData(self, name, typeF, startF, stopF, visible, colour):
def insertData(self, **data):
record = self.tm.record()
record.setValue('value', int(eval(visible))) # converts string(visible) 'True' 'False' to 1 or 0
record.setValue('name', name)
record.setValue('startF', f'{startF:.6f}')
record.setValue('stopF', f'{stopF:.6f}')
bandstype.tm.setFilter('preset = "' + typeF + '"') # using relation directly doesn't seem to work
bandstype.tm.select()
record.setValue('preset', bandstype.tm.record(0).value('ID'))
colours.tm.setFilter('colour = "' + colour + '"') # using relation directly doesn't seem to work
colours.tm.select()
record.setValue('colour', colours.tm.record(0).value('ID'))
for key, value in data.items():
record.setValue(str(key), value)
self.tm.insertRecord(-1, record)
bandstype.tm.setFilter('')
self.tm.select()
self.tm.layoutChanged.emit()
self.dwm.submit()
Expand All @@ -849,19 +842,31 @@ def filterType(self, prefsDialog, boxText):

def readCSV(self, fileName):
with open(fileName, "r") as fileInput:
header = None
for row in csv.reader(fileInput):
if not header:
header = row
logging.info(f'header = {header}')
indx = self.findCols(header)
continue
if len(indx) == 6: # (name, preset(=type), startF, stopF, visible, colour)
logging.info(f'row = {row}')
bands.insertData(row[indx[0]], row[indx[1]], float(row[indx[2]]), float(row[indx[3]]), row[indx[4]], row[indx[5]])
elif len(indx) == 3:
bands.insertData(row[indx[0]], 'RF mic', float(row[indx[1]]) / 1e3, 0, row[indx[2]].lower())
logging.debug(f'colour = {row[indx[2]].lower()}')
reader = csv.DictReader(fileInput)
for row in reader:
record = self.tm.record()
for key, value in row.items():
# don't understand how to make relation work for these fields
if key == 'preset':
value = presetID(value)
if key.lower() == 'colour':
value = colourID(value)
if key == 'value':
value = int(eval(value))
# to match RF mic CSV files
if key == 'Frequency':
key = 'startF'
value = str(float(value) / 1e3)
if key != 'ID': # ID is the table primary key and is auto-populated
record.setValue(str(key), value)
if record.value('value') not in (0, 1): # because it's not present in RF mic CSV files
record.setValue('value', 1)
if record.value('preset') == '': # preset missing so use current preferences filterbox text
record.setValue('preset', presetID(preferences.filterBox.currentText()))
self.tm.insertRecord(-1, record)
self.tm.select()
self.tm.layoutChanged.emit()
self.dwm.submit()

def writeCSV(self, fileName):
header = []
Expand All @@ -875,23 +880,6 @@ def writeCSV(self, fileName):
for columnNumber in range(1, 8)]
output.writerow(fields)

def findCols(self, header):
indx = []
try:
for i in range(1, self.tm.columnCount()): # start at 1 - don't include ID column
indx.append(header.index(self.tm.record().fieldName(i))) # Match to QtTinySA CSV export format
logging.info(f'i = {i} indx = {indx}')
except ValueError:
indx = []
try:
indx.append(header.index('Name')) # Match to RF mic export format
indx.append(header.index('Frequency'))
indx.append(header.index('Colour'))
except ValueError:
popUp('CSV Import failed: Field headers were not identified', QMessageBox.Ok, QMessageBox.Critical)
return
return indx

def mapWidget(self, modelName): # maps the widget combo-box fields to the database tables, using the mapping table
maps.tm.setFilter('model = "' + modelName + '"')
for index in range(0, maps.tm.rowCount()):
Expand Down Expand Up @@ -925,8 +913,10 @@ def addBandPressed():
message = 'M1 frequency >= M2 frequency'
popUp(message, QMessageBox.Ok, QMessageBox.Information)
return
name = 'M' + str(round(S1.vline.value(), 6))
bands.insertData(name, ui.filterBox.currentText(), S1.vline.value(), S2.vline.value(), 'True', 'aliceblue')
bandName = 'M' + str(round(S1.vline.value(), 6))
ID = presetID(str(ui.filterBox.currentText()))
bands.insertData(name=bandName, preset=ID, startF=f'{S1.vline.value():.6f}',
stopF=f'{S2.vline.value():.6f}', value=1, colour="aliceblue")
else:
message = 'M1 and M2 must both be enabled to add a new Band'
popUp(message, QMessageBox.Ok, QMessageBox.Information)
Expand Down Expand Up @@ -1050,17 +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()):
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, '')
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():
Expand All @@ -1069,14 +1067,14 @@ def freqMarkerLabel():

def exportData():
filename = QFileDialog.getSaveFileName(caption="Save As", filter="Comma Separated Values (*.csv)")
logging.info(f'filename {filename}')
logging.info(f'export filename is {filename[0]}')
if filename[0] != '':
bands.writeCSV(filename[0])


def importData():
filename = QFileDialog.getOpenFileName(caption="Select File to Import", filter="Comma Separated Values (*.csv)")
logging.info(f'filename {filename}')
logging.info(f'import filename is {filename[0]}')
if filename[0] != '':
bands.readCSV(filename[0])

Expand All @@ -1099,15 +1097,33 @@ def isMixerMode():
ui.centre_freq.setMaximum(100000)
ui.stop_freq.setMaximum(100000)


def presetID(typeF): # using the QSQLRelation directly doesn't work for preset. Can't see why.
for i in range(0, bandstype.tm.rowCount()):
preset = bandstype.tm.record(i).value('preset')
if preset == typeF:
ID = bandstype.tm.record(i).value('ID')
return ID
return 1


def colourID(shade): # using the QSQLRelation directly doesn't work for colour. Can't see why.
for i in range(0, colours.tm.rowCount()):
colour = colours.tm.record(i).value('colour')
if colour == shade.lower():
ID = colours.tm.record(i).value('ID')
return ID
return 1


###############################################################################
# Instantiate classes


tinySA = analyser()

app = QtWidgets.QApplication([]) # create QApplication for the GUI
app.setApplicationName('QtTinySA')
app.setApplicationVersion(' v0.10.2')
app.setApplicationVersion(' v0.10.3')
window = QtWidgets.QMainWindow()
ui = QtTinySpectrum.Ui_MainWindow()
ui.setupUi(window)
Expand Down Expand Up @@ -1137,6 +1153,7 @@ def isMixerMode():
colours = modelView('SVGColour')
maps = modelView('mapping')

presetmarker = modelView(('frequencies'))

###############################################################################
# GUI settings
Expand Down Expand Up @@ -1169,7 +1186,6 @@ def isMixerMode():
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

Expand Down Expand Up @@ -1206,9 +1222,10 @@ def isMixerMode():
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)
Expand Down Expand Up @@ -1264,31 +1281,32 @@ def isMixerMode():
# 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
fType = QSqlRelationalDelegate(preferences.freqBands)
preferences.freqBands.setItemDelegate(fType)


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)
Expand All @@ -1299,7 +1317,6 @@ def isMixerMode():
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)
Expand Down
9 changes: 5 additions & 4 deletions QtTinySpectrum.py
Original file line number Diff line number Diff line change
@@ -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
#
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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", "<html><head/><body><p>Preset Frequency list</p></body></html>"))
self.m4_type.setToolTip(_translate("MainWindow", "Marker Type"))
Expand All @@ -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"))
Expand Down
9 changes: 6 additions & 3 deletions QtTinySpectrum.ui
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@
</font>
</property>
<property name="toolTip">
<string>Mark preset freqs</string>
<string>Show markers for preset freqs</string>
</property>
<property name="text">
<string>Presets</string>
Expand Down Expand Up @@ -1065,10 +1065,13 @@
</font>
</property>
<property name="toolTip">
<string>Label preset freqs</string>
<string>Show/hide/rotate preset marker labels</string>
</property>
<property name="text">
<string>Labels</string>
<string>Label</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
Expand Down
Loading

0 comments on commit 145af45

Please sign in to comment.