functional 1 port calibration
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
# %% imports
|
# %% imports
|
||||||
import copy
|
import copy
|
||||||
|
import pickle
|
||||||
from enum import IntEnum, unique
|
from enum import IntEnum, unique
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, Dict, List, Literal, Tuple
|
from typing import Any, Callable, Dict, List, Literal, Tuple
|
||||||
@ -360,6 +361,51 @@ class Charon:
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def calibrate_sol(self, prompt: Callable[[str], None] | None = None, **kwargs) -> rf.calibration.Calibration:
|
||||||
|
if len(self.ports) != 1:
|
||||||
|
raise ValueError(
|
||||||
|
f"SOL calibration needs only one port but {len(self.ports)} ports are enabled. "
|
||||||
|
"Did you mean to use SOLT?"
|
||||||
|
)
|
||||||
|
|
||||||
|
if prompt is None:
|
||||||
|
prompt = lambda s: input(f"{s}\nENTER to continue...")
|
||||||
|
|
||||||
|
ideal = rf.media.DefinedGammaZ0(frequency=rf.media.Frequency.from_f(self.frequency, unit="Hz"))
|
||||||
|
ideals = [ideal.short(), ideal.open(), ideal.load(0)]
|
||||||
|
|
||||||
|
names = ["short", "open", "load"]
|
||||||
|
|
||||||
|
measured = list()
|
||||||
|
for name in names:
|
||||||
|
prompt(f"Connect standard: {name} to port {self.ports[0]}")
|
||||||
|
measured.append(self.capture(**kwargs))
|
||||||
|
|
||||||
|
cal = rf.OnePort(ideals=ideals, measured=[s2net(m) for m in measured])
|
||||||
|
|
||||||
|
self.calibration = cal
|
||||||
|
|
||||||
|
return cal
|
||||||
|
|
||||||
|
def save_calibration(self, path: Path | str):
|
||||||
|
path = Path(path)
|
||||||
|
if path.suffix.lower() == ".pkl":
|
||||||
|
with open(str(path), "wb") as f:
|
||||||
|
pickle.dump(self.calibration, f)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"Unknown calibration file extension: {path.suffix}")
|
||||||
|
|
||||||
|
def load_calibration(self, path: Path | str):
|
||||||
|
path = Path(path)
|
||||||
|
if path.suffix.lower() == ".pkl":
|
||||||
|
with open(str(path), "rb") as f:
|
||||||
|
cal = pickle.load(f)
|
||||||
|
if not isinstance(cal, rf.calibration.Calibration):
|
||||||
|
raise ValueError(f"Expected {rf.calibration.Calibration}, got {type(cal)}")
|
||||||
|
self.calibration = cal
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"Unknown calibration file extension: {path.suffix}")
|
||||||
|
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -2,23 +2,52 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from matplotlib import pyplot as plt
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
|
from charon_vna.util import db20, net2s, s2net
|
||||||
from charon_vna.vna import Charon
|
from charon_vna.vna import Charon
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
frequency = np.linspace(80e6, 280e6, 31)
|
frequency = np.linspace(80e6, 280e6, 301)
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
vna = Charon(frequency=frequency, ports=2)
|
vna = Charon(frequency=frequency, ports=1)
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
s = vna.capture(measurements=[(2, 1), (2, 2)])
|
s = vna.capture()
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
for m in s.m.data:
|
for m in s.m.data:
|
||||||
for n in s.n.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.plot(s.frequency, db20(s.sel(m=m, n=n)), label="$S_{" + str(m) + str(n) + "}$")
|
||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
plt.legend()
|
plt.legend()
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
vna.calibrate_sol()
|
||||||
|
|
||||||
|
# %%
|
||||||
|
vna.load_calibration("./calibration.pkl")
|
||||||
|
|
||||||
|
# %%
|
||||||
|
s2 = net2s(vna.calibration.apply_cal(s2net(s)))
|
||||||
|
|
||||||
|
for m in s.m.data:
|
||||||
|
for n in s.n.data:
|
||||||
|
plt.plot(s.frequency, db20(s.sel(m=m, n=n)), label="$S_{" + str(m) + str(n) + "}$ (uncalibrated)")
|
||||||
|
plt.plot(s2.frequency, db20(s2.sel(m=m, n=n)), label="$S_{" + str(m) + str(n) + "}$ (calibrated)")
|
||||||
|
plt.grid(True)
|
||||||
|
plt.legend()
|
||||||
|
plt.ylabel("Magnitude [dB]")
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
for m in s.m.data:
|
||||||
|
for n in s.n.data:
|
||||||
|
plt.plot(s.frequency, np.angle(s.sel(m=m, n=n), deg=True), label="$S_{" + str(m) + str(n) + "}$ (uncalibrated)")
|
||||||
|
plt.plot(s2.frequency, np.angle(s2.sel(m=m, n=n), deg=True), label="$S_{" + str(m) + str(n) + "}$ (calibrated)")
|
||||||
|
plt.grid(True)
|
||||||
|
plt.legend()
|
||||||
|
plt.ylabel("Phase [deg]")
|
||||||
|
plt.show()
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
|
Reference in New Issue
Block a user