Fix merge conflict.

pull/697/head
Otto Edgren 2024-04-09 16:17:16 +02:00
commit 0ecbad1833
12 zmienionych plików z 59 dodań i 99 usunięć

Wyświetl plik

@ -42,3 +42,5 @@ Contributors
* Thomas de Lellis <24543390+t52ta6ek@users.noreply.github.com> * Thomas de Lellis <24543390+t52ta6ek@users.noreply.github.com>
* zstadler <zeev.stadler@gmail.com> * zstadler <zeev.stadler@gmail.com>
* tbergkvist <bergkvist.teo@protonmail.com> * tbergkvist <bergkvist.teo@protonmail.com>
* timmythetank <maans.jacobsson@gmail.com>
* ottoedgren <edgrenotto@gmail.com>

Wyświetl plik

@ -6,4 +6,5 @@ vna = NanoVNASaverHeadless(vna_index=0, verbose=True)
vna.set_sweep(2.9e9, 3.1e9) vna.set_sweep(2.9e9, 3.1e9)
vna.calibrate() vna.calibrate()
vna.stream_data() vna.stream_data()
# vna.calibrate()
vna.kill() vna.kill()

Wyświetl plik

@ -149,29 +149,22 @@ class CalDataSet(UserDict):
+ "\n" + "\n"
+ "# Hz ShortR ShortI OpenR OpenI LoadR LoadI" + "# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
+ ( + (
" ThroughR ThroughI ThrureflR" " ThroughR ThroughI ThrureflR" " ThrureflI IsolationR IsolationI\n"
" ThrureflI IsolationR IsolationI\n"
if self.complete2port() if self.complete2port()
else "\n" else "\n"
) )
+ "\n".join( + "\n".join([f"{self.data.get(freq)}" for freq in self.frequencies()])
[f"{self.data.get(freq)}" for freq in self.frequencies()]
)
+ "\n" + "\n"
) )
if self.complete1port() if self.complete1port()
else "" else ""
) )
def _append_match( def _append_match(self, m: re.Match, header: str, line_nr: int, line: str) -> None:
self, m: re.Match, header: str, line_nr: int, line: str
) -> None:
cal = m.groupdict() cal = m.groupdict()
columns = {col[:-1] for col in cal.keys() if cal[col] and col != "freq"} columns = {col[:-1] for col in cal.keys() if cal[col] and col != "freq"}
if "through" in columns and header == "sol": if "through" in columns and header == "sol":
logger.warning( logger.warning("Through data with sol header. %i: %s", line_nr, line)
"Through data with sol header. %i: %s", line_nr, line
)
# fix short data (without thrurefl) # fix short data (without thrurefl)
if "thrurefl" in columns and "isolation" not in columns: if "thrurefl" in columns and "isolation" not in columns:
cal["isolationr"] = cal["thrureflr"] cal["isolationr"] = cal["thrureflr"]
@ -201,9 +194,7 @@ class CalDataSet(UserDict):
continue continue
if m := RXP_CAL_HEADER.search(line): if m := RXP_CAL_HEADER.search(line):
if header: if header:
logger.warning( logger.warning("Duplicate header in cal data. %i: %s", i, line)
"Duplicate header in cal data. %i: %s", i, line
)
header = "through" if m.group("through") else "sol" header = "through" if m.group("through") else "sol"
continue continue
if not line or line.startswith("#"): if not line or line.startswith("#"):
@ -214,9 +205,7 @@ class CalDataSet(UserDict):
logger.warning("Illegal caldata. Line %i: %s", i, line) logger.warning("Illegal caldata. Line %i: %s", i, line)
continue continue
if not header: if not header:
logger.warning( logger.warning("Caldata without having read header: %i: %s", i, line)
"Caldata without having read header: %i: %s", i, line
)
self._append_match(m, header, line, i) self._append_match(m, header, line, i)
return self return self
@ -290,7 +279,7 @@ class Calibration:
def isValid2Port(self) -> bool: def isValid2Port(self) -> bool:
return self.dataset.complete2port() return self.dataset.complete2port()
def _calc_port_1(self, freq: int, cal: CalData): def _calc_port_1(self, freq: int, cal: CalData):
g1 = self.gamma_short(freq) g1 = self.gamma_short(freq)
g2 = self.gamma_open(freq) g2 = self.gamma_open(freq)
@ -309,8 +298,7 @@ class Calibration:
cal.e00 = ( cal.e00 = (
-( -(
(g2 * gm3 - g3 * gm3) * g1 * gm2 (g2 * gm3 - g3 * gm3) * g1 * gm2
- (g2 * g3 * gm2 - g2 * g3 * gm3 - (g3 * gm2 - g2 * gm3) * g1) - (g2 * g3 * gm2 - g2 * g3 * gm3 - (g3 * gm2 - g2 * gm3) * g1) * gm1
* gm1
) )
/ denominator / denominator
) )
@ -388,9 +376,7 @@ class Calibration:
return ( return (
(Zsp / 50.0 - 1.0) (Zsp / 50.0 - 1.0)
/ (Zsp / 50.0 + 1.0) / (Zsp / 50.0 + 1.0)
* cmath.exp( * cmath.exp(complex(0.0, -4.0 * math.pi * freq * cal_element.short_length))
complex(0.0, -4.0 * math.pi * freq * cal_element.short_length)
)
) )
def gamma_open(self, freq: int) -> complex: def gamma_open(self, freq: int) -> complex:
@ -430,9 +416,7 @@ class Calibration:
return ( return (
(Zl / 50.0 - 1.0) (Zl / 50.0 - 1.0)
/ (Zl / 50.0 + 1.0) / (Zl / 50.0 + 1.0)
* cmath.exp( * cmath.exp(complex(0.0, -4 * math.pi * freq * cal_element.load_length))
complex(0.0, -4 * math.pi * freq * cal_element.load_length)
)
) )
def gamma_through(self, freq: int) -> complex: def gamma_through(self, freq: int) -> complex:
@ -524,8 +508,7 @@ class Calibration:
i = self.interp i = self.interp
s21 = (dp.z - i["e30"](dp.freq)) / i["e10e32"](dp.freq) s21 = (dp.z - i["e30"](dp.freq)) / i["e10e32"](dp.freq)
s21 = s21 * ( s21 = s21 * (
i["e10e01"](dp.freq) i["e10e01"](dp.freq) / (i["e11"](dp.freq) * dp11.z - i["delta_e"](dp.freq))
/ (i["e11"](dp.freq) * dp11.z - i["delta_e"](dp.freq))
) )
return Datapoint(dp.freq, s21.real, s21.imag) return Datapoint(dp.freq, s21.real, s21.imag)

