Exemple #1
0
 def updateLabels(self, s11data: List[Datapoint], s21data: List[Datapoint]):
     from NanoVNASaver.Chart import PhaseChart
     from NanoVNASaver.NanoVNASaver import NanoVNASaver
     if self.location != -1:
         im50, re50, vswr = NanoVNASaver.vswr(s11data[self.location])
         if im50 < 0:
             im50str = " - j" + str(round(-1 * im50, 3))
         else:
             im50str = " + j" + str(round(im50, 3))
         self.frequency_label.setText(
             NanoVNASaver.formatFrequency(s11data[self.location].freq))
         self.impedance_label.setText(str(round(re50, 3)) + im50str)
         self.returnloss_label.setText(
             str(round(20 * math.log10((vswr - 1) / (vswr + 1)), 3)) +
             " dB")
         reactance = NanoVNASaver.reactanceEquivalent(
             im50, s11data[self.location].freq)
         self.reactance_label.setText(reactance)
         self.vswr_label.setText(str(round(vswr, 3)))
         if len(s21data) == len(s11data):
             _, _, vswr = NanoVNASaver.vswr(s21data[self.location])
             self.gain_label.setText(
                 str(round(20 * math.log10((vswr - 1) / (vswr + 1)), 3)) +
                 " dB")
             self.phase_label.setText(
                 str(round(PhaseChart.angle(s21data[self.location]), 2)) +
                 "\N{DEGREE SIGN}")
Exemple #2
0
 def calculateRolloff(self, location1, location2):
     from NanoVNASaver.NanoVNASaver import NanoVNASaver
     frequency1 = self.app.data21[location1].freq
     frequency2 = self.app.data21[location2].freq
     gain1 = NanoVNASaver.gain(self.app.data21[location1])
     gain2 = NanoVNASaver.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
Exemple #3
0
    def updateLabels(self, s11data: List[Datapoint], s21data: List[Datapoint]):
        from NanoVNASaver.Chart import PhaseChart
        from NanoVNASaver.NanoVNASaver import NanoVNASaver
        if self.location != -1:
            im50, re50, vswr = NanoVNASaver.vswr(s11data[self.location])
            rp = (re50**2 + im50**2) / re50
            xp = (re50**2 + im50**2) / im50
            re50 = round(re50, 4 - max(0, math.floor(math.log10(abs(re50)))))
            rp = round(rp, 4 - max(0, math.floor(math.log10(abs(rp)))))
            im50 = round(im50, 4 - max(0, math.floor(math.log10(abs(im50)))))
            xp = round(xp, 4 - max(0, math.floor(math.log10(abs(xp)))))
            if im50 < 0:
                im50str = " -j" + str(-1 * im50)
            else:
                im50str = " +j" + str(im50)
            im50str += "\N{OHM SIGN}"

            if xp < 0:
                xpstr = NanoVNASaver.capacitanceEquivalent(
                    xp, s11data[self.location].freq)
            else:
                xpstr = NanoVNASaver.inductanceEquivalent(
                    xp, s11data[self.location].freq)

            self.frequency_label.setText(
                NanoVNASaver.formatFrequency(s11data[self.location].freq))
            self.impedance_label.setText(str(re50) + im50str)
            self.parallel_r_label.setText(str(rp) + "\N{OHM SIGN}")
            self.parallel_x_label.setText(xpstr)
            self.returnloss_label.setText(
                str(round(20 * math.log10((vswr - 1) / (vswr + 1)), 3)) +
                " dB")
            capacitance = NanoVNASaver.capacitanceEquivalent(
                im50, s11data[self.location].freq)
            inductance = NanoVNASaver.inductanceEquivalent(
                im50, s11data[self.location].freq)
            self.inductance_label.setText(inductance)
            self.capacitance_label.setText(capacitance)
            vswr = round(vswr, 3)
            if vswr < 0:
                vswr = "-"
            self.vswr_label.setText(str(vswr))
            self.quality_factor_label.setText(
                str(
                    round(NanoVNASaver.qualifyFactor(s11data[self.location]),
                          1)))
            self.s11_phase_label.setText(
                str(round(-PhaseChart.angle(s11data[self.location]), 2)) +
                "\N{DEGREE SIGN}")
            if len(s21data) == len(s11data):
                _, _, vswr = NanoVNASaver.vswr(s21data[self.location])
                self.gain_label.setText(
                    str(round(20 * math.log10((vswr - 1) / (vswr + 1)), 3)) +
                    " dB")
                self.s21_phase_label.setText(
                    str(round(-PhaseChart.angle(s21data[self.location]), 2)) +
                    "\N{DEGREE SIGN}")
