def test_missingDigitsAfterPeriod(self): # some poorly formatted values that still work as expected self.assertEqual(parse_frequency('123.'), 123) self.assertEqual(parse_frequency('123.Hz'), 123) self.assertEqual(parse_frequency('123.kHz'), 123000) self.assertEqual(parse_frequency('123.MHz'), 123000000) self.assertEqual(parse_frequency('123.GHz'), 123000000000)
def test_partialHzText(self): ####################################################################### # The current behavior for accidentally missing the H in Hz, is a # detection of 'z' SI unit (zepto = 10^-21), which then rounded to 0. # After reduction of legal SI values in SITools, this would return # a -1 failure code instead. ####################################################################### self.assertEqual(parse_frequency('123z'), 0) self.assertEqual(parse_frequency('123.z'), 0) self.assertEqual(parse_frequency('1.23z'), 0) '''
def test_negativeExponentialNotation(self): # negative exponential values resulting in N < 0, return 0 self.assertEqual(parse_frequency('123e-3'), 0) self.assertEqual(parse_frequency('1234e-4'), 0) self.assertEqual(parse_frequency('12345e-5'), 0) self.assertEqual(parse_frequency('12345678e-8'), 0) # negative exponential values resulting in N > 0, return N self.assertEqual(parse_frequency('100000e-5'), 1) self.assertEqual(parse_frequency('100000e-4'), 10) self.assertEqual(parse_frequency('100000e-3'), 100) self.assertEqual(parse_frequency('100000e-2'), 1000) self.assertEqual(parse_frequency('100000e-1'), 10000)
def test_basicSIUnits(self): # simple well-formed integers with correct SI units self.assertEqual(parse_frequency('123Hz'), 123) self.assertEqual(parse_frequency('123kHz'), 123000) self.assertEqual(parse_frequency('123456kHz'), 123456000) self.assertEqual(parse_frequency('123456Hz'), 123456) self.assertEqual(parse_frequency('123MHz'), 123000000) self.assertEqual(parse_frequency('123456MHz'), 123456000000) self.assertEqual(parse_frequency('123GHz'), 123000000000) self.assertEqual(parse_frequency('123456GHz'), 123456000000000)
def test_basicExponentialNotation(self): # check basic exponential notation self.assertEqual(parse_frequency('123e3'), 123000) self.assertEqual(parse_frequency('123e6'), 123000000) self.assertEqual(parse_frequency('123e9'), 123000000000) self.assertEqual(parse_frequency('123e4'), 1230000) self.assertEqual(parse_frequency('123e12'), 123000000000000) self.assertEqual(parse_frequency('123e18'), 123000000000000000000)
def setMaximumFrequency(self): max_freq_str, selected = QtWidgets.QInputDialog.getText( self, "Stop frequency", "Set stop frequency", text=str(self.maxFrequency)) if not selected: return max_freq = parse_frequency(max_freq_str) if max_freq > 0 and not (self.fixedSpan and max_freq <= self.minFrequency): self.maxFrequency = max_freq if self.fixedSpan: self.update()
def setMinimumFrequency(self): min_freq_str, selected = QtWidgets.QInputDialog.getText( self, "Start frequency", "Set start frequency", text=str(self.minFrequency)) if not selected: return span = abs(self.maxFrequency - self.minFrequency) min_freq = parse_frequency(min_freq_str) if min_freq < 0: return self.minFrequency = min_freq if self.minFrequency >= self.maxFrequency: self.maxFrequency = self.minFrequency + span self.fixedSpan = True self.update()
def setMaximumFrequency(self): max_freq_str, selected = QtWidgets.QInputDialog.getText( self, "Stop frequency", "Set stop frequency", text=str(self.maxFrequency)) if not selected: return span = abs(self.maxFrequency - self.minFrequency) max_freq = parse_frequency(max_freq_str) if max_freq < 0: return self.maxFrequency = max_freq if self.maxFrequency <= self.minFrequency: self.minFrequency = max(self.maxFrequency - span, 0) self.fixedSpan = True self.update()
def get_end(self) -> int: return parse_frequency(self.input_end.text())
def get_start(self) -> int: return parse_frequency(self.input_start.text())
def test_unusualSIUnits(self): ####################################################################### # Current behavior: unusual SI values that are legal, but inappropriate # for this application provide unexpected outputs. This behavior is # based on the FULL set of SI prefixes defined in SITools (below). # PREFIXES = ("y", "z", "a", "f", "p", "n", "µ", "m", # "", "k", "M", "G", "T", "P", "E", "Z", "Y") ####################################################################### self.assertEqual(parse_frequency('123EHz'), 123000000000000000000) self.assertEqual(parse_frequency('123PHz'), 123000000000000000) self.assertEqual(parse_frequency('123THz'), 123000000000000) self.assertEqual(parse_frequency('123YHz'), 123000000000000000000000000) self.assertEqual(parse_frequency('123ZHz'), 123000000000000000000000) self.assertEqual(parse_frequency('123aHz'), 0) self.assertEqual(parse_frequency('123fHz'), 0) self.assertEqual(parse_frequency('123nHz'), 0) self.assertEqual(parse_frequency('123pHz'), 0) self.assertEqual(parse_frequency('123yHz'), 0) self.assertEqual(parse_frequency('123zHz'), 0) ####################################################################### # Recommend: Reducing the legal SI values defined in SITools (see # below). This makes it more likely that typos will result in a -1 # failure code instead of being interpreted as an SI unit. # PREFIXES = ("", "k", "M", "G") ####################################################################### '''
def test_illegalInputValues(self): # poorly formatted inputs that are identified as illegal self.assertEqual(parse_frequency('Junk'), -1) self.assertEqual(parse_frequency('Garbage'), -1) self.assertEqual(parse_frequency('123.Junk'), -1)
def test_commonMistakeKHz_vs_kHz(self): # some poorly formatted values that still work as expected self.assertEqual(parse_frequency('123kHz'), 123000) self.assertEqual(parse_frequency('123KHz'), 123000)
def setFrequency(self, frequency): self.freq = parse_frequency(frequency) self.updated.emit(self)
def test_multiplePeriods(self): # multiple periods are properly detected as bad self.assertEqual(parse_frequency('123..Hz'), -1) self.assertEqual(parse_frequency('123...Hz'), -1) self.assertEqual(parse_frequency('123....Hz'), -1) self.assertEqual(parse_frequency('1.23.Hz'), -1)
def __init__(self, name: str = "", qsettings: QtCore.QSettings = None): super().__init__() self.qsettings = qsettings self.name = name self.color = QtGui.QColor() self.index = 0 if self.qsettings: Marker._instances += 1 Marker.active_labels = self.qsettings.value( "MarkerFields", defaultValue=default_label_ids()) self.index = Marker._instances if not self.name: self.name = f"Marker {Marker._instances}" self.frequencyInput = FrequencyInput() self.frequencyInput.setMinimumHeight(20) self.frequencyInput.setAlignment(QtCore.Qt.AlignRight) self.frequencyInput.editingFinished.connect(lambda: self.setFrequency( parse_frequency(self.frequencyInput.text()))) ############################################################### # Data display labels ############################################################### self.label = {} for l in TYPES: self.label[l.label_id] = MarkerLabel(l.name) self.label['actualfreq'].setMinimumWidth(100) self.label['returnloss'].setMinimumWidth(80) ############################################################### # Marker control layout ############################################################### self.btnColorPicker = QtWidgets.QPushButton("█") self.btnColorPicker.setMinimumHeight(20) self.btnColorPicker.setFixedWidth(20) self.btnColorPicker.clicked.connect(lambda: self.setColor( QtWidgets.QColorDialog.getColor( self.color, options=QtWidgets.QColorDialog.ShowAlphaChannel))) self.isMouseControlledRadioButton = QtWidgets.QRadioButton() self.layout = QtWidgets.QHBoxLayout() self.layout.addWidget(self.frequencyInput) self.layout.addWidget(self.btnColorPicker) self.layout.addWidget(self.isMouseControlledRadioButton) ############################################################### # Data display layout ############################################################### self.group_box = QtWidgets.QGroupBox(self.name) self.group_box.setMaximumWidth(340) box_layout = QtWidgets.QHBoxLayout(self.group_box) try: self.setColor( self.qsettings.value(f"Marker{self.count()}Color", COLORS[self.count()])) except AttributeError: # happens when qsettings == None self.setColor(COLORS[1]) except IndexError: self.setColor(COLORS[0]) line = QtWidgets.QFrame() line.setFrameShape(QtWidgets.QFrame.VLine) # line only if more then 3 selected self.left_form = QtWidgets.QFormLayout() self.left_form.setVerticalSpacing(0) self.right_form = QtWidgets.QFormLayout() self.right_form.setVerticalSpacing(0) box_layout.addLayout(self.left_form) box_layout.addWidget(line) box_layout.addLayout(self.right_form) self.buildForm()
def get_center(self) -> int: return parse_frequency(self.input_center.text())
def get_span(self) -> int: return parse_frequency(self.input_span.text())
def run(self): logger.info("Initializing SweepWorker") self.running = True self.percentage = 0 if not self.app.serial.is_open: logger.debug( "Attempted to run without being connected to the NanoVNA") self.running = False return if int(self.app.sweepCountInput.text()) > 0: self.noSweeps = int(self.app.sweepCountInput.text()) logger.info("%d sweeps", self.noSweeps) if self.averaging: logger.info("%d averages", self.averages) if (self.app.sweepStartInput.text() == "" or self.app.sweepEndInput.text() == ""): logger.debug("First sweep - standard range") # We should handle the first startup by reading frequencies? sweep_from = 1000000 sweep_to = 800000000 else: sweep_from = parse_frequency(self.app.sweepStartInput.text()) sweep_to = parse_frequency(self.app.sweepEndInput.text()) logger.debug("Parsed sweep range as %d to %d", sweep_from, sweep_to) if sweep_from < 0 or sweep_to < 0 or sweep_from == sweep_to: logger.warning("Can't sweep from %s to %s", self.app.sweepStartInput.text(), self.app.sweepEndInput.text()) self.error_message = ("Unable to parse frequency inputs" " - check start and stop fields.") self.stopped = True self.running = False self.signals.sweepError.emit() return span = sweep_to - sweep_from stepsize = int(span / (self.noSweeps * self.vna.datapoints - 1)) # Setup complete values11 = [] values21 = [] frequencies = [] if self.averaging: for i in range(self.noSweeps): logger.debug("Sweep segment no %d averaged over %d readings", i, self.averages) if self.stopped: logger.debug("Stopping sweeping as signalled") break start = sweep_from + i * self.vna.datapoints * stepsize freq, val11, val21 = self.readAveragedSegment( start, start + (self.vna.datapoints - 1) * stepsize, self.averages) frequencies.extend(freq) values11.extend(val11) values21.extend(val21) self.percentage = (i + 1) * (self.vna.datapoints - 1) / \ self.noSweeps logger.debug("Saving acquired data") self.saveData(frequencies, values11, values21) else: for i in range(self.noSweeps): logger.debug("Sweep segment no %d", i) if self.stopped: logger.debug("Stopping sweeping as signalled") break start = sweep_from + i * self.vna.datapoints * stepsize try: freq, val11, val21 = self.readSegment( start, start + (self.vna.datapoints - 1) * stepsize) frequencies.extend(freq) values11.extend(val11) values21.extend(val21) self.percentage = (i + 1) * 100 / self.noSweeps logger.debug("Saving acquired data") self.saveData(frequencies, values11, values21) except NanoVNAValueException as e: self.error_message = str(e) self.stopped = True self.running = False self.signals.sweepError.emit() except NanoVNASerialException as e: self.error_message = str(e) self.stopped = True self.running = False self.signals.sweepFatalError.emit() while self.continuousSweep and not self.stopped: logger.debug("Continuous sweeping") for i in range(self.noSweeps): logger.debug("Sweep segment no %d", i) if self.stopped: logger.debug("Stopping sweeping as signalled") break start = sweep_from + i * self.vna.datapoints * stepsize try: _, values11, values21 = self.readSegment( start, start + (self.vna.datapoints - 1) * stepsize) logger.debug("Updating acquired data") self.updateData(values11, values21, i, self.vna.datapoints) except NanoVNAValueException as e: self.error_message = str(e) self.stopped = True self.running = False self.signals.sweepError.emit() except NanoVNASerialException as e: self.error_message = str(e) self.stopped = True self.running = False self.signals.sweepFatalError.emit() # Reset the device to show the full range if we were multisegment if self.noSweeps > 1: logger.debug("Resetting NanoVNA sweep to full range: %d to %d", parse_frequency(self.app.sweepStartInput.text()), parse_frequency(self.app.sweepEndInput.text())) self.vna.resetSweep( parse_frequency(self.app.sweepStartInput.text()), parse_frequency(self.app.sweepEndInput.text())) self.percentage = 100 logger.debug("Sending \"finished\" signal") self.signals.finished.emit() self.running = False return