Wyświetl plik

@ -84,11 +84,7 @@ def _fix_v2_hwinfo(dev):
def usb_typename(device: ListPortInfo) -> str: def usb_typename(device: ListPortInfo) -> str:
return next( return next(
( (t.name for t in USBDEVICETYPES if device.vid == t.vid and device.pid == t.pid),
t.name
for t in USBDEVICETYPES
if device.vid == t.vid and device.pid == t.pid
),
"", "",
) )
@ -135,9 +131,11 @@ def get_portinfos() -> list[str]:
portinfos.append(version) portinfos.append(version)
return portinfos return portinfos
def get_VNA(iface: Interface) -> VNA: def get_VNA(iface: Interface) -> VNA:
return NAME2DEVICE[iface.comment](iface) return NAME2DEVICE[iface.comment](iface)
def get_comment(iface: Interface) -> str: def get_comment(iface: Interface) -> str:
logger.info("Finding correct VNA type...") logger.info("Finding correct VNA type...")
with iface.lock: with iface.lock:

Wyświetl plik

@ -62,9 +62,7 @@ class NanoVNA(VNA):
self.serial.write("capture\r".encode("ascii")) self.serial.write("capture\r".encode("ascii"))
self.serial.readline() self.serial.readline()
self.serial.timeout = 4 self.serial.timeout = 4
image_data = self.serial.read( image_data = self.serial.read(self.screenwidth * self.screenheight * 2)
self.screenwidth * self.screenheight * 2
)
self.serial.timeout = timeout self.serial.timeout = timeout
self.serial.timeout = timeout self.serial.timeout = timeout
return image_data return image_data
@ -145,9 +143,7 @@ class NanoVNA(VNA):
f"scan {self.start} {self.stop} {self.datapoints} 0b110" f"scan {self.start} {self.stop} {self.datapoints} 0b110"
): ):
data = line.split() data = line.split()
self._sweepdata.append( self._sweepdata.append((f"{data[0]} {data[1]}", f"{data[2]} {data[3]}"))
(f"{data[0]} {data[1]}", f"{data[2]} {data[3]}")
)
if value == "data 0": if value == "data 0":
return [x[0] for x in self._sweepdata] return [x[0] for x in self._sweepdata]
if value == "data 1": if value == "data 1":

