Skip to content

Commit

Permalink
Merge pull request #261 from NanoVNA-Saver/Development
Browse files Browse the repository at this point in the history
v0.3.6
  • Loading branch information
zarath committed Jul 17, 2020
2 parents 408eda6 + 4d4c65a commit 85e1374
Show file tree
Hide file tree
Showing 40 changed files with 1,233 additions and 1,450 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/venv/
/env/
.idea
.vscode
/build/
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
v0.3.6
======

- Implemented bandwidth setting in device management

v0.3.5
======

- Sweep worker now initializes full dataset on setting changes.
Therefore no resize of charts when doing multi segment sweep
- Changing datapoints in DeviceSettings are reflected in SweepSettings widget step size
- Simplified calibration code by just using scipy.interp1d with fill\_value
- Established Interface class to ease locking and allow non usb connections in future
- Cleaned up VNA code. Added some pause statements to get more robust readings
- Added MagLoopAnalysis
- Touchstone class can now generate interpolated Datapoints for a given frequency
Will be usefull in future analysis code
- Fixed a bug in Version comparison


v0.3.4
======

Expand Down
2 changes: 1 addition & 1 deletion NanoVNASaver/About.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

VERSION = "0.3.4"
VERSION = "0.3.6"
VERSION_URL = (
"https://raw.githubusercontent.com/"
"NanoVNA-Saver/nanovna-saver/master/NanoVNASaver/About.py")
Expand Down
295 changes: 44 additions & 251 deletions NanoVNASaver/Analysis/AntennaAnalysis.py
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)
6 changes: 3 additions & 3 deletions NanoVNASaver/Analysis/BandPassAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def runAnalysis(self):
peak_db = db
peak_location = i

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

lower_cutoff_location = -1
pass_band_db = peak_db
Expand Down Expand Up @@ -355,8 +355,8 @@ def runAnalysis(self):

if upper_cutoff_gain < -4 or lower_cutoff_gain < -4:
self.result_label.setText(
f"Analysis complete ({len(self.app.data)} points)\n"
f"Analysis complete ({len(self.app.data11)} points)\n"
f"Insufficient data for analysis. Increase segment count.")
else:
self.result_label.setText(
f"Analysis complete ({len(self.app.data)} points)")
f"Analysis complete ({len(self.app.data11)} points)")
6 changes: 3 additions & 3 deletions NanoVNASaver/Analysis/BandStopAnalysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def runAnalysis(self):
peak_db = db
peak_location = i

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

lower_cutoff_location = -1
pass_band_db = peak_db
Expand Down Expand Up @@ -309,8 +309,8 @@ def runAnalysis(self):

if upper_cutoff_gain < -4 or lower_cutoff_gain < -4:
self.result_label.setText(
f"Analysis complete ({len(self.app.data)} points)\n"
f"Analysis complete ({len(self.app.data11)} points)\n"
f"Insufficient data for analysis. Increase segment count.")
else:
self.result_label.setText(
f"Analysis complete ({len(self.app.data)} points)")
f"Analysis complete ({len(self.app.data11)} points)")
Loading

0 comments on commit 85e1374

Please sign in to comment.