Enhanced formatting for complex and low digit count

pull/140/head
Holger Mueller 2020-01-22 17:54:34 +01:00
rodzic 60d58015c4
commit 88a37c316b
7 zmienionych plików z 151 dodań i 41 usunięć

Wyświetl plik

@ -4096,7 +4096,7 @@ class CapacitanceChart(FrequencyChart):
self.span = span
target_ticks = math.floor(self.chartHeight / 60)
fmt = Format(max_nr_digits=3)
fmt = Format(max_nr_digits=1)
for i in range(target_ticks):
val = minValue + (i / target_ticks) * span
y = self.topMargin + round((self.maxValue - val) / self.span * self.chartHeight)
@ -4223,7 +4223,7 @@ class InductanceChart(FrequencyChart):
self.span = span
target_ticks = math.floor(self.chartHeight / 60)
fmt = Format(max_nr_digits=3)
fmt = Format(max_nr_digits=1)
for i in range(target_ticks):
val = minValue + (i / target_ticks) * span
y = self.topMargin + round((self.maxValue - val) / self.span * self.chartHeight)

Wyświetl plik

@ -23,6 +23,8 @@ FMT_FREQ_INPUTS = SITools.Format(max_nr_digits=10, allow_strip=True, printable_m
FMT_Q_FACTOR = SITools.Format(max_nr_digits=4, assume_infinity=False, min_offset=0, max_offset=0, allow_strip=True)
FMT_GROUP_DELAY = SITools.Format(max_nr_digits=5, space_str=" ")
FMT_REACT = SITools.Format(max_nr_digits=5, space_str=" ", allow_strip=True)
FMT_COMPLEX = SITools.Format(max_nr_digits=3, allow_strip=True,
printable_min=0, unprintable_under="- ")
def format_frequency(freq: float, fmt=FMT_FREQ) -> str:
@ -68,7 +70,7 @@ def format_inductance(val: float, allow_negative: bool = True) -> str:
def format_group_delay(val: float) -> str:
return str(SITools.Value(val, "s", fmt=FMT_GROUP_DELAY))
return str(SITools.Value(val, "s", FMT_GROUP_DELAY))
def format_phase(val: float) -> str:
@ -76,21 +78,6 @@ def format_phase(val: float) -> str:
def format_complex_imp(z: complex) -> str:
if z.real > 0:
if z.real >= 1000:
s = f"{z.real/1000:.3g}k"
else:
s = f"{z.real:.4g}"
else:
s = "- "
if z.imag < 0:
s += " -j"
else:
s += " +j"
if abs(z.imag) >= 1000:
s += f"{abs(z.imag)/1000:.3g}k"
elif abs(z.imag) < 0.1:
s += f"{abs(z.imag)*1000:.3g}m"
else:
s += f"{abs(z.imag):.3g}"
return s + " \N{OHM SIGN}"
re = SITools.Value(z.real, fmt=FMT_COMPLEX)
im = SITools.Value(abs(z.imag), fmt=FMT_COMPLEX)
return f"{re}{'-' if z.imag < 0 else '+'}j{im} \N{OHM SIGN}"

Wyświetl plik

@ -38,20 +38,15 @@ def parallel_to_serial(z: complex) -> complex:
def serial_to_parallel(z: complex) -> complex:
"""Convert serial impedance to parallel impedance equivalent"""
z_sq_sum = z.real ** 2 + z.imag ** 2
if z.real != 0 and z.imag != 0:
return complex(z_sq_sum / z.real, z_sq_sum / z.imag)
elif z.real != 0 and z_sq_sum > 0:
return complex(z_sq_sum / z.real, math.inf)
elif z.real != 0 and z_sq_sum < 0:
return complex(z_sq_sum / z.real, -math.inf)
elif z.imag != 0 and z_sq_sum > 0:
return complex(math.inf, z_sq_sum / z.real)
elif z.imag != 0 and z_sq_sum < 0:
return complex(-math.inf, z_sq_sum / z.real)
elif z_sq_sum == 0:
return complex(0, 0)
else:
if z.real == 0 and z.imag == 0:
return complex(math.inf, math.inf)
if z_sq_sum == 0:
return complex(0, 0)
if z.imag == 0:
return complex(z_sq_sum / z.real, math.copysign(math.inf, z_sq_sum))
if z.real == 0:
return complex(math.copysign(math.inf,z_sq_sum), z_sq_sum / z.real)
return complex(z_sq_sum / z.real, z_sq_sum / z.imag)
def impedance_to_capacitance(z: complex, freq: float) -> float:

Wyświetl plik

@ -59,7 +59,7 @@ class Value:
value: Union[Number, str] = 0,
unit: str = "",
fmt=Format()):
assert 3 <= fmt.max_nr_digits <= 30
assert 1 <= fmt.max_nr_digits <= 30
assert -8 <= fmt.min_offset <= fmt.max_offset <= 8
assert fmt.parse_clamp_min < fmt.parse_clamp_max
assert fmt.printable_min < fmt.printable_max
@ -91,7 +91,7 @@ class Value:
real = float(self._value) / (10 ** (offset * 3))
if fmt.max_nr_digits < 4:
if fmt.max_nr_digits < 3:
formstr = ".0f"
else:
max_digits = fmt.max_nr_digits + (

Wyświetl plik

@ -0,0 +1,112 @@
# NanoVNASaver
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019. Rune B. Broberg
#
# 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 unittest
# Import targets to be tested
from NanoVNASaver import Formatting as fmt
class TestCases(unittest.TestCase):
def test_format_frequency(self):
self.assertEqual(fmt.format_frequency(1), '1.00000 Hz')
self.assertEqual(fmt.format_frequency(12), '12.0000 Hz')
self.assertEqual(fmt.format_frequency(123), '123.000 Hz')
self.assertEqual(fmt.format_frequency(1234), '1.23400 kHz')
self.assertEqual(fmt.format_frequency(1234567), '1.23457 MHz')
self.assertEqual(fmt.format_frequency(1234567890), '1.23457 GHz')
self.assertEqual(fmt.format_frequency(0), '0.00000 Hz')
self.assertEqual(fmt.format_frequency(-1), '-1.00000 Hz')
def test_format_frequency_inputs(self):
self.assertEqual(fmt.format_frequency_inputs(1), '1Hz')
self.assertEqual(fmt.format_frequency_inputs(12), '12Hz')
self.assertEqual(fmt.format_frequency_inputs(123), '123Hz')
self.assertEqual(fmt.format_frequency_inputs(1234), '1.234kHz')
self.assertEqual(fmt.format_frequency_inputs(1234567), '1.234567MHz')
self.assertEqual(fmt.format_frequency_inputs(1234567890), '1.23456789GHz')
self.assertEqual(fmt.format_frequency_inputs(0), '0Hz')
self.assertEqual(fmt.format_frequency_inputs(-1), '- Hz')
def test_format_gain(self):
self.assertEqual(fmt.format_gain(1), '1.000 dB')
self.assertEqual(fmt.format_gain(12), '12.000 dB')
self.assertEqual(fmt.format_gain(1.23456), '1.235 dB')
self.assertEqual(fmt.format_gain(-1), '-1.000 dB')
self.assertEqual(fmt.format_gain(-1, invert=True), '1.000 dB')
def test_format_q_factor(self):
self.assertEqual(fmt.format_q_factor(1), '1')
self.assertEqual(fmt.format_q_factor(12), '12')
self.assertEqual(fmt.format_q_factor(123), '123')
self.assertEqual(fmt.format_q_factor(1234), '1234')
self.assertEqual(fmt.format_q_factor(12345), '\N{INFINITY}')
self.assertEqual(fmt.format_q_factor(-1), '\N{INFINITY}')
self.assertEqual(fmt.format_q_factor(1.2345), '1.234')
def test_format_vswr(self):
self.assertEqual(fmt.format_vswr(1), '1.000')
self.assertEqual(fmt.format_vswr(1.234), '1.234')
self.assertEqual(fmt.format_vswr(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}')
self.assertEqual(fmt.format_resistance(123), '123 \N{OHM SIGN}')
self.assertEqual(fmt.format_resistance(1234), '1.234 k\N{OHM SIGN}')
self.assertEqual(fmt.format_resistance(12345), '12.345 k\N{OHM SIGN}')
self.assertEqual(fmt.format_resistance(123456), '123.46 k\N{OHM SIGN}')
self.assertEqual(fmt.format_resistance(-1), '- \N{OHM SIGN}')
def test_format_capacitance(self):
self.assertEqual(fmt.format_capacitance(1), '1 F')
self.assertEqual(fmt.format_capacitance(1e-3), '1 mF')
self.assertEqual(fmt.format_capacitance(1e-6), '1 µF')
self.assertEqual(fmt.format_capacitance(1e-9), '1 nF')
self.assertEqual(fmt.format_capacitance(1e-12), '1 pF')
self.assertEqual(fmt.format_capacitance(-1), '-1 F')
self.assertEqual(fmt.format_capacitance(-1, False), '- pF')
def test_format_inductance(self):
self.assertEqual(fmt.format_inductance(1), '1 H')
self.assertEqual(fmt.format_inductance(1e-3), '1 mH')
self.assertEqual(fmt.format_inductance(1e-6), '1 µH')
self.assertEqual(fmt.format_inductance(1e-9), '1 nH')
self.assertEqual(fmt.format_inductance(1e-12), '1 pH')
self.assertEqual(fmt.format_inductance(-1), '-1 H')
self.assertEqual(fmt.format_inductance(-1, False), '- nH')
def test_format_group_delay(self):
self.assertEqual(fmt.format_group_delay(1), '1.0000 s')
self.assertEqual(fmt.format_group_delay(1e-9), '1.0000 ns')
self.assertEqual(fmt.format_group_delay(1.23456e-9), '1.2346 ns')
def test_format_phase(self):
self.assertEqual(fmt.format_phase(0), '0.00°')
self.assertEqual(fmt.format_phase(1), '57.30°')
self.assertEqual(fmt.format_phase(-1), '-57.30°')
self.assertEqual(fmt.format_phase(3.1416), '180.00°')
self.assertEqual(fmt.format_phase(6.2831), '360.00°')
self.assertEqual(fmt.format_phase(9.4247), '540.00°')
self.assertEqual(fmt.format_phase(-3.1416), '-180.00°')
def test_format_complex_imp(self):
self.assertEqual(fmt.format_complex_imp(complex(1, 0)), '1+j0 \N{OHM SIGN}')
self.assertEqual(fmt.format_complex_imp(complex(1234, 1234)), '1.23k+j1.23k \N{OHM SIGN}')
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}')

Wyświetl plik

@ -23,13 +23,15 @@ from math import inf
F_DEFAULT = Format()
F_ASSERT_DIGITS_1 = Format(max_nr_digits=2)
F_ASSERT_DIGITS_0 = Format(max_nr_digits=0)
F_ASSERT_DIGITS_2 = Format(max_nr_digits=31)
F_ASSERT_OFFSET_1 = Format(min_offset=-9)
F_ASSERT_OFFSET_2 = Format(max_offset=9)
F_ASSERT_OFFSET_3 = Format(min_offset=9)
F_ASSERT_CLAMP = Format(parse_clamp_min=10, parse_clamp_max=9)
F_DIGITS_1 = Format(max_nr_digits=1, min_offset=-2,
max_offset=2, assume_infinity=False)
F_DIGITS_3 = Format(max_nr_digits=3, min_offset=-2,
max_offset=2, assume_infinity=False)
F_DIGITS_4 = Format(max_nr_digits=4)
@ -42,7 +44,7 @@ F_WITH_UNDERSCORE = Format(space_str="_")
class TestTSIToolsValue(unittest.TestCase):
def test_format_assertions(self):
self.assertRaises(AssertionError, Value, fmt=F_ASSERT_DIGITS_1)
self.assertRaises(AssertionError, Value, fmt=F_ASSERT_DIGITS_0)
self.assertRaises(AssertionError, Value, fmt=F_ASSERT_DIGITS_2)
self.assertRaises(AssertionError, Value, fmt=F_ASSERT_OFFSET_1)
self.assertRaises(AssertionError, Value, fmt=F_ASSERT_OFFSET_2)
@ -95,8 +97,8 @@ class TestTSIToolsValue(unittest.TestCase):
self.assertEqual(str(Value(1e-30)), "0.00000")
self.assertEqual(float(Value(1e-30)), 1e-30)
def test_format_digits_3(self):
v = Value(fmt=F_DIGITS_3)
def test_format_digits_1(self):
v = Value(fmt=F_DIGITS_1)
self.assertEqual(str(v.parse("1")), "1")
self.assertEqual(str(v.parse("10")), "10")
self.assertEqual(str(v.parse("100")), "100")
@ -109,6 +111,20 @@ class TestTSIToolsValue(unittest.TestCase):
self.assertEqual(str(v.parse("1e-3")), "1m")
self.assertEqual(str(v.parse("1e-9")), "0")
def test_format_digits_3(self):
v = Value(fmt=F_DIGITS_3)
self.assertEqual(str(v.parse("1")), "1.00")
self.assertEqual(str(v.parse("10")), "10.0")
self.assertEqual(str(v.parse("100")), "100")
self.assertEqual(str(v.parse("1e3")), "1.00k")
self.assertEqual(str(v.parse("1e4")), "10.0k")
self.assertEqual(str(v.parse("1e5")), "100k")
self.assertEqual(str(v.parse("1e9")), "1000M")
self.assertEqual(str(v.parse("1e-1")), "100m")
self.assertEqual(str(v.parse("1e-2")), "10.0m")
self.assertEqual(str(v.parse("1e-3")), "1.00m")
self.assertEqual(str(v.parse("1e-9")), "0.00")
def test_format_digits_4(self):
v = Value(fmt=F_DIGITS_4)
self.assertEqual(str(v.parse("1")), "1.000")

Wyświetl plik

@ -31,7 +31,7 @@ import unittest
if __name__ == '__main__':
sys.path.append('.')
loader = unittest.TestLoader()
tests = loader.discover('.')
tests = loader.discover('./test')
testRunner = unittest.runner.TextTestRunner(
failfast=False,
verbosity=2)