kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
First beta of a Quality Factor chart
rodzic
35823a6234
commit
9cf710992e
|
@ -898,3 +898,190 @@ class LogMagChart(Chart):
|
|||
# Calculate the reflection coefficient
|
||||
mag = math.sqrt((re50 - 50) * (re50 - 50) + im50 * im50) / math.sqrt((re50 + 50) * (re50 + 50) + im50 * im50)
|
||||
return -20 * math.log10(mag)
|
||||
|
||||
|
||||
class QualityFactorChart(Chart):
|
||||
def __init__(self, name=""):
|
||||
super().__init__()
|
||||
self.leftMargin = 35
|
||||
self.chartWidth = 360
|
||||
self.chartHeight = 360
|
||||
self.name = name
|
||||
self.fstart = 0
|
||||
self.fstop = 0
|
||||
self.mouselocation = 0
|
||||
|
||||
self.minQ = 0
|
||||
self.maxQ = 0
|
||||
self.span = 0
|
||||
|
||||
self.setMinimumSize(self.chartWidth + 20 + self.leftMargin, self.chartHeight + 40)
|
||||
self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding))
|
||||
pal = QtGui.QPalette()
|
||||
pal.setColor(QtGui.QPalette.Background, self.backgroundColor)
|
||||
self.setPalette(pal)
|
||||
self.setAutoFillBackground(True)
|
||||
|
||||
self.marker1Color = QtGui.QColor(255, 0, 20)
|
||||
self.marker2Color = QtGui.QColor(20, 0, 255)
|
||||
|
||||
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
|
||||
self.chartWidth = a0.size().width()-20-self.leftMargin
|
||||
self.chartHeight = a0.size().height()-40
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
|
||||
qp = QtGui.QPainter(self)
|
||||
#qp.begin(self) # Apparently not needed?
|
||||
self.drawChart(qp)
|
||||
self.drawValues(qp)
|
||||
qp.end()
|
||||
|
||||
def drawChart(self, qp: QtGui.QPainter):
|
||||
from NanoVNASaver.NanoVNASaver import NanoVNASaver
|
||||
qp.setPen(QtGui.QPen(self.textColor))
|
||||
qp.drawText(3, 15, self.name)
|
||||
qp.setPen(QtGui.QPen(QtGui.QColor("lightgray")))
|
||||
qp.drawLine(self.leftMargin, 20, self.leftMargin, 20+self.chartHeight+5)
|
||||
qp.drawLine(self.leftMargin-5, 20+self.chartHeight, self.leftMargin+self.chartWidth, 20 + self.chartHeight)
|
||||
minQ = 0 # We always want 0 to be included in the graph
|
||||
maxQ = 0
|
||||
|
||||
# Make up some sensible scaling here
|
||||
for d in self.data:
|
||||
Q = NanoVNASaver.qualifyFactor(d)
|
||||
if Q > maxQ:
|
||||
maxQ = Q
|
||||
if Q < minQ:
|
||||
minQ = Q
|
||||
if maxQ != 0:
|
||||
maxQ = min(1000, maxQ) # Don't show Q over 1000
|
||||
maxScale = math.floor(max(math.log10(maxQ), 1))
|
||||
else:
|
||||
maxScale = 1
|
||||
if minQ != 0:
|
||||
minQ = max(-1000, minQ) # Nor Q less than -1000
|
||||
minScale = math.floor(max(math.log10(abs(minQ)), 1))
|
||||
else:
|
||||
minScale = 1
|
||||
self.maxQ = math.ceil(round(maxQ / maxScale) * maxScale)
|
||||
self.minQ = math.floor(round(minQ / minScale) * minScale)
|
||||
self.span = maxQ - minQ
|
||||
step = math.floor(self.span / 8)
|
||||
if step == 0:
|
||||
return # No data to draw the graph from
|
||||
for i in range(self.minQ, self.maxQ, step):
|
||||
y = 30 + round((maxQ - i) / self.span * (self.chartHeight-10))
|
||||
if i != minQ:
|
||||
qp.setPen(QtGui.QPen(self.textColor))
|
||||
qp.drawText(3, y+3, str(i))
|
||||
qp.setPen(QtGui.QPen(QtGui.QColor("lightgray")))
|
||||
qp.drawLine(self.leftMargin-5, y, self.leftMargin+self.chartWidth, y)
|
||||
#qp.drawLine(self.leftMargin - 5, 30, self.leftMargin + self.chartWidth, 30)
|
||||
qp.setPen(self.textColor)
|
||||
#qp.drawText(3, 35, str(maxQ))
|
||||
#qp.drawText(3, self.chartHeight+20, str(minQ))
|
||||
|
||||
def drawValues(self, qp: QtGui.QPainter):
|
||||
from NanoVNASaver.NanoVNASaver import NanoVNASaver
|
||||
if len(self.data) == 0 and len(self.reference) == 0:
|
||||
return
|
||||
pen = QtGui.QPen(self.sweepColor)
|
||||
pen.setWidth(2)
|
||||
line_pen = QtGui.QPen(self.sweepColor)
|
||||
line_pen.setWidth(1)
|
||||
highlighter = QtGui.QPen(QtGui.QColor(20, 0, 255))
|
||||
highlighter.setWidth(1)
|
||||
if len(self.data) > 0:
|
||||
fstart = self.data[0].freq
|
||||
fstop = self.data[len(self.data)-1].freq
|
||||
else:
|
||||
fstart = self.reference[0].freq
|
||||
fstop = self.reference[len(self.reference) - 1].freq
|
||||
self.fstart = fstart
|
||||
self.fstop = fstop
|
||||
fspan = fstop-fstart
|
||||
qp.drawText(self.leftMargin-20, 20 + self.chartHeight + 15, Chart.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(self.textColor)
|
||||
qp.drawText(x-20, 20+self.chartHeight+15, Chart.shortenFrequency(round(fspan/ticks*(i+1) + fstart)))
|
||||
|
||||
if self.mouselocation != 0:
|
||||
qp.setPen(QtGui.QPen(QtGui.QColor(224,224,224)))
|
||||
x = self.leftMargin + 1 + round(self.chartWidth * (self.mouselocation - fstart) / fspan)
|
||||
qp.drawLine(x, 20, x, 20 + self.chartHeight +5)
|
||||
|
||||
qp.setPen(pen)
|
||||
for i in range(len(self.data)):
|
||||
Q = NanoVNASaver.qualifyFactor(self.data[i])
|
||||
|
||||
x = self.leftMargin + 1 + round(self.chartWidth/len(self.data) * i)
|
||||
y = 30 + round((self.maxQ - Q)/ self.span *(self.chartHeight-10))
|
||||
qp.drawPoint(int(x), int(y))
|
||||
if self.drawLines and i > 0:
|
||||
Q = NanoVNASaver.qualifyFactor(self.data[i-1])
|
||||
prevx = self.leftMargin + 1 + round(self.chartWidth / len(self.data) * (i-1))
|
||||
prevy = 30 + round((self.maxQ - Q) / self.span * (self.chartHeight - 10))
|
||||
qp.setPen(line_pen)
|
||||
qp.drawLine(x, y, prevx, prevy)
|
||||
qp.setPen(pen)
|
||||
pen.setColor(self.referenceColor)
|
||||
qp.setPen(pen)
|
||||
for i in range(len(self.reference)):
|
||||
if self.reference[i].freq < fstart or self.reference[i].freq > fstop:
|
||||
continue
|
||||
Q = NanoVNASaver.qualifyFactor(self.reference[i])
|
||||
x = self.leftMargin + 1 + round(self.chartWidth*(self.reference[i].freq - fstart)/fspan)
|
||||
y = 30 + round((self.maxQ - Q)/self.span*(self.chartHeight-10))
|
||||
qp.drawPoint(int(x), int(y))
|
||||
if self.drawLines and i > 0:
|
||||
Q = NanoVNASaver.qualifyFactor(self.reference[i-1])
|
||||
prevx = x = self.leftMargin + 1 + round(self.chartWidth*(self.reference[i-1].freq - fstart)/fspan)
|
||||
prevy = 30 + round((self.maxQ - Q) / self.span * (self.chartHeight - 10))
|
||||
qp.setPen(line_pen)
|
||||
qp.drawLine(x, y, prevx, prevy)
|
||||
qp.setPen(pen)
|
||||
# Now draw the markers
|
||||
for m in self.markers:
|
||||
if m.location != -1:
|
||||
highlighter.setColor(m.color)
|
||||
qp.setPen(highlighter)
|
||||
Q = NanoVNASaver.qualifyFactor(self.data[m.location])
|
||||
x = self.leftMargin + 1 + round(self.chartWidth/len(self.data) * m.location)
|
||||
y = 30 + round((self.maxQ - Q) / self.span * (self.chartHeight - 10))
|
||||
qp.drawLine(int(x), int(y) + 3, int(x) - 3, int(y) - 3)
|
||||
qp.drawLine(int(x), int(y) + 3, int(x) + 3, int(y) - 3)
|
||||
qp.drawLine(int(x) - 3, int(y) - 3, int(x) + 3, int(y) - 3)
|
||||
#qp.drawPoint(int(x), int(y))
|
||||
|
||||
def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
|
||||
self.mouseMoveEvent(a0)
|
||||
|
||||
def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
|
||||
x = a0.x()
|
||||
absx = x - self.leftMargin
|
||||
if absx < 0 or absx > self.chartWidth:
|
||||
self.mouselocation = 0
|
||||
a0.ignore()
|
||||
return
|
||||
a0.accept()
|
||||
if self.fstop - self.fstart > 0:
|
||||
span = self.fstop - self.fstart
|
||||
step = span/self.chartWidth
|
||||
f = self.fstart + absx * step
|
||||
# self.mouselocation = f
|
||||
self.markers[0].setFrequency(str(round(f)))
|
||||
self.markers[0].frequencyInput.setText(str(round(f)))
|
||||
else:
|
||||
self.mouselocation = 0
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def angle(d: Datapoint) -> float:
|
||||
re = d.re
|
||||
im = d.im
|
||||
return -math.degrees(math.atan2(im, re))
|
||||
|
|
|
@ -24,7 +24,7 @@ import serial
|
|||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
from serial.tools import list_ports
|
||||
|
||||
from .Chart import Chart, PhaseChart, VSWRChart, PolarChart, SmithChart, LogMagChart
|
||||
from .Chart import Chart, PhaseChart, VSWRChart, PolarChart, SmithChart, LogMagChart, QualityFactorChart
|
||||
from .Calibration import CalibrationWindow, Calibration
|
||||
from .Marker import Marker
|
||||
from .SweepWorker import SweepWorker
|
||||
|
@ -97,12 +97,14 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
self.s11Phase = PhaseChart("S11 Phase")
|
||||
self.s21Phase = PhaseChart("S21 Phase")
|
||||
self.s11VSWR = VSWRChart("S11 VSWR")
|
||||
self.s11QualityFactor = QualityFactorChart("S11 Quality Factor")
|
||||
|
||||
self.s11charts: List[Chart] = []
|
||||
self.s11charts.append(self.s11SmithChart)
|
||||
self.s11charts.append(self.s11LogMag)
|
||||
self.s11charts.append(self.s11Phase)
|
||||
self.s11charts.append(self.s11VSWR)
|
||||
self.s11charts.append(self.s11QualityFactor)
|
||||
|
||||
self.s21charts: List[Chart] = []
|
||||
self.s21charts.append(self.s21PolarChart)
|
||||
|
@ -757,6 +759,15 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
vswr = (1 + mag) / (1 - mag)
|
||||
return im50, re50, vswr
|
||||
|
||||
@staticmethod
|
||||
def qualifyFactor(data: Datapoint):
|
||||
im50, re50, _ = NanoVNASaver.vswr(data)
|
||||
if re50 != 0:
|
||||
Q = im50 / re50
|
||||
else:
|
||||
Q = 0
|
||||
return Q
|
||||
|
||||
@staticmethod
|
||||
def reactanceEquivalent(im50, freq) -> str:
|
||||
capacitance = 10**12/(freq * 2 * math.pi * im50)
|
||||
|
|
Ładowanie…
Reference in New Issue