Beispiel #1
0
    def setBandSweep(self):
        index_start = self.band_list.model().index(
            self.band_list.currentIndex(), 1)
        index_stop = self.band_list.model().index(
            self.band_list.currentIndex(), 2)
        start = int(self.band_list.model().data(
            index_start, QtCore.Qt.ItemDataRole).value())
        stop = int(self.band_list.model().data(index_stop,
                                               QtCore.Qt.ItemDataRole).value())

        if self.band_pad_10.isChecked():
            padding = 10
        elif self.band_pad_25.isChecked():
            padding = 25
        elif self.band_pad_100.isChecked():
            padding = 100
        else:
            padding = 0

        if padding > 0:
            span = stop - start
            start -= round(span * padding / 100)
            start = max(1, start)
            stop += round(span * padding / 100)

        self.app.sweepStartInput.setText(RFTools.formatSweepFrequency(start))
        self.app.sweepEndInput.setText(RFTools.formatSweepFrequency(stop))
        self.app.sweepEndInput.textEdited.emit(self.app.sweepEndInput.text())
Beispiel #2
0
    def runAnalysis(self):
        if self.rbtn_data_vswr.isChecked():
            suffix = ""
            data = []
            for d in self.app.data:
                data.append(d.vswr)
        elif self.rbtn_data_resistance.isChecked():
            suffix = " \N{OHM SIGN}"
            data = []
            for d in self.app.data:
                data.append(d.impedance().real)
        elif self.rbtn_data_reactance.isChecked():
            suffix = " \N{OHM SIGN}"
            data = []
            for d in self.app.data:
                data.append(d.impedance().imag)
        elif self.rbtn_data_s21_gain.isChecked():
            suffix = " dB"
            data = []
            for d in self.app.data21:
                data.append(d.gain)
        else:
            logger.warning("Searching for peaks on unknown data")
            return

        if len(data) == 0:
            return

        if self.rbtn_peak_positive.isChecked():
            idx_peak = np.argmax(data)
        elif self.rbtn_peak_negative.isChecked():
            idx_peak = np.argmin(data)
        else:
            # Both is not yet in
            logger.warning(
                "Searching for peaks,"
                " but neither looking at positive nor negative?")
            return

        self.peak_frequency.setText(
            RFTools.formatFrequency(self.app.data[idx_peak].freq))
        self.peak_value.setText(str(round(data[idx_peak], 3)) + suffix)

        if self.checkbox_move_marker.isChecked() and len(self.app.markers) >= 1:
            self.app.markers[0].setFrequency(str(self.app.data[idx_peak].freq))
            self.app.markers[0].frequencyInput.setText(
                RFTools.formatFrequency(self.app.data[idx_peak].freq))
 def calculateRolloff(self, location1, location2):
     if location1 == location2:
         return 0, 0
     frequency1 = self.app.data21[location1].freq
     frequency2 = self.app.data21[location2].freq
     gain1 = RFTools.gain(self.app.data21[location1])
     gain2 = RFTools.gain(self.app.data21[location2])
     frequency_factor = frequency2 / frequency1
     if frequency_factor < 1:
         frequency_factor = 1 / frequency_factor
     attenuation = abs(gain1 - gain2)
     logger.debug("Measured points: %d Hz and %d Hz", frequency1,
                  frequency2)
     logger.debug("%f dB over %f factor", attenuation, frequency_factor)
     octave_attenuation = attenuation / (math.log10(frequency_factor) /
                                         math.log10(2))
     decade_attenuation = attenuation / math.log10(frequency_factor)
     return octave_attenuation, decade_attenuation
Beispiel #4
0
 def setFrequency(self, frequency):
     f = RFTools.parseFrequency(frequency)
     if f > 0:
         self.frequency = f
         self.updated.emit()
     else:
         self.frequency = 0
         self.updated.emit()
         return
