mirror of
https://github.com/nqrduck/nqrduck-autotm.git
synced 2024-11-05 01:40:01 +00:00
Added information on calibration.
This commit is contained in:
parent
ae3a42f869
commit
6a36c9db5f
3 changed files with 79 additions and 30 deletions
|
@ -121,6 +121,14 @@ class AutoTMController(ModuleController):
|
||||||
def calculate_calibration(self) -> None:
|
def calculate_calibration(self) -> None:
|
||||||
"""This method is called when the calculate calibration button is pressed.
|
"""This method is called when the calculate calibration button is pressed.
|
||||||
It calculates the calibration from the short, open and calibration data points.
|
It calculates the calibration from the short, open and calibration data points.
|
||||||
|
|
||||||
|
@TODO: Make calibration useful. Right now the calibration does not work for the probe coils. It completly messes up the S11 data.
|
||||||
|
For 50 Ohm reference loads the calibration makes the S11 data usable - one then gets a flat line at -50 dB.
|
||||||
|
The problem is probably two things:
|
||||||
|
1. The ideal values for open, short and load should be measured with a VNA and then be loaded for the calibration.
|
||||||
|
The ideal values are probably not -1, 1 and 0 but will also show frequency dependent behaviour.
|
||||||
|
2 The AD8302 chip only returns the absolute value of the phase. One would probably need to calculate the phase with various algorithms found in the literature.
|
||||||
|
Though Im not sure if these proposed algorithms would work for the AD8302 chip.
|
||||||
"""
|
"""
|
||||||
logger.debug("Calculating calibration")
|
logger.debug("Calculating calibration")
|
||||||
# First we check if the short and open calibration data points are available
|
# First we check if the short and open calibration data points are available
|
||||||
|
@ -143,26 +151,40 @@ class AutoTMController(ModuleController):
|
||||||
measured_gamma_open = self.module.model.open_calibration.gamma
|
measured_gamma_open = self.module.model.open_calibration.gamma
|
||||||
measured_gamma_load = self.module.model.load_calibration.gamma
|
measured_gamma_load = self.module.model.load_calibration.gamma
|
||||||
|
|
||||||
e_00s = []
|
E_Ds = []
|
||||||
e11s = []
|
E_Ss = []
|
||||||
delta_es = []
|
E_ts = []
|
||||||
for gamma_s, gamma_o, gamma_l in zip(measured_gamma_short, measured_gamma_open, measured_gamma_load):
|
for gamma_s, gamma_o, gamma_l in zip(measured_gamma_short, measured_gamma_open, measured_gamma_load):
|
||||||
A = np.array([
|
# This is the solution from
|
||||||
[1, ideal_gamma_short * gamma_s, -ideal_gamma_short],
|
# A = np.array([
|
||||||
[1, ideal_gamma_open * gamma_o, -ideal_gamma_open],
|
# [1, ideal_gamma_short * gamma_s, -ideal_gamma_short],
|
||||||
[1, ideal_gamma_load * gamma_l, -ideal_gamma_load]
|
# [1, ideal_gamma_open * gamma_o, -ideal_gamma_open],
|
||||||
])
|
# [1, ideal_gamma_load * gamma_l, -ideal_gamma_load]
|
||||||
|
# ])
|
||||||
|
|
||||||
B = np.array([gamma_s, gamma_o, gamma_l])
|
# B = np.array([gamma_s, gamma_o, gamma_l])
|
||||||
|
|
||||||
# Solve the system
|
# Solve the system
|
||||||
e_00, e11, delta_e = np.linalg.lstsq(A, B, rcond=None)[0]
|
# e_00, e11, delta_e = np.linalg.lstsq(A, B, rcond=None)[0]
|
||||||
|
|
||||||
e_00s.append(e_00)
|
E_D = gamma_l
|
||||||
e11s.append(e11)
|
E_ = (2 * gamma_l - (gamma_s + gamma_o)) / (gamma_s - gamma_o)
|
||||||
delta_es.append(delta_e)
|
E_S = (2 * (gamma_o + gamma_l) * (gamma_s + gamma_l)) / (gamma_s - gamma_o)
|
||||||
|
|
||||||
self.module.model.calibration = (e_00s, e11s, delta_es)
|
E_Ds.append(E_D)
|
||||||
|
E_Ss.append(E_S)
|
||||||
|
E_ts.append(E_)
|
||||||
|
# e_00 = gamma_l # Because here the reflection coefficient should be 0
|
||||||
|
|
||||||
|
# e11 = (gamma_o + gamma_o - 2 * e_00) / (gamma_o - gamma_s)
|
||||||
|
|
||||||
|
# delta_e = -gamma_o + gamma_o* e11 + e_00
|
||||||
|
|
||||||
|
# e_00s.append(e_00)
|
||||||
|
# e11s.append(e11)
|
||||||
|
# delta_es.append(delta_e)
|
||||||
|
|
||||||
|
self.module.model.calibration = (E_Ds, E_Ss, E_ts)
|
||||||
|
|
||||||
def export_calibration(self, filename: str) -> None:
|
def export_calibration(self, filename: str) -> None:
|
||||||
"""This method is called when the export calibration button is pressed.
|
"""This method is called when the export calibration button is pressed.
|
||||||
|
|
|
@ -40,7 +40,12 @@ class S11Data:
|
||||||
@property
|
@property
|
||||||
def gamma(self):
|
def gamma(self):
|
||||||
"""Complex reflection coefficient"""
|
"""Complex reflection coefficient"""
|
||||||
return map(cmath.rect, (10 ** (-self.return_loss_db / 20), self.phase_rad))
|
if len(self.return_loss_db) != len(self.phase_rad):
|
||||||
|
raise ValueError("return_loss_db and phase_rad must be the same length")
|
||||||
|
|
||||||
|
return [cmath.rect(10 ** (-loss_db / 20), phase_rad) for loss_db, phase_rad in zip(self.return_loss_db, self.phase_rad)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return {
|
return {
|
||||||
|
@ -72,6 +77,7 @@ class AutoTMModel(ModuleModel):
|
||||||
super().__init__(module)
|
super().__init__(module)
|
||||||
self.data_points = []
|
self.data_points = []
|
||||||
self.active_calibration = None
|
self.active_calibration = None
|
||||||
|
self.calibration = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available_devices(self):
|
def available_devices(self):
|
||||||
|
|
|
@ -126,27 +126,48 @@ class AutoTMView(ModuleView):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data_points (list): List of data points to plot.
|
data_points (list): List of data points to plot.
|
||||||
|
|
||||||
|
@TODO: implement proper calibration. See the controller class for more information.
|
||||||
"""
|
"""
|
||||||
frequency = data.frequency
|
frequency = data.frequency
|
||||||
return_loss_db = data.return_loss_db
|
return_loss_db = data.return_loss_db
|
||||||
phase = data.phase_deg
|
phase = data.phase_deg
|
||||||
|
|
||||||
gamma = data.gamma
|
gamma = data.gamma
|
||||||
# Calibration test:
|
# Plot complex reflection coefficient
|
||||||
#calibration = self.module.model.calibration
|
""" import matplotlib.pyplot as plt
|
||||||
#e_00 = calibration[0]
|
fig, ax = plt.subplots()
|
||||||
#e11 = calibration[1]
|
ax.plot([g.real for g in gamma], [g.imag for g in gamma])
|
||||||
#delta_e = calibration[2]
|
ax.set_aspect('equal')
|
||||||
|
ax.grid(True)
|
||||||
|
ax.set_title("Complex reflection coefficient")
|
||||||
|
ax.set_xlabel("Real")
|
||||||
|
ax.set_ylabel("Imaginary")
|
||||||
|
plt.show()
|
||||||
|
"""
|
||||||
|
|
||||||
|
magnitude_ax = self._ui_form.S11Plot.canvas.ax
|
||||||
|
# @ TODO: implement proper calibration
|
||||||
|
if self.module.model.calibration is not None:
|
||||||
|
# Calibration test:
|
||||||
|
import cmath
|
||||||
|
calibration = self.module.model.calibration
|
||||||
|
E_D = calibration[0]
|
||||||
|
E_S = calibration[1]
|
||||||
|
E_t = calibration[2]
|
||||||
|
|
||||||
#y_corr = [(data_point - e_00[i]) / (data_point * e11[i] - delta_e[i]) for i, data_point in enumerate(y)]
|
# gamma_corr = [(data_point - e_00[i]) / (data_point * e11[i] - delta_e[i]) for i, data_point in enumerate(gamma)]
|
||||||
#import numpy as np
|
gamma_corr = [(data_point - E_D[i]) / (E_S[i] * (data_point - E_D[i]) + E_t[i]) for i, data_point in enumerate(gamma)]
|
||||||
#y = [data_point[1] for data_point in self.module.model.data_points]
|
""" fig, ax = plt.subplots()
|
||||||
#open_calibration = [data_point[1] for data_point in self.module.model.open_calibration]
|
ax.plot([g.real for g in gamma_corr], [g.imag for g in gamma_corr])
|
||||||
#load_calibration = [data_point[1] for data_point in self.module.model.load_calibration]
|
ax.set_aspect('equal')
|
||||||
#short_calibration = [data_point[1] for data_point in self.module.model.short_calibration]
|
ax.grid(True)
|
||||||
|
ax.set_title("Complex reflection coefficient")
|
||||||
#y_corr = np.array(y) - np.array(load_calibration)
|
ax.set_xlabel("Real")
|
||||||
#y_corr = y_corr - np.mean(y_corr)
|
ax.set_ylabel("Imaginary")
|
||||||
|
plt.show() """
|
||||||
|
return_loss_db_corr = [-20 * cmath.log10(abs(g + 1e-12)) for g in gamma_corr]
|
||||||
|
magnitude_ax.plot(frequency, return_loss_db_corr, color="red")
|
||||||
|
|
||||||
phase_ax = self._ui_form.S11Plot.canvas.ax.twinx()
|
phase_ax = self._ui_form.S11Plot.canvas.ax.twinx()
|
||||||
phase_ax.set_ylabel("Phase (deg)")
|
phase_ax.set_ylabel("Phase (deg)")
|
||||||
|
@ -154,7 +175,7 @@ class AutoTMView(ModuleView):
|
||||||
phase_ax.set_ylim(-180, 180)
|
phase_ax.set_ylim(-180, 180)
|
||||||
phase_ax.invert_yaxis()
|
phase_ax.invert_yaxis()
|
||||||
|
|
||||||
magnitude_ax = self._ui_form.S11Plot.canvas.ax
|
|
||||||
magnitude_ax.clear()
|
magnitude_ax.clear()
|
||||||
magnitude_ax.set_xlabel("Frequency (MHz)")
|
magnitude_ax.set_xlabel("Frequency (MHz)")
|
||||||
magnitude_ax.set_ylabel("S11 (dB)")
|
magnitude_ax.set_ylabel("S11 (dB)")
|
||||||
|
|
Loading…
Reference in a new issue