Exemple #4
0
def main():
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("-d", "--debug", action="store_true",
                        help="Set loglevel to debug")
    parser.add_argument("-D", "--debug-file",
                        help="File to write debug logging output to")
    parser.add_argument("--version", action="version",
                        version=f"NanoVNASaver {VERSION}")
    args = parser.parse_args()

    console_log_level = logging.WARNING
    file_log_level = logging.DEBUG

    print(INFO)

    if args.debug:
        console_log_level = logging.DEBUG

    logger = logging.getLogger("NanoVNASaver")
    logger.setLevel(logging.DEBUG)

    ch = logging.StreamHandler()
    ch.setLevel(console_log_level)
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    if args.debug_file:
        fh = logging.FileHandler(args.debug_file)
        fh.setLevel(file_log_level)
        fh.setFormatter(formatter)
        logger.addHandler(fh)

    logger.info("Startup...")

    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling,
                                        True)
    app = QtWidgets.QApplication(sys.argv)
    window = NanoVNASaver()
    window.show()
    try:
        app.exec_()
    except BaseException as exc:
        logger.exception("%s", exc)
Exemple #5
0
    def runAnalysis(self):
        from NanoVNASaver.NanoVNASaver import NanoVNASaver
        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 = NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.gain(self.app.data21[initial_cutoff_location])
        for i in range(0, initial_cutoff_location):
            db = NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.formatFrequency(six_db_cutoff_frequency))

        ten_db_location = -1
        for i in range(cutoff_location, len(self.app.data21)):
            db = NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency))
        else:
            # # We derive 60 dB instead
            # factor = 10 * (-54 / decade_attenuation)
            # sixty_db_cutoff_frequency = round(six_db_cutoff_frequency + six_db_cutoff_frequency * factor)
            # self.sixty_db_label.setText(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency) + " (derived)")
            self.sixty_db_label.setText("Not calculated")

        if ten_db_location > 0 and twenty_db_location > 0:
            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)")
Exemple #6
0
    def runAnalysis(self):
        from NanoVNASaver.NanoVNASaver import NanoVNASaver
        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 = NanoVNASaver.gain(self.app.data21[0])
        for i in range(len(self.app.data21)):
            db = NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.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(NanoVNASaver.formatFrequency(span))
        self.center_frequency_label.setText(NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.formatFrequency(lower_six_db_cutoff_frequency))

        ten_db_location = -1
        for i in range(lower_cutoff_location, len(self.app.data21)):
            db = NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency))
        else:
            # # We derive 60 dB instead
            # factor = 10 * (-54 / decade_attenuation)
            # sixty_db_cutoff_frequency = round(six_db_cutoff_frequency + six_db_cutoff_frequency * factor)
            # self.sixty_db_label.setText(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency) + " (derived)")
            self.lower_sixty_db_label.setText("Not calculated")

        if ten_db_location > 0 and twenty_db_location > 0:
            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 = NanoVNASaver.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(NanoVNASaver.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(NanoVNASaver.formatFrequency(six_db_span))

        ten_db_location = -1
        for i in range(upper_cutoff_location, -1, -1):
            db = NanoVNASaver.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 = NanoVNASaver.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 = NanoVNASaver.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(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency))
        else:
            # # We derive 60 dB instead
            # factor = 10 * (-54 / decade_attenuation)
            # sixty_db_cutoff_frequency = round(six_db_cutoff_frequency + six_db_cutoff_frequency * factor)
            # self.sixty_db_label.setText(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency) + " (derived)")
            self.upper_sixty_db_label.setText("Not calculated")

        if ten_db_location > 0 and twenty_db_location > 0:
            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)")