Wyświetl plik

@ -121,10 +121,7 @@ class NanoVNA_V2(VNA):
self.txPowerRanges = [ self.txPowerRanges = [
( (
(140e6, self.sweep_max_freq_Hz), (140e6, self.sweep_max_freq_Hz),
[ [_ADF4350_TXPOWER_DESC_MAP[value] for value in (3, 2, 1, 0)],
_ADF4350_TXPOWER_DESC_MAP[value]
for value in (3, 2, 1, 0)
],
), ),
] ]
@ -172,14 +169,10 @@ class NanoVNA_V2(VNA):
self.serial.write(pack("<Q", 0)) self.serial.write(pack("<Q", 0))
sleep(WRITE_SLEEP) sleep(WRITE_SLEEP)
# cmd: write register 0x30 to clear FIFO # cmd: write register 0x30 to clear FIFO
self.serial.write( self.serial.write(pack("<BBB", _CMD_WRITE, _ADDR_VALUES_FIFO, 0))
pack("<BBB", _CMD_WRITE, _ADDR_VALUES_FIFO, 0)
)
sleep(WRITE_SLEEP) sleep(WRITE_SLEEP)
# clear sweepdata # clear sweepdata
self._sweepdata = [(complex(), complex())] * ( self._sweepdata = [(complex(), complex())] * (self.datapoints + s21hack)
self.datapoints + s21hack
)
pointstodo = self.datapoints + s21hack pointstodo = self.datapoints + s21hack
# we read at most 255 values at a time and the time required # we read at most 255 values at a time and the time required
# empirically is just over 3 seconds for 101 points or # empirically is just over 3 seconds for 101 points or
@ -205,9 +198,7 @@ class NanoVNA_V2(VNA):
# timeout secs # timeout secs
arr = self.serial.read(nBytes) arr = self.serial.read(nBytes)
if nBytes != len(arr): if nBytes != len(arr):
logger.warning( logger.warning("expected %d bytes, got %d", nBytes, len(arr))
"expected %d bytes, got %d", nBytes, len(arr)
)
# the way to retry on timeout is keep the data # the way to retry on timeout is keep the data
# already read then try to read the rest of # already read then try to read the rest of
# the data into the array # the data into the array
@ -225,9 +216,7 @@ class NanoVNA_V2(VNA):
self._sweepdata = self._sweepdata[1:] self._sweepdata = self._sweepdata[1:]
idx = 1 if value == "data 1" else 0 idx = 1 if value == "data 1" else 0
return [ return [f"{str(x[idx].real)} {str(x[idx].imag)}" for x in self._sweepdata]
f"{str(x[idx].real)} {str(x[idx].imag)}" for x in self._sweepdata
]
def resetSweep(self, start: int, stop: int): def resetSweep(self, start: int, stop: int):
self.setSweep(start, stop) self.setSweep(start, stop)
@ -251,9 +240,7 @@ class NanoVNA_V2(VNA):
return result return result
def read_board_revision(self) -> "Version": def read_board_revision(self) -> "Version":
result = self._read_version( result = self._read_version(_ADDR_DEVICE_VARIANT, _ADDR_HARDWARE_REVISION)
_ADDR_DEVICE_VARIANT, _ADDR_HARDWARE_REVISION
)
logger.debug("read_board_revision: %s", result) logger.debug("read_board_revision: %s", result)
return result return result
@ -279,12 +266,8 @@ class NanoVNA_V2(VNA):
_ADDR_SWEEP_START, _ADDR_SWEEP_START,
max(50000, int(self.sweepStartHz - (self.sweepStepHz * s21hack))), max(50000, int(self.sweepStartHz - (self.sweepStepHz * s21hack))),
) )
cmd += pack( cmd += pack("<BBQ", _CMD_WRITE8, _ADDR_SWEEP_STEP, int(self.sweepStepHz))
"<BBQ", _CMD_WRITE8, _ADDR_SWEEP_STEP, int(self.sweepStepHz) cmd += pack("<BBH", _CMD_WRITE2, _ADDR_SWEEP_POINTS, self.datapoints + s21hack)
)
cmd += pack(
"<BBH", _CMD_WRITE2, _ADDR_SWEEP_POINTS, self.datapoints + s21hack
)
cmd += pack("<BBH", _CMD_WRITE2, _ADDR_SWEEP_VALS_PER_FREQ, 1) cmd += pack("<BBH", _CMD_WRITE2, _ADDR_SWEEP_VALS_PER_FREQ, 1)
with self.serial.lock: with self.serial.lock:
self.serial.write(cmd) self.serial.write(cmd)

