-
Notifications
You must be signed in to change notification settings - Fork 276
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #261 from NanoVNA-Saver/Development
v0.3.6
- Loading branch information
Showing
40 changed files
with
1,233 additions
and
1,450 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
/venv/ | ||
/env/ | ||
.idea | ||
.vscode | ||
/build/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,271 +1,64 @@ | ||
# NanoVNASaver | ||
# | ||
# A python program to view and export Touchstone data from a NanoVNA | ||
# 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 <https://www.gnu.org/licenses/>. | ||
''' | ||
Created on 30 giu 2020 | ||
Created on May 30th 2020 | ||
@author: mauro | ||
''' | ||
|
||
from PyQt5 import QtWidgets, QtTest | ||
import logging | ||
import math | ||
|
||
from NanoVNASaver.Analysis import Analysis | ||
|
||
from NanoVNASaver.Hardware import VNA | ||
from PyQt5 import QtWidgets | ||
|
||
import numpy as np | ||
from NanoVNASaver.Marker import Marker | ||
from NanoVNASaver import RFTools | ||
from NanoVNASaver.Analysis.VSWRAnalysis import VSWRAnalysis | ||
from NanoVNASaver.Formatting import format_frequency_sweep | ||
|
||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class Antenna(object): | ||
|
||
@staticmethod | ||
def group_consecutives(vals, step=1): | ||
""" | ||
https://stackoverflow.com/questions/7352684/how-to-find-the-groups-of-consecutive-elements-from-an-array-in-numpy | ||
Return list of consecutive lists of numbers from vals (number list). | ||
:param vals: | ||
:param step: | ||
""" | ||
run = [] | ||
result = [run] | ||
expect = None | ||
for v in vals: | ||
if (v == expect) or (expect is None): | ||
run.append(v) | ||
else: | ||
run = [v] | ||
result.append(run) | ||
expect = v + step | ||
return result | ||
|
||
@classmethod | ||
def analyze(cls, frequencies, values, FIELD_NAME, step=5000, vuoto=False): | ||
''' | ||
dati dati, prova a trovare minimi e bands passanti | ||
:param cls: | ||
''' | ||
|
||
if FIELD_NAME == "rl": | ||
BAND_THRESHOLD = -7.0 | ||
MIN_CALCOLO_Q = -27 | ||
|
||
elif FIELD_NAME == "vswr": | ||
BAND_THRESHOLD = 2.62 | ||
MIN_CALCOLO_Q = 1.1 | ||
else: | ||
raise ValueError("unknown threshold for {}".format(FIELD_NAME)) | ||
|
||
bands_raw = np.where(values < BAND_THRESHOLD)[0] | ||
|
||
# raggruppo posizioni in cui il valore è sotto la soglia | ||
bands = cls.group_consecutives(bands_raw) | ||
# print("raggruppate in ", bands) | ||
out = [] | ||
# print "bands", bands | ||
banda_dict = None | ||
for band in bands: | ||
if band: | ||
|
||
print("band ", band) | ||
fmin = frequencies[band[0]] | ||
|
||
fmax = frequencies[band[-1]] | ||
estensione = fmax - fmin | ||
x = np.argmin(values[band[0]:band[-1] + 1]) | ||
prog = x + band[0] | ||
min_val = values[prog] | ||
|
||
if banda_dict: | ||
salto = fmin - banda_dict["fmax"] | ||
if salto < (10 * step): | ||
logger.warning("unisco band e proseguo") | ||
if min_val < banda_dict["min"]: | ||
logger.debug("aggiusto nuovo minimo, da %s a %s", | ||
banda_dict["min"], min_val) | ||
banda_dict["min"] = min_val | ||
# invalido eventuale Q e band passante ?!? | ||
banda_dict["q"] = None | ||
banda_dict["banda_passante"] = None | ||
banda_dict["fmax"] = fmax | ||
# non servono ulteriori elaborazioni | ||
continue | ||
|
||
else: | ||
logger.warning("finalizzo band precedente") | ||
out.append(banda_dict) | ||
banda_dict = None | ||
# se sono qui è nuova | ||
|
||
if estensione == 0 and vuoto: | ||
logger.warning("ritorno minima estensione") | ||
banda_dict = {"fmin": fmin - 30 * step, | ||
"fmax": fmin + 30 * step, | ||
"banda_passante": None, | ||
"q": None, | ||
"min": min_val, | ||
"freq": fmin, | ||
"prog": prog, | ||
} | ||
else: | ||
logger.warning("Nuova band") | ||
if min_val <= MIN_CALCOLO_Q: | ||
|
||
# FIXME: verificare che ci siano valori > | ||
# BAND_THRESHOLD?!? | ||
q = np.sqrt(fmax * fmin) / (fmax - fmin) | ||
logger.info("Q=%s", q) | ||
else: | ||
logger.info( | ||
"non calcolo Q perchè minimo %s non è abbastanza", min_val) | ||
q = None | ||
banda_dict = {"fmin": fmin, | ||
"fmax": fmax, | ||
"banda_passante": fmax - fmin, | ||
"q": q, | ||
"min": min_val, | ||
"freq": frequencies[prog], | ||
"prog": prog, | ||
} | ||
|
||
if banda_dict: | ||
out.append(banda_dict) | ||
return out | ||
|
||
class ChartFactory(object): | ||
|
||
@classmethod | ||
def NewChart(cls, chart_class, name, app): | ||
from NanoVNASaver.NanoVNASaver import BandsModel | ||
new_chart = chart_class(name) | ||
new_chart.isPopout = True | ||
new_chart.data = app.data | ||
new_chart.bands = BandsModel() | ||
i=0 | ||
default_color = app.default_marker_colors[i] | ||
color = app.settings.value("Marker" + str(i+1) + "Color", default_color) | ||
marker = Marker("Marker " + str(i+1), color) | ||
marker.isMouseControlledRadioButton.setChecked(True) | ||
new_chart.setMarkers([marker]) | ||
|
||
return new_chart | ||
|
||
class MinVswrAnalysis(Antenna, Analysis): | ||
|
||
def __init__(self, app): | ||
super().__init__(app) | ||
self._widget = QtWidgets.QWidget() | ||
|
||
def runAnalysis(self): | ||
self.reset() | ||
|
||
if len(self.app.data) == 0: | ||
logger.debug("No data to analyse") | ||
self.result_label.setText("No data to analyse.") | ||
return | ||
|
||
frequencies = [] | ||
values = [] | ||
for p in self.app.data: | ||
frequencies.append(p.freq) | ||
vswr = p.vswr | ||
values.append(vswr) | ||
|
||
res = self.analyze(np.array(frequencies), | ||
np.array(values), | ||
"vswr") | ||
marker = 0 | ||
for banda in res: | ||
if marker < 3: | ||
self.app.markers[marker].setFrequency( | ||
str(round(banda["freq"]))) | ||
marker += 1 | ||
print("min {min} a {freq}".format(**banda)) | ||
|
||
# Charts | ||
progr = 0 | ||
for c in self.app.subscribing_charts: | ||
if c.name == "S11 VSWR": | ||
new_chart = c.copy() | ||
new_chart.isPopout = True | ||
new_chart.show() | ||
new_chart.setWindowTitle("%s %s" % (new_chart.name, progr)) | ||
|
||
vna = self.app.vna | ||
if isinstance(vna, InvalidVNA): | ||
logger.warning("end analysis, non valid vna") | ||
else: | ||
logger.warning("band zoom") | ||
for banda in res: | ||
progr += 1 | ||
# scan | ||
self.app.sweepStartInput.setText(str(banda["fmin"])) | ||
self.app.sweepEndInput.setText(str(banda["fmax"])) | ||
self.app.sweep() | ||
while not self.app.btnSweep.isEnabled(): | ||
QtTest.QTest.qWait(500) | ||
for c in self.app.subscribing_charts: | ||
if c.name == "S11 VSWR": | ||
new_chart = c.copy() | ||
new_chart.isPopout = True | ||
new_chart.show() | ||
new_chart.setWindowTitle("%s %s" % (new_chart.name, progr)) | ||
|
||
|
||
class ZeroCrossAnalysis(Antenna, Analysis): | ||
|
||
def __init__(self, app): | ||
super().__init__(app) | ||
self._widget = QtWidgets.QWidget() | ||
|
||
def runAnalysis(self): | ||
self.reset() | ||
|
||
if len(self.app.data) == 0: | ||
logger.debug("No data to analyse") | ||
self.result_label.setText("No data to analyse.") | ||
return | ||
|
||
frequencies = [] | ||
values = [] | ||
for p in self.app.data: | ||
|
||
frequencies.append(p.freq) | ||
|
||
values.append(p.z.imag) | ||
|
||
zero_crossings = np.where(np.diff(np.sign(np.array(values))))[0] | ||
|
||
marker = 0 | ||
for pos in zero_crossings: | ||
freq = round(frequencies[pos]) | ||
if marker < 3: | ||
self.app.markers[marker].setFrequency( | ||
str(freq)) | ||
marker += 1 | ||
print("cross at {}".format(freq)) | ||
|
||
class MagLoopAnalysis(VSWRAnalysis): | ||
''' | ||
Find min vswr and change sweep to zoom. | ||
Useful for tuning magloop. | ||
''' | ||
max_dips_shown = 1 | ||
vswr_limit_value = 2.56 | ||
bandwith = 250000 | ||
|
||
def runAnalysis(self): | ||
|
||
super().runAnalysis() | ||
|
||
for m in self.minimums: | ||
start, lowest, end = m | ||
if start != end: | ||
Q = self.app.data[lowest].freq/(self.app.data[end].freq-self.app.data[start].freq) | ||
self.layout.addRow("Q",QtWidgets.QLabel("{}".format(int(Q)))) | ||
self.app.sweepStartInput.setText(self.app.data[start].freq) | ||
self.app.sweepEndInput.setText(self.app.data[end].freq) | ||
# self.app.sweepEndInput.textEdited.emit(self.app.sweepEndInput.text()) | ||
|
||
if len(self.minimums) > 1: | ||
self.layout.addRow("", QtWidgets.QLabel( | ||
"Not magloop or try to lower VSWR limit")) | ||
|
||
for m in self.minimums[:1]: | ||
# only one time | ||
start, lowest, end = m | ||
if start != end: | ||
Q = self.app.data11[lowest].freq / \ | ||
(self.app.data11[end].freq - self.app.data11[start].freq) | ||
self.layout.addRow( | ||
"Q", QtWidgets.QLabel("{}".format(int(Q)))) | ||
self.app.sweep_control.set_start(self.app.data11[start].freq) | ||
self.app.sweep_control.set_end(self.app.data11[end].freq) | ||
else: | ||
self.app.sweep_control.set_start( | ||
self.app.data11[start].freq - self.bandwith) | ||
self.app.sweep_control.set_end( | ||
self.app.data11[end].freq + self.bandwith) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.