Exemple #7
0
    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
        # Find scaling
        minVSWR = 1
        maxVSWR = 3
        for d in self.data:
            _, _, vswr = NanoVNASaver.vswr(d)
            if vswr > maxVSWR:
                maxVSWR = vswr
        maxVSWR = min(25, math.ceil(maxVSWR))
        span = maxVSWR - minVSWR
        ticksize = 1
        if span > 10 and span % 5 == 0:
            ticksize = 5
        elif span > 12 and span % 4 == 0:
            ticksize = 4
        elif span > 8 and span % 3 == 0:
            ticksize = 3
        elif span > 7 and span % 2 == 0:
            ticksize = 2

        for i in range(minVSWR, maxVSWR, ticksize):
            y = 30 + round((maxVSWR - i) / span * (self.chartHeight - 10))
            if i != minVSWR and i != maxVSWR:
                qp.setPen(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(maxVSWR))
        qp.drawText(3, self.chartHeight + 20, str(minVSWR))
        # At least 100 px between ticks
        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)):
            _, _, vswr = NanoVNASaver.vswr(self.data[i])
            x = self.leftMargin + 1 + round(
                self.chartWidth / len(self.data) * i)
            y = 30 + round((maxVSWR - vswr) / span * (self.chartHeight - 10))
            if y < 30:
                continue
            qp.drawPoint(int(x), int(y))
            if self.drawLines and i > 0:
                _, _, vswr = NanoVNASaver.vswr(self.data[i - 1])
                prevx = self.leftMargin + 1 + round(
                    self.chartWidth / len(self.data) * (i - 1))
                prevy = 30 + round(
                    (maxVSWR - vswr) / span * (self.chartHeight - 10))
                if prevy < 30:
                    continue
                qp.setPen(line_pen)
                qp.drawLine(x, y, prevx, prevy)
                qp.setPen(pen)
        pen.setColor(self.referenceColor)
        line_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
            _, _, vswr = NanoVNASaver.vswr(self.reference[i])
            x = self.leftMargin + 1 + round(
                self.chartWidth * (self.reference[i].freq - fstart) / fspan)
            y = 30 + round((maxVSWR - vswr) / span * (self.chartHeight - 10))
            if y < 30:
                continue
            qp.drawPoint(int(x), int(y))
            if self.drawLines and i > 0:
                _, _, vswr = NanoVNASaver.vswr(self.reference[i - 1])
                prevx = self.leftMargin + 1 + round(
                    self.chartWidth *
                    (self.reference[i - 1].freq - fstart) / fspan)
                prevy = 30 + round(
                    (maxVSWR - vswr) / span * (self.chartHeight - 10))
                if prevy < 30:
                    continue
                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)
                _, _, vswr = NanoVNASaver.vswr(self.data[m.location])
                x = self.leftMargin + 1 + round(
                    self.chartWidth / len(self.data) * m.location)
                y = 30 + round(
                    (maxVSWR - vswr) / span * (self.chartHeight - 10))
                if y < 30:
                    continue
                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)