Wyświetl plik

@ -62,9 +62,7 @@ class TinySA(VNA):
self.serial.write("capture\r".encode("ascii")) self.serial.write("capture\r".encode("ascii"))
self.serial.readline() self.serial.readline()
self.serial.timeout = 4 self.serial.timeout = 4
image_data = self.serial.read( image_data = self.serial.read(self.screenwidth * self.screenheight * 2)
self.screenwidth * self.screenheight * 2
)
self.serial.timeout = timeout self.serial.timeout = timeout
self.serial.timeout = timeout self.serial.timeout = timeout
return image_data return image_data
@ -122,8 +120,7 @@ class TinySA(VNA):
logger.debug("Read: %s", value) logger.debug("Read: %s", value)
if value == "data 0": if value == "data 0":
self._sweepdata = [ self._sweepdata = [
f"{conv2float(line)} 0.0" f"{conv2float(line)} 0.0" for line in self.exec_command("data 0")
for line in self.exec_command("data 0")
] ]
return self._sweepdata return self._sweepdata

Wyświetl plik

@ -43,9 +43,7 @@ WAIT = 0.05
def _max_retries(bandwidth: int, datapoints: int) -> int: def _max_retries(bandwidth: int, datapoints: int) -> int:
return round( return round(
20 20 + 20 * (datapoints / 101) + (1000 / bandwidth) ** 1.30 * (datapoints / 101)
+ 20 * (datapoints / 101)
+ (1000 / bandwidth) ** 1.30 * (datapoints / 101)
) )
@ -149,9 +147,7 @@ class VNA:
] ]
def set_bandwidth(self, bandwidth: int): def set_bandwidth(self, bandwidth: int):
bw_val = ( bw_val = DISLORD_BW[bandwidth] if self.bw_method == "dislord" else bandwidth
DISLORD_BW[bandwidth] if self.bw_method == "dislord" else bandwidth
)
result = " ".join(self.exec_command(f"bandwidth {bw_val}")) result = " ".join(self.exec_command(f"bandwidth {bw_val}"))
if self.bw_method == "ttrftech" and result: if self.bw_method == "ttrftech" and result:
raise IOError(f"set_bandwith({bandwidth}: {result}") raise IOError(f"set_bandwith({bandwidth}: {result}")

Wyświetl plik

@ -22,13 +22,16 @@ import typing
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
_RXP = re.compile(r"""^ _RXP = re.compile(
r"""^
\D* \D*
(?P<major>\d+)\. (?P<major>\d+)\.
(?P<minor>\d+)\.? (?P<minor>\d+)\.?
(?P<revision>\d+)? (?P<revision>\d+)?
(?P<note>.*) (?P<note>.*)
$""", re.VERBOSE) $""",
re.VERBOSE,
)
class _Version(typing.NamedTuple): class _Version(typing.NamedTuple):
@ -38,18 +41,17 @@ class _Version(typing.NamedTuple):
note: str note: str
def __str__(self) -> str: def __str__(self) -> str:
return ( return f"{self.major}.{self.minor}" f".{self.revision}{self.note}"
f'{self.major}.{self.minor}'
f'.{self.revision}{self.note}'
)
def Version(vstring: str = "0.0.0") -> '_Version': def Version(vstring: str = "0.0.0") -> "_Version":
if (match := _RXP.search(vstring)) is None: if (match := _RXP.search(vstring)) is None:
logger.error("Unable to parse version: %s", vstring) logger.error("Unable to parse version: %s", vstring)
return _Version(0, 0, 0, '') return _Version(0, 0, 0, "")
return _Version(int(match.group('major')), return _Version(
int(match.group('minor')), int(match.group("major")),
int(match.group('revision') or '0'), int(match.group("minor")),
match.group('note')) int(match.group("revision") or "0"),
match.group("note"),
)

