Compare commits
6 Commits
b4e4b689ea
...
f05dbe3a09
Author | SHA1 | Date | |
---|---|---|---|
f05dbe3a09 | |||
f021780971 | |||
6f947a28fa | |||
581131f1e0 | |||
adf6e40752 | |||
411f96dd87 |
@@ -274,7 +274,7 @@ def main() -> None:
|
|||||||
"Pluto IP Address",
|
"Pluto IP Address",
|
||||||
"Enter Pluto IP Address",
|
"Enter Pluto IP Address",
|
||||||
QLineEdit.Normal,
|
QLineEdit.Normal,
|
||||||
"192.168.2.1",
|
Charon.DEFAULT_IP,
|
||||||
)
|
)
|
||||||
match = re.match(r"(\d{1,3}\.){3}\d{1,3}", text)
|
match = re.match(r"(\d{1,3}\.){3}\d{1,3}", text)
|
||||||
if not match:
|
if not match:
|
||||||
|
@@ -82,7 +82,7 @@ class AD9361DacStepFactor(IntEnum):
|
|||||||
|
|
||||||
class Charon:
|
class Charon:
|
||||||
FREQUENCY_OFFSET = 1e6
|
FREQUENCY_OFFSET = 1e6
|
||||||
DEFAULT_IP = "192.168.2.1"
|
DEFAULT_IP = "192.168.3.1"
|
||||||
|
|
||||||
calibration: rf.calibration.Calibration | None = None
|
calibration: rf.calibration.Calibration | None = None
|
||||||
|
|
||||||
@@ -90,8 +90,11 @@ class Charon:
|
|||||||
self,
|
self,
|
||||||
ip: str = DEFAULT_IP,
|
ip: str = DEFAULT_IP,
|
||||||
frequency: npt.ArrayLike = np.linspace(1e9, 2e9, 3),
|
frequency: npt.ArrayLike = np.linspace(1e9, 2e9, 3),
|
||||||
ports: Tuple[int] = (1,),
|
ports: Tuple[int] | int = 1,
|
||||||
):
|
):
|
||||||
|
if isinstance(ports, int):
|
||||||
|
ports = (np.arange(ports) + 1).tolist()
|
||||||
|
ports = tuple(ports)
|
||||||
self.ports = ports
|
self.ports = ports
|
||||||
self.frequency = frequency
|
self.frequency = frequency
|
||||||
|
|
||||||
@@ -128,7 +131,7 @@ class Charon:
|
|||||||
self.sdr.rx_hardwaregain_chan1 = 10
|
self.sdr.rx_hardwaregain_chan1 = 10
|
||||||
self.sdr.tx_hardwaregain_chan0 = -10
|
self.sdr.tx_hardwaregain_chan0 = -10
|
||||||
|
|
||||||
# # switch control
|
# switch control
|
||||||
ctx = iio.Context(uri)
|
ctx = iio.Context(uri)
|
||||||
self.ctrl = ctx.find_device("ad9361-phy")
|
self.ctrl = ctx.find_device("ad9361-phy")
|
||||||
# raw ad9361 register accesss:
|
# raw ad9361 register accesss:
|
||||||
@@ -136,11 +139,14 @@ class Charon:
|
|||||||
# https://www.analog.com/media/cn/technical-documentation/user-guides/ad9364_register_map_reference_manual_ug-672.pdf # noqa: E501
|
# https://www.analog.com/media/cn/technical-documentation/user-guides/ad9364_register_map_reference_manual_ug-672.pdf # noqa: E501
|
||||||
self.ctrl.reg_write(AD9361Register.EXTERNAL_LNA_CONTROL, 0x90) # bit 7: AuxDAC Manual, bit 4: GPO Manual
|
self.ctrl.reg_write(AD9361Register.EXTERNAL_LNA_CONTROL, 0x90) # bit 7: AuxDAC Manual, bit 4: GPO Manual
|
||||||
self.ctrl.reg_write(AD9361Register.AUXDAC_ENABLE_CONTROL, 0x3F)
|
self.ctrl.reg_write(AD9361Register.AUXDAC_ENABLE_CONTROL, 0x3F)
|
||||||
|
|
||||||
|
# initialize switch control outputs
|
||||||
self._set_gpo(0b0000)
|
self._set_gpo(0b0000)
|
||||||
self._set_dac_code(value=0, channel=1)
|
self._set_dac_code(value=0, channel=1)
|
||||||
self._set_dac_code(value=0, channel=2)
|
self._set_dac_code(value=0, channel=2)
|
||||||
|
|
||||||
self.set_switches(a=0, b=0)
|
# set default switch state
|
||||||
|
self.set_switches(a=self.ports[0] - 1, b=self.ports[0] - 1)
|
||||||
|
|
||||||
def get_config(self) -> Dict[str, Any]:
|
def get_config(self) -> Dict[str, Any]:
|
||||||
config = dict()
|
config = dict()
|
||||||
@@ -170,20 +176,15 @@ class Charon:
|
|||||||
def _set_gpo(self, value: int) -> None:
|
def _set_gpo(self, value: int) -> None:
|
||||||
self.ctrl.reg_write(AD9361Register.GPO_FORCE_AND_INIT, (value & 0x0F) << 4) # bits 7-4: GPO3-0
|
self.ctrl.reg_write(AD9361Register.GPO_FORCE_AND_INIT, (value & 0x0F) << 4) # bits 7-4: GPO3-0
|
||||||
|
|
||||||
def _set_dac_voltage(self, voltage: float, channel: Literal[1, 2]):
|
def _get_dac_code(self, channel: Literal[1, 2]) -> Tuple[float, AD9361DacVref, AD9361DacStepFactor]:
|
||||||
raise NotImplementedError()
|
word = self.ctrl.reg_read(AD9361Register.__getitem__(f"AUXDAC{channel}_WORD"))
|
||||||
|
config = self.ctrl.reg_read(AD9361Register.__getitem__(f"AUXDAC{channel}_CONFIG"))
|
||||||
|
|
||||||
def set_switches(self, a: int, b: int, excitation: int | None = None):
|
value = (word << 2) + (config & 0x3)
|
||||||
if excitation is None:
|
vref = AD9361DacVref((config >> 2) & 0x3)
|
||||||
excitation = a
|
step_factor = AD9361DacStepFactor((config >> 4) & 0x1)
|
||||||
|
|
||||||
val = 0
|
return (value, vref, step_factor)
|
||||||
|
|
||||||
val |= int(bool(excitation)) << 0 # exc = GPO0
|
|
||||||
val |= int(bool(a)) << 2 # a = GPO2
|
|
||||||
val |= int(bool(b)) << 1 # b = GPO1
|
|
||||||
|
|
||||||
self._set_gpo(val)
|
|
||||||
|
|
||||||
def _set_dac_code(
|
def _set_dac_code(
|
||||||
self,
|
self,
|
||||||
@@ -217,18 +218,17 @@ class Charon:
|
|||||||
(value & 0x3) | (vref.value << 2) | (step_factor << 4),
|
(value & 0x3) | (vref.value << 2) | (step_factor << 4),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_dac_code(self, channel: Literal[1, 2]) -> Tuple[float, AD9361DacVref, AD9361DacStepFactor]:
|
def set_switches(self, b: int, a: int, excitation: int | None = None):
|
||||||
word = self.ctrl.reg_read(AD9361Register.__getitem__(f"AUXDAC{channel}_WORD"))
|
if excitation is None:
|
||||||
config = self.ctrl.reg_read(AD9361Register.__getitem__(f"AUXDAC{channel}_CONFIG"))
|
excitation = a
|
||||||
|
|
||||||
value = (word << 2) + (config & 0x3)
|
val = 0
|
||||||
vref = AD9361DacVref((config >> 2) & 0x3)
|
|
||||||
step_factor = AD9361DacStepFactor((config >> 4) & 0x1)
|
|
||||||
|
|
||||||
return (value, vref, step_factor)
|
val |= int(bool(excitation)) << 0 # exc = GPO0
|
||||||
|
val |= int(bool(a)) << 2 # a = GPO2
|
||||||
|
val |= int(bool(b)) << 1 # b = GPO1
|
||||||
|
|
||||||
def _get_dac_voltage(self) -> float:
|
self._set_gpo(val)
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def set_output_power(self, power: float):
|
def set_output_power(self, power: float):
|
||||||
pout = xr.DataArray(
|
pout = xr.DataArray(
|
||||||
@@ -305,22 +305,26 @@ class Charon:
|
|||||||
|
|
||||||
return np.mean(data[1] / data[0])
|
return np.mean(data[1] / data[0])
|
||||||
|
|
||||||
def sweep_b_over_a(self):
|
def sweep_b_over_a(self, **kwargs):
|
||||||
s = xr.DataArray(
|
s = xr.DataArray(
|
||||||
np.zeros(
|
np.zeros(
|
||||||
len(self.frequency),
|
[len(self.frequency), len(self.ports), len(self.ports)],
|
||||||
dtype=np.complex128,
|
dtype=np.complex128,
|
||||||
),
|
),
|
||||||
dims=["frequency"],
|
dims=["frequency", "m", "n"],
|
||||||
coords=dict(
|
coords=dict(
|
||||||
frequency=self.frequency,
|
frequency=self.frequency,
|
||||||
|
m=list(self.ports),
|
||||||
|
n=list(self.ports),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
for frequency in self.frequency:
|
for m in s.m.data:
|
||||||
s.loc[dict(frequency=frequency)] = self.get_b_over_a(frequency=frequency)
|
for n in s.n.data:
|
||||||
|
self.set_switches(b=m - 1, a=n - 1)
|
||||||
|
s.loc[dict(m=m, n=n)] = self.vna_capture(frequency=self.frequency, **kwargs)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def vna_capture(self, frequency: npt.ArrayLike, callback: Callable[int, int] | None):
|
def vna_capture(self, frequency: npt.ArrayLike, callback: Callable[int, int] | None = None):
|
||||||
s = xr.DataArray(
|
s = xr.DataArray(
|
||||||
np.empty(len(frequency), dtype=np.complex128),
|
np.empty(len(frequency), dtype=np.complex128),
|
||||||
dims=["frequency"],
|
dims=["frequency"],
|
||||||
|
24
charon_vna/vna_dev.py
Normal file
24
charon_vna/vna_dev.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# %% imports
|
||||||
|
import numpy as np
|
||||||
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
from charon_vna.vna import Charon
|
||||||
|
|
||||||
|
# %%
|
||||||
|
frequency = np.linspace(80e6, 280e6, 31)
|
||||||
|
|
||||||
|
# %%
|
||||||
|
vna = Charon(frequency=frequency, ports=2)
|
||||||
|
|
||||||
|
# %%
|
||||||
|
s = vna.sweep_b_over_a()
|
||||||
|
|
||||||
|
# %%
|
||||||
|
for m in s.m.data:
|
||||||
|
for n in s.n.data:
|
||||||
|
plt.plot(s.frequency, 20 * np.log10(np.abs(s.sel(m=m, n=n))), label="$S_{" + str(m) + str(n) + "}$")
|
||||||
|
plt.grid(True)
|
||||||
|
plt.legend()
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
Reference in New Issue
Block a user