diff --git a/.coveragerc b/.coveragerc
index 7269f7e..6f64402 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -10,7 +10,7 @@ omit =
NanoVNASaver/Inputs.py
NanoVNASaver/Marker/*.py
NanoVNASaver/NanoVNASaver.py
- NanoVNASaver/Settings.py
+ NanoVNASaver/Settings/Bands.py
NanoVNASaver/SweepWorker.py
NanoVNASaver/Windows/*.py
**/__init__.py
diff --git a/NanoVNASaver/Formatting.py b/NanoVNASaver/Formatting.py
index 2f04972..7c406f8 100644
--- a/NanoVNASaver/Formatting.py
+++ b/NanoVNASaver/Formatting.py
@@ -104,7 +104,7 @@ def format_group_delay(val: float) -> str:
def format_phase(val: float) -> str:
- return f"{math.degrees(val):.2f}\N{DEGREE SIGN}"
+ return f"{math.degrees(val):.2f}""\N{DEGREE SIGN}"
def format_complex_imp(z: complex, allow_negative: bool = False) -> str:
@@ -113,7 +113,7 @@ def format_complex_imp(z: complex, allow_negative: bool = False) -> str:
fmt_re = FMT_COMPLEX_NEG
re = SITools.Value(z.real, fmt=fmt_re)
im = SITools.Value(abs(z.imag), fmt=FMT_COMPLEX)
- return f"{re}{'-' if z.imag < 0 else '+'}j{im} \N{OHM SIGN}"
+ return f"{re}{'-' if z.imag < 0 else '+'}j{im} ""\N{OHM SIGN}"
def format_wavelength(length: Number) -> str:
return str(SITools.Value(length, "m", FMT_WAVELENGTH))
diff --git a/NanoVNASaver/Settings/Sweep.py b/NanoVNASaver/Settings/Sweep.py
index 1a4e018..9884214 100644
--- a/NanoVNASaver/Settings/Sweep.py
+++ b/NanoVNASaver/Settings/Sweep.py
@@ -58,7 +58,7 @@ class Sweep():
def stepsize(self) -> int:
return round(self.span / ((self.points -1) * self.segments))
- def _exp_factor(self, index: int) -> int:
+ def _exp_factor(self, index: int) -> float:
return 1 - log(self.segments + 1 - index) / log(self.segments + 1)
def get_index_range(self, index: int) -> Tuple[int, int]:
@@ -66,8 +66,8 @@ class Sweep():
start = self.start + index * self.points * self.step
end = start + (self.points - 1) * self.step
else:
- start = self.start + self.span * self._exp_factor(index)
- end = self.start + self.span * self._exp_factor(index + 1)
+ start = round(self.start + self.span * self._exp_factor(index))
+ end = round(self.start + self.span * self._exp_factor(index + 1))
logger.debug("get_index_range(%s) -> (%s, %s)", index, start, end)
return (start, end)
diff --git a/NanoVNASaver/Version.py b/NanoVNASaver/Version.py
index 305429b..6fff530 100644
--- a/NanoVNASaver/Version.py
+++ b/NanoVNASaver/Version.py
@@ -1,5 +1,4 @@
# 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
@@ -18,142 +17,10 @@
# along with this program. If not, see .
import logging
import re
-import typing
-from typing import List, Tuple
-
-from PyQt5 import QtCore, QtGui
-from PyQt5.QtCore import QModelIndex
logger = logging.getLogger(__name__)
-class BandsModel(QtCore.QAbstractTableModel):
- bands: List[Tuple[str, int, int]] = []
- enabled = False
- color = QtGui.QColor(128, 128, 128, 48)
-
- # These bands correspond broadly to the Danish Amateur Radio allocation
- default_bands = ["2200 m;135700;137800",
- "630 m;472000;479000",
- "160 m;1800000;2000000",
- "80 m;3500000;3800000",
- "60 m;5250000;5450000",
- "40 m;7000000;7200000",
- "30 m;10100000;10150000",
- "20 m;14000000;14350000",
- "17 m;18068000;18168000",
- "15 m;21000000;21450000",
- "12 m;24890000;24990000",
- "10 m;28000000;29700000",
- "6 m;50000000;52000000",
- "4 m;69887500;70512500",
- "2 m;144000000;146000000",
- "70 cm;432000000;438000000",
- "23 cm;1240000000;1300000000",
- "13 cm;2320000000;2450000000"]
-
- def __init__(self):
- super().__init__()
- self.settings = QtCore.QSettings(QtCore.QSettings.IniFormat,
- QtCore.QSettings.UserScope,
- "NanoVNASaver", "Bands")
- self.settings.setIniCodec("UTF-8")
- self.enabled = self.settings.value("ShowBands", False, bool)
-
- stored_bands: List[str] = self.settings.value("bands", self.default_bands)
- if stored_bands:
- for b in stored_bands:
- (name, start, end) = b.split(";")
- self.bands.append((name, int(start), int(end)))
-
- def saveSettings(self):
- stored_bands = []
- for b in self.bands:
- stored_bands.append(b[0] + ";" + str(b[1]) + ";" + str(b[2]))
- self.settings.setValue("bands", stored_bands)
- self.settings.sync()
-
- def resetBands(self):
- self.bands = []
- for b in self.default_bands:
- (name, start, end) = b.split(";")
- self.bands.append((name, int(start), int(end)))
- self.layoutChanged.emit()
- self.saveSettings()
-
- def columnCount(self, parent: QModelIndex = ...) -> int:
- return 3
-
- def rowCount(self, parent: QModelIndex = ...) -> int:
- return len(self.bands)
-
- def data(self, index: QModelIndex, role: int = ...) -> QtCore.QVariant:
- if (role == QtCore.Qt.DisplayRole or
- role == QtCore.Qt.ItemDataRole or role == QtCore.Qt.EditRole):
- return QtCore.QVariant(self.bands[index.row()][index.column()])
- if role == QtCore.Qt.TextAlignmentRole:
- if index.column() == 0:
- return QtCore.QVariant(QtCore.Qt.AlignCenter)
- return QtCore.QVariant(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
- return QtCore.QVariant()
-
- def setData(self, index: QModelIndex, value: typing.Any, role: int = ...) -> bool:
- if role == QtCore.Qt.EditRole and index.isValid():
- t = self.bands[index.row()]
- name = t[0]
- start = t[1]
- end = t[2]
- if index.column() == 0:
- name = value
- elif index.column() == 1:
- start = value
- elif index.column() == 2:
- end = value
- self.bands[index.row()] = (name, start, end)
- self.dataChanged.emit(index, index)
- self.saveSettings()
- return True
- return False
-
- def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex:
- return self.createIndex(row, column)
-
- def addRow(self):
- self.bands.append(("New", 0, 0))
- self.dataChanged.emit(self.index(len(self.bands), 0), self.index(len(self.bands), 2))
- self.layoutChanged.emit()
-
- def removeRow(self, row: int, parent: QModelIndex = ...) -> bool:
- self.bands.remove(self.bands[row])
- self.layoutChanged.emit()
- self.saveSettings()
- return True
-
- def headerData(self, section: int,
- orientation: QtCore.Qt.Orientation, role: int = ...):
- if (role == QtCore.Qt.DisplayRole and
- orientation == QtCore.Qt.Horizontal):
- if section == 0:
- return "Band"
- if section == 1:
- return "Start (Hz)"
- if section == 2:
- return "End (Hz)"
- return "Invalid"
- super().headerData(section, orientation, role)
-
- def flags(self, index: QModelIndex) -> QtCore.Qt.ItemFlags:
- if index.isValid():
- return QtCore.Qt.ItemFlags(
- QtCore.Qt.ItemIsEditable |
- QtCore.Qt.ItemIsEnabled |
- QtCore.Qt.ItemIsSelectable)
- super().flags(index)
-
- def setColor(self, color):
- self.color = color
-
-
class Version:
RXP = re.compile(r"""^
\D*
diff --git a/NanoVNASaver/Windows/SweepSettings.py b/NanoVNASaver/Windows/SweepSettings.py
index 721324d..136fe04 100644
--- a/NanoVNASaver/Windows/SweepSettings.py
+++ b/NanoVNASaver/Windows/SweepSettings.py
@@ -77,7 +77,7 @@ class SweepSettingsWindow(QtWidgets.QWidget):
"averages. Common values are 3/0, 5/2, 9/4 and 25/6.\n")
label.setWordWrap(True)
settings_layout.addRow(label)
-
+
self.s21att = QtWidgets.QLineEdit("0")
label = QtWidgets.QLabel(
"Some times when you measure amplifiers you need to use an"
@@ -88,7 +88,8 @@ class SweepSettingsWindow(QtWidgets.QWidget):
settings_layout.addRow("Attenuator in port CH1 (s21) in dB", self.s21att)
- # settings_layout.addRow(QtWidgets.QLabel("Common values with un-un are 16.9 (49:1 2450) 9.54 (9:1 450)"))
+ # settings_layout.addRow(QtWidgets.QLabel(
+ # "Common values with un-un are 16.9 (49:1 2450) 9.54 (9:1 450)"))
self.continuous_sweep_radiobutton.toggled.connect(
lambda: self.app.worker.setContinuousSweep(
diff --git a/test/test_formatting.py b/test/test_formatting.py
index 9bb8b75..86997b2 100644
--- a/test/test_formatting.py
+++ b/test/test_formatting.py
@@ -25,6 +25,15 @@ from NanoVNASaver import Formatting as fmt
class TestCases(unittest.TestCase):
def test_format_frequency(self):
+ self.assertEqual(fmt.format_frequency(1), '1.00000Hz')
+ self.assertEqual(fmt.format_frequency(12), '12.0000Hz')
+ self.assertEqual(fmt.format_frequency(123), '123.000Hz')
+ self.assertEqual(fmt.format_frequency(1234), '1.23400kHz')
+ self.assertEqual(fmt.format_frequency(1234567), '1.23457MHz')
+ self.assertEqual(fmt.format_frequency(1234567890), '1.23457GHz')
+ self.assertEqual(fmt.format_frequency(0), '0.00000Hz')
+ self.assertEqual(fmt.format_frequency(-1), '-1.00000Hz')
+
self.assertEqual(fmt.format_frequency_space(1), '1.00000 Hz')
self.assertEqual(fmt.format_frequency_space(12), '12.0000 Hz')
self.assertEqual(fmt.format_frequency_space(123), '123.000 Hz')
@@ -34,6 +43,15 @@ class TestCases(unittest.TestCase):
self.assertEqual(fmt.format_frequency_space(0), '0.00000 Hz')
self.assertEqual(fmt.format_frequency_space(-1), '-1.00000 Hz')
+ self.assertEqual(fmt.format_frequency_short(1), '1.000Hz')
+ self.assertEqual(fmt.format_frequency_short(12), '12.00Hz')
+ self.assertEqual(fmt.format_frequency_short(123), '123.0Hz')
+ self.assertEqual(fmt.format_frequency_short(1234), '1.234kHz')
+ self.assertEqual(fmt.format_frequency_short(1234567), '1.235MHz')
+ self.assertEqual(fmt.format_frequency_short(1234567890), '1.235GHz')
+ self.assertEqual(fmt.format_frequency_short(0), '0.000Hz')
+ self.assertEqual(fmt.format_frequency_short(-1), '-1.000Hz')
+
def test_format_frequency_inputs(self):
self.assertEqual(fmt.format_frequency_inputs(1), '1Hz')
self.assertEqual(fmt.format_frequency_inputs(12), '12Hz')
@@ -65,6 +83,11 @@ class TestCases(unittest.TestCase):
self.assertEqual(fmt.format_vswr(1.234), '1.234')
self.assertEqual(fmt.format_vswr(12345.12345), '12345.123')
+ def test_format_magnitude(self):
+ self.assertEqual(fmt.format_magnitude(1), '1.000')
+ self.assertEqual(fmt.format_magnitude(1.234), '1.234')
+ self.assertEqual(fmt.format_magnitude(12345.12345), '12345.123')
+
def test_format_resistance(self):
self.assertEqual(fmt.format_resistance(1), '1 \N{OHM SIGN}')
self.assertEqual(fmt.format_resistance(12), '12 \N{OHM SIGN}')
@@ -112,3 +135,7 @@ class TestCases(unittest.TestCase):
self.assertEqual(fmt.format_complex_imp(complex(1234, -1234)), '1.23k-j1.23k \N{OHM SIGN}')
self.assertEqual(fmt.format_complex_imp(complex(1.234, 1234)), '1.23+j1.23k \N{OHM SIGN}')
self.assertEqual(fmt.format_complex_imp(complex(-1, 1.23e-3)), '- +j1.23m \N{OHM SIGN}')
+ self.assertEqual(fmt.format_complex_imp(complex(-1, 1.23e-3), True), '-1+j1.23m \N{OHM SIGN}')
+
+ def test_format_wavelength(self):
+ self.assertEqual(fmt.format_wavelength(12.3456), '12.35 m')
diff --git a/test/test_sweep.py b/test/test_sweep.py
new file mode 100644
index 0000000..912ddb4
--- /dev/null
+++ b/test/test_sweep.py
@@ -0,0 +1,42 @@
+# 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 unittest
+
+# Import targets to be tested
+from NanoVNASaver.Settings import Sweep
+
+class TestCases(unittest.TestCase):
+
+ def test_sweep(self):
+ sweep = Sweep()
+ self.assertEqual(str(sweep), 'Sweep(3600000, 30000000, 101, 1, False)')
+ self.assertTrue(Sweep(3600000) == sweep)
+ self.assertFalse(Sweep(3600001) == sweep)
+ self.assertRaises(ValueError, Sweep, -1)
+ sweep = Sweep(segments = 3)
+ self.assertEqual(sweep.get_index_range(1), (12488000, 21288000))
+ data = list(sweep.get_frequencies())
+ self.assertEqual(data[0], 3600000)
+ self.assertEqual(data[-1], 30000000)
+ sweep = Sweep(segments = 3, logarithmic=True)
+ self.assertEqual(sweep.get_index_range(1), (9078495, 16800000))
+ data = list(sweep.get_frequencies())
+ self.assertEqual(data[0], 3600000)
+ self.assertEqual(data[-1], 29869307)
+
diff --git a/test/test_version.py b/test/test_version.py
new file mode 100644
index 0000000..17312ab
--- /dev/null
+++ b/test/test_version.py
@@ -0,0 +1,38 @@
+# 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 unittest
+
+# Import targets to be tested
+from NanoVNASaver.Version import Version
+
+class TestCases(unittest.TestCase):
+
+ def test_version(self):
+ ver = Version("v1.2.3-test")
+ self.assertEqual(str(ver), '1.2.3-test')
+ self.assertLessEqual(ver, Version("1.2.4"))
+ self.assertFalse(ver > Version("1.2.4"))
+ self.assertFalse(ver > Version("1.2.3-u"))
+ self.assertTrue(Version("1.2.4") >= ver)
+ self.assertFalse(Version("0.0.0") == Version("0.0.0-rc"))
+ self.assertEqual(ver.major, 1)
+ self.assertEqual(ver.minor, 2)
+ self.assertEqual(ver.revision, 3)
+ self.assertEqual(ver.note, '-test')
+ Version("asdasd")