Exemple #8
0
    def runAnalysis(self):
        from NanoVNASaver.NanoVNASaver import NanoVNASaver
        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 = NanoVNASaver.gain(self.app.data21[pass_band_location])

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

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

        if initial_lower_cutoff_location < 0:
            self.result_label.setText("Lower cutoff location not found.")
            return

        initial_lower_cutoff_frequency = self.app.data21[
            initial_lower_cutoff_location].freq

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

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

        if initial_upper_cutoff_location < 0:
            self.result_label.setText("Upper cutoff location not found.")
            return

        initial_upper_cutoff_frequency = self.app.data21[
            initial_upper_cutoff_location].freq

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

        peak_location = -1
        peak_db = NanoVNASaver.gain(
            self.app.data21[initial_lower_cutoff_location])
        for i in range(initial_lower_cutoff_location,
                       initial_upper_cutoff_location, 1):
            db = NanoVNASaver.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(peak_location, -1, -1):
            db = NanoVNASaver.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 = NanoVNASaver.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(
            NanoVNASaver.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
        pass_band_db = peak_db
        for i in range(peak_location, len(self.app.data21), 1):
            db = NanoVNASaver.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 = NanoVNASaver.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(
            NanoVNASaver.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(NanoVNASaver.formatFrequency(span))
        self.center_frequency_label.setText(
            NanoVNASaver.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, -1, -1):
            db = NanoVNASaver.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(
            NanoVNASaver.formatFrequency(lower_six_db_cutoff_frequency))

        ten_db_location = -1
        for i in range(lower_cutoff_location, -1, -1):
            db = NanoVNASaver.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, -1, -1):
            db = NanoVNASaver.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, -1, -1):
            db = NanoVNASaver.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:
            if sixty_db_location > 0:
                sixty_db_cutoff_frequency = self.app.data21[
                    sixty_db_location].freq
                self.lower_sixty_db_label.setText(
                    NanoVNASaver.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(
                    NanoVNASaver.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, len(self.app.data21), 1):
            db = NanoVNASaver.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(
            NanoVNASaver.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(
            NanoVNASaver.formatFrequency(six_db_span))

        ten_db_location = -1
        for i in range(upper_cutoff_location, len(self.app.data21), 1):
            db = NanoVNASaver.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, len(self.app.data21), 1):
            db = NanoVNASaver.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, len(self.app.data21), 1):
            db = NanoVNASaver.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(
                NanoVNASaver.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(
                NanoVNASaver.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)")
Exemple #9
0
    def runAnalysis(self):
        from NanoVNASaver.NanoVNASaver import NanoVNASaver
        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 = NanoVNASaver.gain(self.app.data21[pass_band_location])

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

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

        if initial_lower_cutoff_location < 0:
            self.result_label.setText("Lower cutoff location not found.")
            return

        initial_lower_cutoff_frequency = self.app.data21[
            initial_lower_cutoff_location].freq

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

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

        if initial_upper_cutoff_location < 0:
            self.result_label.setText("Upper cutoff location not found.")
            return

        initial_upper_cutoff_frequency = self.app.data21[
            initial_upper_cutoff_location].freq

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

        peak_location = -1
        peak_db = NanoVNASaver.gain(
            self.app.data21[initial_lower_cutoff_location])
        for i in range(initial_lower_cutoff_location,
                       initial_upper_cutoff_location, 1):
            db = NanoVNASaver.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(peak_location, -1, -1):
            db = NanoVNASaver.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 = NanoVNASaver.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(
            NanoVNASaver.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
        pass_band_db = peak_db
        for i in range(peak_location, len(self.app.data21), 1):
            db = NanoVNASaver.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 = NanoVNASaver.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(
            NanoVNASaver.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(NanoVNASaver.formatFrequency(span))
        self.center_frequency_label.setText(
            NanoVNASaver.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, -1, -1):
            db = NanoVNASaver.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(
            NanoVNASaver.formatFrequency(lower_six_db_cutoff_frequency))

        lower_six_db_attenuation = NanoVNASaver.gain(
            self.app.data21[lower_six_db_location])
        lower_max_attenuation = NanoVNASaver.gain(self.app.data21[0])
        frequency_factor = self.app.data21[
            0].freq / lower_six_db_cutoff_frequency
        lower_attenuation = (lower_max_attenuation - lower_six_db_attenuation)
        logger.debug("Measured points: %d Hz and %d Hz",
                     lower_six_db_cutoff_frequency, self.app.data21[0].freq)
        logger.debug("%d dB over %f factor", lower_attenuation,
                     frequency_factor)
        octave_attenuation = lower_attenuation / (
            math.log10(frequency_factor) / math.log10(2))
        self.lower_db_per_octave_label.setText(
            str(round(octave_attenuation, 3)) + " dB / octave")
        decade_attenuation = lower_attenuation / math.log10(frequency_factor)
        self.lower_db_per_decade_label.setText(
            str(round(decade_attenuation, 3)) + " dB / decade")

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

        if lower_sixty_db_location < 0:
            # # We derive 60 dB instead
            # factor = 10 * (-54 / decade_attenuation)
            # sixty_db_cutoff_frequency = round(six_db_cutoff_frequency + six_db_cutoff_frequency * factor)
            # self.upper_sixty_db_label.setText(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency) + " (derived)")
            self.lower_sixty_db_label.setText("Not calculated")

        else:
            lower_sixty_db_cutoff_frequency = self.app.data21[
                lower_sixty_db_location].freq
            self.lower_sixty_db_label.setText(
                NanoVNASaver.formatFrequency(lower_sixty_db_cutoff_frequency))

        # Upper roll-off

        upper_six_db_location = -1
        for i in range(upper_cutoff_location, len(self.app.data21), 1):
            db = NanoVNASaver.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(
            NanoVNASaver.formatFrequency(upper_six_db_cutoff_frequency))

        upper_six_db_attenuation = NanoVNASaver.gain(
            self.app.data21[upper_six_db_location])
        upper_max_attenuation = NanoVNASaver.gain(self.app.data21[0])
        frequency_factor = self.app.data21[
            0].freq / upper_six_db_cutoff_frequency
        upper_attenuation = (upper_max_attenuation - upper_six_db_attenuation)
        logger.debug("Measured points: %d Hz and %d Hz",
                     upper_six_db_cutoff_frequency, self.app.data21[0].freq)
        logger.debug("%d dB over %f factor", upper_attenuation,
                     frequency_factor)
        octave_attenuation = upper_attenuation / (
            math.log10(frequency_factor) / math.log10(2))
        self.upper_db_per_octave_label.setText(
            str(round(octave_attenuation, 3)) + " dB / octave")
        decade_attenuation = upper_attenuation / math.log10(frequency_factor)
        self.upper_db_per_decade_label.setText(
            str(round(decade_attenuation, 3)) + " dB / decade")

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

        if upper_sixty_db_location < 0:
            # # We derive 60 dB instead
            # factor = 10 * (-54 / decade_attenuation)
            # sixty_db_cutoff_frequency = round(six_db_cutoff_frequency + six_db_cutoff_frequency * factor)
            # self.upper_sixty_db_label.setText(NanoVNASaver.formatFrequency(sixty_db_cutoff_frequency) + " (derived)")
            self.upper_sixty_db_label.setText("Not calculated")

        else:
            upper_sixty_db_cutoff_frequency = self.app.data21[
                upper_sixty_db_location].freq
            self.upper_sixty_db_label.setText(
                NanoVNASaver.formatFrequency(upper_sixty_db_cutoff_frequency))

        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)")