kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
138 wiersze
4.9 KiB
Python
138 wiersze
4.9 KiB
Python
# NanoVNASaver
|
|
#
|
|
# A python program to view and export Touchstone data from a NanoVNA
|
|
# Copyright (C) 2019, 2020 Rune B. Broberg
|
|
# Copyright (C) 2020ff 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 <https://www.gnu.org/licenses/>.
|
|
import os
|
|
import csv
|
|
import logging
|
|
from typing import List
|
|
|
|
from PyQt5 import QtWidgets
|
|
|
|
import NanoVNASaver.AnalyticTools as at
|
|
from NanoVNASaver.Analysis.Base import Analysis, QHLine
|
|
from NanoVNASaver.Formatting import (
|
|
format_frequency, format_complex_imp,
|
|
format_resistance)
|
|
from NanoVNASaver.RFTools import reflection_coefficient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def format_resistence_neg(x):
|
|
return format_resistance(x, allow_negative=True)
|
|
|
|
|
|
def vswr_transformed(z, ratio=49) -> float:
|
|
refl = reflection_coefficient(z / ratio)
|
|
mag = abs(refl)
|
|
return 1 if mag == 1 else (1 + mag) / (1 - mag)
|
|
|
|
|
|
class ResonanceAnalysis(Analysis):
|
|
|
|
def __init__(self, app):
|
|
super().__init__(app)
|
|
self.crossing: List[int] = []
|
|
self.filename = ""
|
|
self._widget = QtWidgets.QWidget()
|
|
self.layout = QtWidgets.QFormLayout()
|
|
self._widget.setLayout(self.layout)
|
|
self.input_description = QtWidgets.QLineEdit("")
|
|
self.checkbox_move_marker = QtWidgets.QCheckBox()
|
|
self.layout.addRow(QtWidgets.QLabel("<b>Settings</b>"))
|
|
self.layout.addRow("Description", self.input_description)
|
|
self.layout.addRow(QHLine())
|
|
|
|
self.layout.addRow(QHLine())
|
|
|
|
self.results_label = QtWidgets.QLabel("<b>Results</b>")
|
|
self.layout.addRow(self.results_label)
|
|
|
|
def _get_data(self, index):
|
|
s11 = self.app.data.s11
|
|
my_data = {
|
|
"freq": s11[index].freq,
|
|
"s11": s11[index].z,
|
|
"lambda": s11[index].wavelength,
|
|
"impedance": s11[index].impedance(),
|
|
"vswr": s11[index].vswr,
|
|
}
|
|
my_data["vswr_49"] = vswr_transformed(
|
|
my_data["impedance"], 49)
|
|
my_data["vswr_4"] = vswr_transformed(
|
|
my_data["impedance"], 4)
|
|
my_data["r"] = my_data["impedance"].real
|
|
my_data["x"] = my_data["impedance"].imag
|
|
|
|
return my_data
|
|
|
|
def runAnalysis(self):
|
|
self.reset()
|
|
self.filename = os.path.join(
|
|
"/tmp/", f"{self.input_description.text()}.csv"
|
|
) if self.input_description.text() else ""
|
|
|
|
results_header = self.layout.indexOf(self.results_label)
|
|
logger.debug("Results start at %d, out of %d",
|
|
results_header, self.layout.rowCount())
|
|
|
|
for _ in range(results_header, self.layout.rowCount()):
|
|
self.layout.removeRow(self.layout.rowCount() - 1)
|
|
|
|
self.crossing = at.zero_crossings([d.phase for d in self.app.data.s11])
|
|
logger.debug("Found %d sections ",
|
|
len(self.crossing))
|
|
if not self.crossing:
|
|
self.layout.addRow(QtWidgets.QLabel(
|
|
"No resonance found"))
|
|
return
|
|
|
|
self.do_resonance_analysis()
|
|
|
|
def do_resonance_analysis(self):
|
|
extended_data = []
|
|
for m in self.crossing:
|
|
start, lowest, end = m
|
|
my_data = self._get_data(lowest)
|
|
s11_low = self.app.data.s11[lowest]
|
|
extended_data.append(my_data)
|
|
if start != end:
|
|
logger.debug(
|
|
"Section from %d to %d, lowest at %d",
|
|
start, end, lowest)
|
|
self.layout.addRow(
|
|
"Resonance",
|
|
QtWidgets.QLabel(
|
|
f"{format_frequency(s11_low.freq)}"
|
|
f" ({format_complex_imp(s11_low.impedance())})"))
|
|
else:
|
|
self.layout.addRow("Resonance", QtWidgets.QLabel(
|
|
format_frequency(self.app.data.s11[lowest].freq)))
|
|
self.layout.addWidget(QHLine())
|
|
# Remove the final separator line
|
|
self.layout.removeRow(self.layout.rowCount() - 1)
|
|
if self.filename and extended_data:
|
|
with open(
|
|
self.filename, 'w', encoding='utf-8', newline=''
|
|
) as csvfile:
|
|
fieldnames = extended_data[0].keys()
|
|
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
|
writer.writeheader()
|
|
for row in extended_data:
|
|
writer.writerow(row)
|