Beispiel #5
0
 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 = RFTools.parseFrequency(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()
Beispiel #6
0
    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 = RFTools.parseFrequency(self.app.sweepStartInput.text())
            sweep_to = RFTools.parseFrequency(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

        values = []
        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 += freq
                values += val11
                values21 += val21

                self.percentage = (i + 1) * (self.vna.datapoints-1) / self.noSweeps
                logger.debug("Saving acquired data")
                self.saveData(frequencies, values, 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 += freq
                    values += val11
                    values21 += val21

                    self.percentage = (i+1)*100/self.noSweeps
                    logger.debug("Saving acquired data")
                    self.saveData(frequencies, values, 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:
                    _, values, values21 = self.readSegment(
                        start, start + (self.vna.datapoints-1) * stepsize)
                    logger.debug("Updating acquired data")
                    self.updateData(values, 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",
                         RFTools.parseFrequency(
                             self.app.sweepStartInput.text()),
                         RFTools.parseFrequency(self.app.sweepEndInput.text()))
            self.vna.resetSweep(RFTools.parseFrequency(self.app.sweepStartInput.text()),
                                RFTools.parseFrequency(self.app.sweepEndInput.text()))

        self.percentage = 100
        logger.debug("Sending \"finished\" signal")
        self.signals.finished.emit()
        self.running = False
        return
    def runAnalysis(self):
        self.reset()
        pass_band_location = self.app.markers[0].location
        logger.debug("Pass band location: %d", pass_band_location)

        if len(self.app.data21) == 0:
            logger.debug("No data to analyse")
            self.result_label.setText("No data to analyse.")
            return

        if pass_band_location < 0:
            logger.debug("No location for %s", self.app.markers[0].name)
            self.result_label.setText("Please place " +
                                      self.app.markers[0].name +
                                      " in the passband.")
            return

        pass_band_db = RFTools.gain(self.app.data21[pass_band_location])

        logger.debug("Initial passband gain: %d", pass_band_db)

        initial_cutoff_location = -1
        for i in range(pass_band_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 3:
                # We found a cutoff location
                initial_cutoff_location = i
                break

        if initial_cutoff_location < 0:
            self.result_label.setText("Cutoff location not found.")
            return

        initial_cutoff_frequency = self.app.data21[
            initial_cutoff_location].freq

        logger.debug("Found initial cutoff frequency at %d",
                     initial_cutoff_frequency)

        peak_location = -1
        peak_db = RFTools.gain(self.app.data21[initial_cutoff_location])
        for i in range(0, initial_cutoff_location):
            db = RFTools.gain(self.app.data21[i])
            if db > peak_db:
                peak_db = db
                peak_location = i

        logger.debug("Found peak of %f at %d", peak_db,
                     self.app.data[peak_location].freq)

        self.app.markers[0].setFrequency(
            str(self.app.data21[peak_location].freq))
        self.app.markers[0].frequencyInput.setText(
            str(self.app.data21[peak_location].freq))

        cutoff_location = -1
        pass_band_db = peak_db
        for i in range(peak_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 3:
                # We found the cutoff location
                cutoff_location = i
                break

        cutoff_frequency = self.app.data21[cutoff_location].freq
        cutoff_gain = RFTools.gain(
            self.app.data21[cutoff_location]) - pass_band_db
        if cutoff_gain < -4:
            logger.debug(
                "Cutoff frequency found at %f dB - insufficient data points for true -3 dB point.",
                cutoff_gain)
        logger.debug("Found true cutoff frequency at %d", cutoff_frequency)

        self.cutoff_label.setText(
            RFTools.formatFrequency(cutoff_frequency) + " (" +
            str(round(cutoff_gain, 1)) + " dB)")
        self.app.markers[1].setFrequency(str(cutoff_frequency))
        self.app.markers[1].frequencyInput.setText(str(cutoff_frequency))

        six_db_location = -1
        for i in range(cutoff_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 6:
                # We found 6dB location
                six_db_location = i
                break

        if six_db_location < 0:
            self.result_label.setText("6 dB location not found.")
            return
        six_db_cutoff_frequency = self.app.data21[six_db_location].freq
        self.six_db_label.setText(
            RFTools.formatFrequency(six_db_cutoff_frequency))

        ten_db_location = -1
        for i in range(cutoff_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 10:
                # We found 6dB location
                ten_db_location = i
                break

        twenty_db_location = -1
        for i in range(cutoff_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 20:
                # We found 6dB location
                twenty_db_location = i
                break

        sixty_db_location = -1
        for i in range(six_db_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 60:
                # We found 60dB location! Wow.
                sixty_db_location = i
                break

        if sixty_db_location > 0:
            sixty_db_cutoff_frequency = self.app.data21[sixty_db_location].freq
            self.sixty_db_label.setText(
                RFTools.formatFrequency(sixty_db_cutoff_frequency))
        elif ten_db_location != -1 and twenty_db_location != -1:
            ten = self.app.data21[ten_db_location].freq
            twenty = self.app.data21[twenty_db_location].freq
            sixty_db_frequency = ten * 10**(
                5 * (math.log10(twenty) - math.log10(ten)))
            self.sixty_db_label.setText(
                RFTools.formatFrequency(sixty_db_frequency) + " (derived)")
        else:
            self.sixty_db_label.setText("Not calculated")

        if ten_db_location > 0 and twenty_db_location > 0 and ten_db_location != twenty_db_location:
            octave_attenuation, decade_attenuation = self.calculateRolloff(
                ten_db_location, twenty_db_location)
            self.db_per_octave_label.setText(
                str(round(octave_attenuation, 3)) + " dB / octave")
            self.db_per_decade_label.setText(
                str(round(decade_attenuation, 3)) + " dB / decade")
        else:
            self.db_per_octave_label.setText("Not calculated")
            self.db_per_decade_label.setText("Not calculated")

        self.result_label.setText("Analysis complete (" +
                                  str(len(self.app.data)) + " points)")
    def runAnalysis(self):
        self.reset()

        if len(self.app.data21) == 0:
            logger.debug("No data to analyse")
            self.result_label.setText("No data to analyse.")
            return

        peak_location = -1
        peak_db = RFTools.gain(self.app.data21[0])
        for i in range(len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if db > peak_db:
                peak_db = db
                peak_location = i

        logger.debug("Found peak of %f at %d", peak_db,
                     self.app.data[peak_location].freq)

        lower_cutoff_location = -1
        pass_band_db = peak_db
        for i in range(len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 3:
                # We found the cutoff location
                lower_cutoff_location = i
                break

        lower_cutoff_frequency = self.app.data21[lower_cutoff_location].freq
        lower_cutoff_gain = RFTools.gain(
            self.app.data21[lower_cutoff_location]) - pass_band_db

        if lower_cutoff_gain < -4:
            logger.debug(
                "Lower cutoff frequency found at %f dB - insufficient data points for true -3 dB point.",
                lower_cutoff_gain)

        logger.debug("Found true lower cutoff frequency at %d",
                     lower_cutoff_frequency)

        self.lower_cutoff_label.setText(
            RFTools.formatFrequency(lower_cutoff_frequency) + " (" +
            str(round(lower_cutoff_gain, 1)) + " dB)")

        self.app.markers[1].setFrequency(str(lower_cutoff_frequency))
        self.app.markers[1].frequencyInput.setText(str(lower_cutoff_frequency))

        upper_cutoff_location = -1
        for i in range(len(self.app.data21) - 1, -1, -1):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 3:
                # We found the cutoff location
                upper_cutoff_location = i
                break

        upper_cutoff_frequency = self.app.data21[upper_cutoff_location].freq
        upper_cutoff_gain = RFTools.gain(
            self.app.data21[upper_cutoff_location]) - pass_band_db
        if upper_cutoff_gain < -4:
            logger.debug(
                "Upper cutoff frequency found at %f dB - insufficient data points for true -3 dB point.",
                upper_cutoff_gain)

        logger.debug("Found true upper cutoff frequency at %d",
                     upper_cutoff_frequency)

        self.upper_cutoff_label.setText(
            RFTools.formatFrequency(upper_cutoff_frequency) + " (" +
            str(round(upper_cutoff_gain, 1)) + " dB)")
        self.app.markers[2].setFrequency(str(upper_cutoff_frequency))
        self.app.markers[2].frequencyInput.setText(str(upper_cutoff_frequency))

        span = upper_cutoff_frequency - lower_cutoff_frequency
        center_frequency = math.sqrt(lower_cutoff_frequency *
                                     upper_cutoff_frequency)
        q = center_frequency / span

        self.span_label.setText(RFTools.formatFrequency(span))
        self.center_frequency_label.setText(
            RFTools.formatFrequency(center_frequency))
        self.quality_label.setText(str(round(q, 2)))

        self.app.markers[0].setFrequency(str(round(center_frequency)))
        self.app.markers[0].frequencyInput.setText(str(
            round(center_frequency)))

        # Lower roll-off

        lower_six_db_location = -1
        for i in range(lower_cutoff_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 6:
                # We found 6dB location
                lower_six_db_location = i
                break

        if lower_six_db_location < 0:
            self.result_label.setText("Lower 6 dB location not found.")
            return
        lower_six_db_cutoff_frequency = self.app.data21[
            lower_six_db_location].freq
        self.lower_six_db_label.setText(
            RFTools.formatFrequency(lower_six_db_cutoff_frequency))

        ten_db_location = -1
        for i in range(lower_cutoff_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 10:
                # We found 6dB location
                ten_db_location = i
                break

        twenty_db_location = -1
        for i in range(lower_cutoff_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 20:
                # We found 6dB location
                twenty_db_location = i
                break

        sixty_db_location = -1
        for i in range(lower_six_db_location, len(self.app.data21)):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 60:
                # We found 60dB location! Wow.
                sixty_db_location = i
                break

        if sixty_db_location > 0:
            sixty_db_cutoff_frequency = self.app.data21[sixty_db_location].freq
            self.lower_sixty_db_label.setText(
                RFTools.formatFrequency(sixty_db_cutoff_frequency))
        elif ten_db_location != -1 and twenty_db_location != -1:
            ten = self.app.data21[ten_db_location].freq
            twenty = self.app.data21[twenty_db_location].freq
            sixty_db_frequency = ten * 10**(
                5 * (math.log10(twenty) - math.log10(ten)))
            self.lower_sixty_db_label.setText(
                RFTools.formatFrequency(sixty_db_frequency) + " (derived)")
        else:
            self.lower_sixty_db_label.setText("Not calculated")

        if ten_db_location > 0 and twenty_db_location > 0 and ten_db_location != twenty_db_location:
            octave_attenuation, decade_attenuation = self.calculateRolloff(
                ten_db_location, twenty_db_location)
            self.lower_db_per_octave_label.setText(
                str(round(octave_attenuation, 3)) + " dB / octave")
            self.lower_db_per_decade_label.setText(
                str(round(decade_attenuation, 3)) + " dB / decade")
        else:
            self.lower_db_per_octave_label.setText("Not calculated")
            self.lower_db_per_decade_label.setText("Not calculated")

        # Upper roll-off

        upper_six_db_location = -1
        for i in range(upper_cutoff_location, -1, -1):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 6:
                # We found 6dB location
                upper_six_db_location = i
                break

        if upper_six_db_location < 0:
            self.result_label.setText("Upper 6 dB location not found.")
            return
        upper_six_db_cutoff_frequency = self.app.data21[
            upper_six_db_location].freq
        self.upper_six_db_label.setText(
            RFTools.formatFrequency(upper_six_db_cutoff_frequency))

        six_db_span = upper_six_db_cutoff_frequency - lower_six_db_cutoff_frequency

        self.six_db_span_label.setText(RFTools.formatFrequency(six_db_span))

        ten_db_location = -1
        for i in range(upper_cutoff_location, -1, -1):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 10:
                # We found 6dB location
                ten_db_location = i
                break

        twenty_db_location = -1
        for i in range(upper_cutoff_location, -1, -1):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 20:
                # We found 6dB location
                twenty_db_location = i
                break

        sixty_db_location = -1
        for i in range(upper_six_db_location, -1, -1):
            db = RFTools.gain(self.app.data21[i])
            if (pass_band_db - db) > 60:
                # We found 60dB location! Wow.
                sixty_db_location = i
                break

        if sixty_db_location > 0:
            sixty_db_cutoff_frequency = self.app.data21[sixty_db_location].freq
            self.upper_sixty_db_label.setText(
                RFTools.formatFrequency(sixty_db_cutoff_frequency))
        elif ten_db_location != -1 and twenty_db_location != -1:
            ten = self.app.data21[ten_db_location].freq
            twenty = self.app.data21[twenty_db_location].freq
            sixty_db_frequency = ten * 10**(
                5 * (math.log10(twenty) - math.log10(ten)))
            self.upper_sixty_db_label.setText(
                RFTools.formatFrequency(sixty_db_frequency) + " (derived)")
        else:
            self.upper_sixty_db_label.setText("Not calculated")

        if ten_db_location > 0 and twenty_db_location > 0 and ten_db_location != twenty_db_location:
            octave_attenuation, decade_attenuation = self.calculateRolloff(
                ten_db_location, twenty_db_location)
            self.upper_db_per_octave_label.setText(
                str(round(octave_attenuation, 3)) + " dB / octave")
            self.upper_db_per_decade_label.setText(
                str(round(decade_attenuation, 3)) + " dB / decade")
        else:
            self.upper_db_per_octave_label.setText("Not calculated")
            self.upper_db_per_decade_label.setText("Not calculated")

        if upper_cutoff_gain < -4 or lower_cutoff_gain < -4:
            self.result_label.setText(
                "Analysis complete (" + str(len(self.app.data)) +
                " points)\n" +
                "Insufficient data for analysis. Increase segment count.")
        else:
            self.result_label.setText("Analysis complete (" +
                                      str(len(self.app.data)) + " points)")
Beispiel #9
0
    def updateLabels(self, s11data: List[Datapoint], s21data: List[Datapoint]):
        if self.location == -1:
            return
        s11 = s11data[self.location]
        if s21data:
            s21 = s21data[self.location]
        imp = s11.impedance()
        re50, im50 = imp.real, imp.imag
        vswr = s11.vswr
        if re50 > 0:
            rp = (re50 ** 2 + im50 ** 2) / re50
            rp = round(rp, 3 - max(0, math.floor(math.log10(abs(rp)))))
            if rp > 10000:
                rpstr = str(round(rp/1000, 2)) + "k"
            elif rp > 1000:
                rpstr = str(round(rp))
            else:
                rpstr = str(rp)

            re50 = round(re50, 3 - max(0, math.floor(math.log10(abs(re50)))))
            if re50 > 10000:
                re50str = str(round(re50/1000, 2)) + "k"
            elif re50 > 1000:
                re50str = str(round(re50))  # Remove the ".0"
            else:
                re50str = str(re50)
        else:
            rpstr = "-"
            re50 = 0
            re50str = "-"

        if im50 != 0:
            xp = (re50 ** 2 + im50 ** 2) / im50
            xp = round(xp, 3 - max(0, math.floor(math.log10(abs(xp)))))
            xpcstr = RFTools.capacitanceEquivalent(xp, s11data[self.location].freq)
            xplstr = RFTools.inductanceEquivalent(xp, s11data[self.location].freq)
            if xp < 0:
                xpstr = xpcstr
                xp50str = " -j" + str(-1 * xp)
            else:
                xpstr = xplstr
                xp50str = " +j" + str(xp)
            xp50str += " \N{OHM SIGN}"
        else:
            xp50str = " +j ? \N{OHM SIGN}"
            xpstr = xpcstr = xplstr = "-"

        if im50 != 0:
            im50 = round(im50, 3 - max(0, math.floor(math.log10(abs(im50)))))

        if im50 < 0:
            im50str = " -j" + str(-1 * im50)
        else:
            im50str = " +j" + str(im50)
        im50str += " \N{OHM SIGN}"

        self.frequency_label.setText(RFTools.formatFrequency(s11data[self.location].freq))
        self.impedance_label.setText(re50str + im50str)
        self.admittance_label.setText(rpstr + xp50str)
        self.series_r_label.setText(re50str + " \N{OHM SIGN}")
        self.parallel_r_label.setText(rpstr + " \N{OHM SIGN}")
        self.parallel_x_label.setText(xpstr)
        if self.returnloss_is_positive:
            returnloss = -round(s11data[self.location].gain, 3)
        else:
            returnloss = round(s11data[self.location].gain, 3)
        self.returnloss_label.setText(str(returnloss) + " dB")
        capacitance = RFTools.capacitanceEquivalent(im50, s11data[self.location].freq)
        inductance = RFTools.inductanceEquivalent(im50, s11data[self.location].freq)
        self.inductance_label.setText(inductance)
        self.capacitance_label.setText(capacitance)
        self.parallel_c_label.setText(xpcstr)
        self.parallel_l_label.setText(xplstr)
        if im50 > 0:
            self.series_lc_label.setText(inductance)
        else:
            self.series_lc_label.setText(capacitance)
        vswr = round(vswr, 3)
        if vswr < 0:
            vswr = "-"
        self.vswr_label.setText(str(vswr))
        q = s11data[self.location].qFactor()
        self.quality_factor_label.setText(format_q_factor(q))
        self.s11_phase_label.setText(
            str(round(math.degrees(s11data[self.location].phase), 2)) + "\N{DEGREE SIGN}")
        fmt = SITools.Format(max_nr_digits=5, space_str=" ")
        self.s11_group_delay_label.setText(str(SITools.Value(groupDelay(s11data, self.location), "s", fmt)))

        if len(s21data) == len(s11data):
            self.gain_label.setText(str(round(s21data[self.location].gain, 3)) + " dB")
            self.s21_phase_label.setText(
                str(round(math.degrees(s21data[self.location].phase), 2)) + "\N{DEGREE SIGN}")
            self.s21_group_delay_label.setText(str(SITools.Value(groupDelay(s21data, self.location) / 2,
                                                                    "s", fmt)))
Beispiel #10
0
 def setFrequency(self, frequency):
     f = RFTools.parseFrequency(frequency)
     self.frequency = max(f, 0)
     self.updated.emit(self)
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

import unittest

# Import targets to be tested
from NanoVNASaver.RFTools import RFTools
rft = RFTools()


# TODO: should be tested against SITools.Value
# RFTools.parseFrequency will hopefully go away in future
# and be specialised by input field and device, like
# parse_clamp_min=50000 for sweep input with
# a nanovna version 1 attached ...
# the hardware developer already announced a successor
# which will have different limits
class TestCases(unittest.TestCase):
    def test_basicSIUnits(self):
        # simple well-formed integers with correct SI units
        self.assertEqual(rft.parseFrequency('123Hz'), 123)
        self.assertEqual(rft.parseFrequency('123456Hz'), 123456)
        self.assertEqual(rft.parseFrequency('123kHz'), 123000)
Beispiel #12
0
    def updateLabels(self, s11data: List[Datapoint], s21data: List[Datapoint]):
        if self.location != -1:
            re50, im50 = RFTools.normalize50(s11data[self.location])
            vswr = RFTools.calculateVSWR(s11data[self.location])
            if re50 > 0:
                rp = (re50**2 + im50**2) / re50
                rp = round(rp, 3 - max(0, math.floor(math.log10(abs(rp)))))
                if rp > 10000:
                    rpstr = str(round(rp / 1000, 2)) + "k"
                elif rp > 1000:
                    rpstr = str(round(rp))
                else:
                    rpstr = str(rp)

                re50 = round(re50,
                             3 - max(0, math.floor(math.log10(abs(re50)))))
                if re50 > 10000:
                    re50str = str(round(re50 / 1000, 2)) + "k"
                elif re50 > 1000:
                    re50str = str(round(re50))  # Remove the ".0"
                else:
                    re50str = str(re50)
            else:
                rpstr = "-"
                re50 = 0
                re50str = "-"

            if im50 != 0:
                xp = (re50**2 + im50**2) / im50
                xp = round(xp, 3 - max(0, math.floor(math.log10(abs(xp)))))
                xpcstr = RFTools.capacitanceEquivalent(
                    xp, s11data[self.location].freq)
                xplstr = RFTools.inductanceEquivalent(
                    xp, s11data[self.location].freq)
                if xp < 0:
                    xpstr = xpcstr
                    xp50str = " -j" + str(-1 * xp)
                else:
                    xpstr = xplstr
                    xp50str = " +j" + str(xp)
                xp50str += " \N{OHM SIGN}"
            else:
                xp50str = " +j ? \N{OHM SIGN}"
                xpstr = xpcstr = xplstr = "-"

            if im50 != 0:
                im50 = round(im50,
                             3 - max(0, math.floor(math.log10(abs(im50)))))

            if im50 < 0:
                im50str = " -j" + str(-1 * im50)
            else:
                im50str = " +j" + str(im50)
            im50str += " \N{OHM SIGN}"

            self.frequency_label.setText(
                RFTools.formatFrequency(s11data[self.location].freq))
            self.impedance_label.setText(re50str + im50str)
            self.admittance_label.setText(rpstr + xp50str)
            self.series_r_label.setText(re50str + " \N{OHM SIGN}")
            self.parallel_r_label.setText(rpstr + " \N{OHM SIGN}")
            self.parallel_x_label.setText(xpstr)
            if self.returnloss_is_positive:
                returnloss = -round(RFTools.gain(s11data[self.location]), 3)
            else:
                returnloss = round(RFTools.gain(s11data[self.location]), 3)
            self.returnloss_label.setText(str(returnloss) + " dB")
            capacitance = RFTools.capacitanceEquivalent(
                im50, s11data[self.location].freq)
            inductance = RFTools.inductanceEquivalent(
                im50, s11data[self.location].freq)
            self.inductance_label.setText(inductance)
            self.capacitance_label.setText(capacitance)
            self.parallel_c_label.setText(xpcstr)
            self.parallel_l_label.setText(xplstr)
            if im50 > 0:
                self.series_lc_label.setText(inductance)
            else:
                self.series_lc_label.setText(capacitance)
            vswr = round(vswr, 3)
            if vswr < 0:
                vswr = "-"
            self.vswr_label.setText(str(vswr))
            q = RFTools.qualityFactor(s11data[self.location])
            if q > 10000 or q < 0:
                q_str = "\N{INFINITY}"
            elif q > 1000:
                q_str = str(round(q, 0))
            elif q > 100:
                q_str = str(round(q, 1))
            elif q > 10:
                q_str = str(round(q, 2))
            else:
                q_str = str(round(q, 3))
            self.quality_factor_label.setText(q_str)
            self.s11_phase_label.setText(
                str(round(RFTools.phaseAngle(s11data[self.location]), 2)) +
                "\N{DEGREE SIGN}")
            if len(s21data) == len(s11data):
                self.gain_label.setText(
                    str(round(RFTools.gain(s21data[self.location]), 3)) +
                    " dB")
                self.s21_phase_label.setText(
                    str(round(RFTools.phaseAngle(s21data[self.location]), 2)) +
                    "\N{DEGREE SIGN}")
Beispiel #13
0
    def runAnalysis(self):
        max_dips_shown = 3
        data = []
        for d in self.app.data:
            data.append(d.vswr)
        # min_idx = np.argmin(data)
        #
        # logger.debug("Minimum at %d", min_idx)
        # logger.debug("Value at minimum: %f", data[min_idx])
        # logger.debug("Frequency: %d", self.app.data[min_idx].freq)
        #
        # if self.checkbox_move_marker.isChecked():
        #     self.app.markers[0].setFrequency(str(self.app.data[min_idx].freq))
        #     self.app.markers[0].frequencyInput.setText(str(self.app.data[min_idx].freq))

        minimums = []
        min_start = -1
        min_idx = -1
        threshold = self.input_vswr_limit.value()
        min_val = threshold
        for i, d in enumerate(data):
            if d < threshold and i < len(data) - 1:
                if d < min_val:
                    min_val = d
                    min_idx = i
                if min_start == -1:
                    min_start = i
            elif min_start != -1:
                # We are above the threshold, and were in a section that was below
                minimums.append((min_start, min_idx, i - 1))
                min_start = -1
                min_idx = -1
                min_val = threshold

        logger.debug("Found %d sections under %f threshold", len(minimums),
                     threshold)

        results_header = self.layout.indexOf(self.results_label)
        logger.debug("Results start at %d, out of %d", results_header,
                     self.layout.rowCount())
        for i in range(results_header, self.layout.rowCount()):
            self.layout.removeRow(self.layout.rowCount() - 1)

        if len(minimums) > max_dips_shown:
            self.layout.addRow(
                QtWidgets.QLabel("<b>More than " + str(max_dips_shown) +
                                 " dips found. Lowest shown.</b>"))
            dips = []
            for m in minimums:
                start, lowest, end = m
                dips.append(data[lowest])

            best_dips = []
            for i in range(max_dips_shown):
                min_idx = np.argmin(dips)
                best_dips.append(minimums[min_idx])
                dips.remove(dips[min_idx])
                minimums.remove(minimums[min_idx])
            minimums = best_dips

        if len(minimums) > 0:
            for m in minimums:
                start, lowest, end = m
                if start != end:
                    logger.debug("Section from %d to %d, lowest at %d", start,
                                 end, lowest)
                    self.layout.addRow(
                        "Start",
                        QtWidgets.QLabel(
                            RFTools.formatFrequency(
                                self.app.data[start].freq)))
                    self.layout.addRow(
                        "Minimum",
                        QtWidgets.QLabel(
                            RFTools.formatFrequency(self.app.data[lowest].freq)
                            + " (" + str(round(data[lowest], 2)) + ")"))
                    self.layout.addRow(
                        "End",
                        QtWidgets.QLabel(
                            RFTools.formatFrequency(self.app.data[end].freq)))
                    self.layout.addRow(
                        "Span",
                        QtWidgets.QLabel(
                            RFTools.formatFrequency(
                                self.app.data[end].freq -
                                self.app.data[start].freq)))
                    self.layout.addWidget(PeakSearchAnalysis.QHLine())
                else:
                    self.layout.addRow(
                        "Low spot",
                        QtWidgets.QLabel(
                            RFTools.formatFrequency(
                                self.app.data[lowest].freq)))
                    self.layout.addWidget(PeakSearchAnalysis.QHLine())
            # Remove the final separator line
            self.layout.removeRow(self.layout.rowCount() - 1)
        else:
            self.layout.addRow(
                QtWidgets.QLabel("No areas found with VSWR below " +
                                 str(round(threshold, 2)) + "."))