kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Copyright notice on program startup.
LogMagChart now has frequency ticks and text. File picker button using system file save dialog. Reading data and frequencies is standardized, including basic error handling. Removed a number of debugging statements. Version 0.0.1pull/1/head
rodzic
1a662bfe77
commit
8f2b33e9aa
|
@ -108,6 +108,20 @@ class LogMagChart(QtWidgets.QWidget):
|
|||
qp.setPen(QtCore.Qt.black)
|
||||
qp.drawText(3, 35, str(-min))
|
||||
qp.drawText(3, self.chartHeight+20, str(-max))
|
||||
# Draw frequency markers
|
||||
fstart = self.data[0].freq
|
||||
fstop = self.data[len(self.data)-1].freq
|
||||
fspan = fstop-fstart
|
||||
# At least 100 px between ticks
|
||||
qp.drawText(self.leftMargin-20, 20 + self.chartHeight + 15, LogMagChart.shortenFrequency(fstart))
|
||||
ticks = math.floor(self.chartWidth/100) # Number of ticks does not include the origin
|
||||
for i in range(ticks):
|
||||
x = self.leftMargin + round((i+1)*self.chartWidth/ticks)
|
||||
qp.setPen(QtGui.QPen(QtGui.QColor("lightgray")))
|
||||
qp.drawLine(x, 20, x, 20+self.chartHeight+5)
|
||||
qp.setPen(QtCore.Qt.black)
|
||||
qp.drawText(x-20, 20+self.chartHeight+15, LogMagChart.shortenFrequency(round(fspan/ticks*(i+1) + fstart)))
|
||||
|
||||
qp.setPen(pen)
|
||||
for i in range(len(self.data)):
|
||||
re = self.data[i].re
|
||||
|
@ -138,15 +152,21 @@ class LogMagChart(QtWidgets.QWidget):
|
|||
qp.drawPoint(int(x), int(y))
|
||||
|
||||
def setValues(self, values, frequencies):
|
||||
print("### Updating values ###")
|
||||
self.values = values
|
||||
self.frequencies = frequencies
|
||||
self.update()
|
||||
|
||||
def setData(self, data):
|
||||
print("### Updating data ###")
|
||||
self.data = data
|
||||
self.update()
|
||||
|
||||
def setMarkers(self, markers):
|
||||
self.markers = markers
|
||||
self.markers = markers
|
||||
|
||||
@staticmethod
|
||||
def shortenFrequency(frequency):
|
||||
if frequency < 50000:
|
||||
return frequency
|
||||
if frequency < 5000000:
|
||||
return str(round(frequency / 1000)) + "k"
|
||||
return str(round(frequency / 1000000, 1)) + "M"
|
|
@ -168,11 +168,17 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
file_control_layout = QtWidgets.QFormLayout(file_control_box)
|
||||
self.fileNameInput = QtWidgets.QLineEdit("")
|
||||
self.fileNameInput.setAlignment(QtCore.Qt.AlignRight)
|
||||
btnFilePicker = QtWidgets.QPushButton("...")
|
||||
btnFilePicker.setMaximumWidth(25)
|
||||
btnFilePicker.clicked.connect(self.pickFile)
|
||||
fileNameLayout = QtWidgets.QHBoxLayout()
|
||||
fileNameLayout.addWidget(self.fileNameInput)
|
||||
fileNameLayout.addWidget(btnFilePicker)
|
||||
|
||||
file_control_layout.addRow(QtWidgets.QLabel("Filename"), self.fileNameInput)
|
||||
file_control_layout.addRow(QtWidgets.QLabel("Filename"), fileNameLayout)
|
||||
|
||||
self.btnExportFile = QtWidgets.QPushButton("Export data")
|
||||
self.btnExportFile.clicked.connect(self.exportFile)
|
||||
self.btnExportFile = QtWidgets.QPushButton("Export data S1P")
|
||||
self.btnExportFile.clicked.connect(self.exportFileS11)
|
||||
file_control_layout.addRow(self.btnExportFile)
|
||||
|
||||
left_column.addWidget(file_control_box)
|
||||
|
@ -200,19 +206,37 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
self.worker.signals.updated.connect(self.dataUpdated)
|
||||
self.worker.signals.finished.connect(self.sweepFinished)
|
||||
|
||||
def exportFile(self):
|
||||
def pickFile(self):
|
||||
filename, _ = QtWidgets.QFileDialog.getSaveFileName(directory=self.fileNameInput.text(), filter="Touchstone Files (*.s1p *.s2p);;All files (*.*)")
|
||||
self.fileNameInput.setText(filename)
|
||||
|
||||
|
||||
def exportFileS11(self):
|
||||
print("Save file to " + self.fileNameInput.text())
|
||||
if (len(self.data) == 0):
|
||||
self.lister.appendPlainText("No data stored, nothing written.")
|
||||
return
|
||||
filename = self.fileNameInput.text()
|
||||
# TODO: Make some proper file handling here?
|
||||
file = open(filename, "w+")
|
||||
self.lister.clear()
|
||||
self.lister.appendPlainText("# Hz S RI R 50")
|
||||
file.write("# Hz S RI R 50\n")
|
||||
for i in range(len(self.values)):
|
||||
if i > 0 and self.frequencies[i] != self.frequencies[i-1]:
|
||||
self.lister.appendPlainText(self.frequencies[i] + " " + self.values[i])
|
||||
file.write(self.frequencies[i] + " " + self.values[i] + "\n")
|
||||
file.close()
|
||||
if filename == "":
|
||||
self.lister.appendPlainText("No filename entered.")
|
||||
return
|
||||
try:
|
||||
file = open(filename, "w+")
|
||||
self.lister.clear()
|
||||
self.lister.appendPlainText("# Hz S RI R 50")
|
||||
file.write("# Hz S RI R 50\n")
|
||||
for i in range(len(self.values)):
|
||||
if i > 0 and self.frequencies[i] != self.frequencies[i-1]:
|
||||
self.lister.appendPlainText(self.frequencies[i] + " " + self.values[i])
|
||||
file.write(self.frequencies[i] + " " + self.values[i] + "\n")
|
||||
file.close()
|
||||
except Exception as e:
|
||||
print("Error during file export: " + str(e))
|
||||
self.lister.appendPlainText("Error during file export: " + str(e))
|
||||
return
|
||||
|
||||
self.lister.appendPlainText("")
|
||||
self.lister.appendPlainText("File " + filename + " written.")
|
||||
|
||||
def serialButtonClick(self):
|
||||
if self.serial.is_open:
|
||||
|
@ -266,7 +290,7 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
return
|
||||
|
||||
def setSweep(self, start, stop):
|
||||
print("Sending: " + "sweep " + str(start) + " " + str(stop) + " 101")
|
||||
# print("Sending: " + "sweep " + str(start) + " " + str(stop) + " 101")
|
||||
self.writeSerial("sweep " + str(start) + " " + str(stop) + " 101")
|
||||
|
||||
def sweep(self):
|
||||
|
@ -281,7 +305,6 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
|
||||
def readValues(self, value):
|
||||
if self.serialLock.acquire():
|
||||
print("### Reading " + str(value) + " ###")
|
||||
try:
|
||||
data = "a"
|
||||
while data != "":
|
||||
|
@ -290,16 +313,14 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
# Then send the command to read data
|
||||
self.serial.write(str(value + "\r").encode('ascii'))
|
||||
except serial.SerialException as exc:
|
||||
print("Exception received")
|
||||
print("Exception received: " + str(exc))
|
||||
result = ""
|
||||
data = ""
|
||||
sleep(0.01)
|
||||
while "ch>" not in data:
|
||||
data = self.serial.readline().decode('ascii')
|
||||
result += data
|
||||
print("### Done reading ###")
|
||||
values = result.split("\r\n")
|
||||
print("Total values: " + str(len(values) - 2))
|
||||
self.serialLock.release()
|
||||
return values[1:102]
|
||||
|
||||
|
@ -345,4 +366,5 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
|
||||
def sweepFinished(self):
|
||||
self.sweepProgressBar.setValue(100)
|
||||
self.btnSweep.setDisabled(False)
|
||||
self.btnSweep.setDisabled(False)
|
||||
|
||||
|
|
|
@ -108,13 +108,11 @@ class SmithChart(QtWidgets.QWidget):
|
|||
qp.drawPoint(int(x), int(y))
|
||||
|
||||
def setValues(self, values, frequencies):
|
||||
print("### Updating values ###")
|
||||
self.values = values
|
||||
self.frequencies = frequencies
|
||||
self.update()
|
||||
|
||||
def setData(self, data):
|
||||
print("### Updating data ###")
|
||||
self.data = data
|
||||
self.update()
|
||||
|
||||
|
@ -122,5 +120,4 @@ class SmithChart(QtWidgets.QWidget):
|
|||
self.markers = markers
|
||||
|
||||
def heightForWidth(self, a0: int) -> int:
|
||||
print("Asked about height")
|
||||
return a0
|
|
@ -40,7 +40,6 @@ class SweepWorker(QtCore.QRunnable):
|
|||
|
||||
@pyqtSlot()
|
||||
def run(self):
|
||||
print("I am thread")
|
||||
self.percentage = 0
|
||||
if not self.app.serial.is_open:
|
||||
return
|
||||
|
@ -48,7 +47,6 @@ class SweepWorker(QtCore.QRunnable):
|
|||
if int(self.app.sweepCountInput.text()) > 0:
|
||||
self.noSweeps = int(self.app.sweepCountInput.text())
|
||||
|
||||
print("### Updating... ### ")
|
||||
if not self.app.sweepStartInput.text().isnumeric() or not self.app.sweepEndInput.text().isnumeric():
|
||||
# We should handle the first startup by reading frequencies?
|
||||
sweepFrom = 1000000
|
||||
|
@ -70,69 +68,22 @@ class SweepWorker(QtCore.QRunnable):
|
|||
self.app.setSweep(sweepFrom + i*101*stepsize, sweepFrom+(100+i*101)*stepsize)
|
||||
sleep(0.8)
|
||||
# S11
|
||||
tmpdata = []
|
||||
done = False
|
||||
while not done:
|
||||
done = True
|
||||
tmpdata = self.app.readValues("data 0")
|
||||
for d in tmpdata:
|
||||
a, b = d.split(" ")
|
||||
try:
|
||||
if float(a) < -1.5 or float(a) > 1.5:
|
||||
print("Warning: Got a non-float data value: " + d + " (" + a + ")")
|
||||
done = False
|
||||
if float(b) < -1.5 or float(b) > 1.5:
|
||||
print("Warning: Got a non-float data value: " + d + " (" + b + ")")
|
||||
done = False
|
||||
except Exception:
|
||||
done = False
|
||||
|
||||
values += tmpdata
|
||||
|
||||
values += self.readData("data 0")
|
||||
# S12
|
||||
tmpdata = []
|
||||
done = False
|
||||
while not done:
|
||||
done = True
|
||||
tmpdata = self.app.readValues("data 1")
|
||||
for d in tmpdata:
|
||||
a, b = d.split(" ")
|
||||
try:
|
||||
if float(a) < -1.5 or float(a) > 1.5:
|
||||
print("Warning: Got a non-float data value: " + d + " (" + a + ")")
|
||||
done = False
|
||||
if float(b) < -1.5 or float(b) > 1.5:
|
||||
print("Warning: Got a non-float data value: " + d + " (" + b + ")")
|
||||
done = False
|
||||
except Exception:
|
||||
done = False
|
||||
values12 += self.readData("data 1")
|
||||
|
||||
values12 += tmpdata
|
||||
|
||||
# TODO: Figure out why frequencies sometimes arrive as non-numbers
|
||||
tmpfreq = []
|
||||
done = False
|
||||
while not done:
|
||||
done = True
|
||||
tmpfreq = self.app.readValues("frequencies")
|
||||
for f in tmpfreq:
|
||||
if not f.isdigit():
|
||||
print("Warning: Got a non-digit frequency: " + f)
|
||||
done = False
|
||||
|
||||
frequencies += tmpfreq
|
||||
frequencies += self.readFreq()
|
||||
self.percentage = (i+1)*100/self.noSweeps
|
||||
self.saveData(frequencies, values, values12)
|
||||
|
||||
# Reset the device to show the full range
|
||||
self.app.setSweep(self.app.sweepStartInput.text(), self.app.sweepEndInput.text())
|
||||
else:
|
||||
print("### Reading values ###")
|
||||
values = self.app.readValues("data 0")
|
||||
values12 = self.app.readValues("data 1")
|
||||
print("### Reading frequencies ###")
|
||||
frequencies = self.app.readValues("frequencies")
|
||||
print("Read data, saving")
|
||||
self.app.setSweep(sweepFrom, sweepTo)
|
||||
sleep(0.8)
|
||||
values = self.readData("data 0")
|
||||
values12 = self.readData("data 1")
|
||||
frequencies = self.readFreq()
|
||||
self.saveData(frequencies, values, values12)
|
||||
|
||||
self.percentage = 100
|
||||
|
@ -153,5 +104,35 @@ class SweepWorker(QtCore.QRunnable):
|
|||
data += [Datapoint(freq, re, im)]
|
||||
data12 += [Datapoint(freq, re12, im12)]
|
||||
self.app.saveData(data, data12)
|
||||
print("Saved data, emitting signal")
|
||||
self.signals.updated.emit()
|
||||
|
||||
def readData(self, data):
|
||||
done = False
|
||||
while not done:
|
||||
done = True
|
||||
tmpdata = self.app.readValues(data)
|
||||
for d in tmpdata:
|
||||
a, b = d.split(" ")
|
||||
try:
|
||||
if float(a) < -1.5 or float(a) > 1.5:
|
||||
print("Warning: Got a non-float data value: " + d + " (" + a + ")")
|
||||
done = False
|
||||
if float(b) < -1.5 or float(b) > 1.5:
|
||||
print("Warning: Got a non-float data value: " + d + " (" + b + ")")
|
||||
done = False
|
||||
except Exception:
|
||||
done = False
|
||||
return tmpdata
|
||||
|
||||
def readFreq(self):
|
||||
# TODO: Figure out why frequencies sometimes arrive as non-integers
|
||||
tmpfreq = []
|
||||
done = False
|
||||
while not done:
|
||||
done = True
|
||||
tmpfreq = self.app.readValues("frequencies")
|
||||
for f in tmpfreq:
|
||||
if not f.isdigit():
|
||||
print("Warning: Got a non-digit frequency: " + f)
|
||||
done = False
|
||||
return tmpfreq
|
|
@ -18,7 +18,15 @@ from PyQt5 import QtWidgets
|
|||
|
||||
from NanoVNASaver import NanoVNASaver
|
||||
|
||||
version = "0.0.1"
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("NanoVNASaver " + version)
|
||||
print("Copyright (C) 2019 Rune B. Broberg")
|
||||
print("This program comes with ABSOLUTELY NO WARRANTY")
|
||||
print("This program is licensed under the GNU General Public License version 3")
|
||||
print("")
|
||||
print("See https://github.com/mihtjel/nanovna-saver for further details")
|
||||
# Main code goes here
|
||||
app = QtWidgets.QApplication([])
|
||||
window = NanoVNASaver()
|
||||
|
|
Ładowanie…
Reference in New Issue