Wyświetl plik

@ -5,6 +5,7 @@ from .RFTools import Datapoint
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import math import math
class NanoVNASaverHeadless: class NanoVNASaverHeadless:
def __init__(self, vna_index=0, verbose=False): def __init__(self, vna_index=0, verbose=False):
self.verbose = verbose self.verbose = verbose
@ -39,7 +40,14 @@ class NanoVNASaverHeadless:
def set_sweep(self, start, stop): def set_sweep(self, start, stop):
self.vna.setSweep(start, stop) self.vna.setSweep(start, stop)
print("Sweep set from " + str(self.vna.readFrequencies()[0]/1e9) + "e9" + " to " + str(self.vna.readFrequencies()[-1]/1e9) + "e9") print(
"Sweep set from "
+ str(self.vna.readFrequencies()[0] / 1e9)
+ "e9"
+ " to "
+ str(self.vna.readFrequencies()[-1] / 1e9)
+ "e9"
)
def stream_data(self): def stream_data(self):
data = self.get_data() data = self.get_data()
@ -80,7 +88,7 @@ class NanoVNASaverHeadless:
values = item.split() values = item.split()
real.append(float(values[0])) real.append(float(values[0]))
imaginary.append(float(values[1])) imaginary.append(float(values[1]))
#add exception handling # add exception handling
return real, imaginary return real, imaginary
def kill(self): def kill(self):
@ -90,4 +98,4 @@ class NanoVNASaverHeadless:
else: else:
if self.verbose: if self.verbose:
print("Disconnected VNA.") print("Disconnected VNA.")
return return

Wyświetl plik

@ -76,9 +76,7 @@ class Datapoint(NamedTuple):
return -1 if imp.real == 0.0 else abs(imp.imag / imp.real) return -1 if imp.real == 0.0 else abs(imp.imag / imp.real)
def capacitiveEquivalent(self, ref_impedance: float = 50) -> float: def capacitiveEquivalent(self, ref_impedance: float = 50) -> float:
return impedance_to_capacitance( return impedance_to_capacitance(self.impedance(ref_impedance), self.freq)
self.impedance(ref_impedance), self.freq
)
def inductiveEquivalent(self, ref_impedance: float = 50) -> float: def inductiveEquivalent(self, ref_impedance: float = 50) -> float:
return impedance_to_inductance(self.impedance(ref_impedance), self.freq) return impedance_to_inductance(self.impedance(ref_impedance), self.freq)
@ -125,9 +123,7 @@ def norm_to_impedance(z: complex, ref_impedance: float = 50) -> complex:
def parallel_to_serial(z: complex) -> complex: def parallel_to_serial(z: complex) -> complex:
"""Convert parallel impedance to serial impedance equivalent""" """Convert parallel impedance to serial impedance equivalent"""
z_sq_sum = z.real**2 + z.imag**2 or 10.0e-30 z_sq_sum = z.real**2 + z.imag**2 or 10.0e-30
return complex( return complex(z.real * z.imag**2 / z_sq_sum, z.real**2 * z.imag / z_sq_sum)
z.real * z.imag**2 / z_sq_sum, z.real**2 * z.imag / z_sq_sum
)
def reflection_coefficient(z: complex, ref_impedance: float = 50) -> complex: def reflection_coefficient(z: complex, ref_impedance: float = 50) -> complex:

Wyświetl plik

@ -116,9 +116,7 @@ class Value:
fmt = self.fmt fmt = self.fmt
if math.isnan(self._value): if math.isnan(self._value):
return f"-{fmt.space_str}{self._unit}" return f"-{fmt.space_str}{self._unit}"
if fmt.assume_infinity and abs(self._value) >= 10 ** ( if fmt.assume_infinity and abs(self._value) >= 10 ** ((fmt.max_offset + 1) * 3):
(fmt.max_offset + 1) * 3
):
return ( return (
("-" if self._value < 0 else "") ("-" if self._value < 0 else "")
+ "\N{INFINITY}" + "\N{INFINITY}"