# NanoVNASaver # # A python program to view and export Touchstone data from a NanoVNA # Copyright (C) 2019, 2020 Rune B. Broberg # Copyright (C) 2020 NanoVNA-Saver Authors # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # 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 . import logging from PyQt5 import QtWidgets import numpy as np from NanoVNASaver.Analysis import Analysis, PeakSearchAnalysis from NanoVNASaver.Formatting import format_frequency logger = logging.getLogger(__name__) class VSWRAnalysis(Analysis): max_dips_shown = 3 vswr_limit_value = 1.5 class QHLine(QtWidgets.QFrame): def __init__(self): super().__init__() self.setFrameShape(QtWidgets.QFrame.HLine) def __init__(self, app): super().__init__(app) self._widget = QtWidgets.QWidget() self.layout = QtWidgets.QFormLayout() self._widget.setLayout(self.layout) self.input_vswr_limit = QtWidgets.QDoubleSpinBox() self.input_vswr_limit.setValue(self.vswr_limit_value) self.input_vswr_limit.setSingleStep(0.1) self.input_vswr_limit.setMinimum(1) self.input_vswr_limit.setMaximum(25) self.input_vswr_limit.setDecimals(2) self.checkbox_move_marker = QtWidgets.QCheckBox() self.layout.addRow(QtWidgets.QLabel("Settings")) self.layout.addRow("VSWR limit", self.input_vswr_limit) self.layout.addRow(VSWRAnalysis.QHLine()) self.results_label = QtWidgets.QLabel("Results") self.layout.addRow(self.results_label) def runAnalysis(self): max_dips_shown = self.max_dips_shown data = [] for d in self.app.data11: 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.data11[min_idx].freq) # # if self.checkbox_move_marker.isChecked(): # self.app.markers[0].setFrequency(str(self.app.data11[min_idx].freq)) # self.app.markers[0].frequencyInput.setText(str(self.app.data11[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("More than " + str(max_dips_shown) + " dips found. Lowest shown.")) 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 self.minimums = minimums 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( format_frequency(self.app.data11[start].freq))) self.layout.addRow( "Minimum", QtWidgets.QLabel( f"{format_frequency(self.app.data11[lowest].freq)}" f" ({round(data[lowest], 2)})")) self.layout.addRow("End", QtWidgets.QLabel( format_frequency(self.app.data11[end].freq))) self.layout.addRow( "Span", QtWidgets.QLabel( format_frequency(self.app.data11[end].freq - self.app.data11[start].freq))) self.layout.addWidget(PeakSearchAnalysis.QHLine()) else: self.layout.addRow("Low spot", QtWidgets.QLabel( format_frequency(self.app.data11[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)) + "."))