Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import VNA
import pyvisa
import time
import numpy
import math
import cmath
import dut_measurement
class VnaData:
def __init__(self, power, frequency, s11, s21, s12, s22):
self.power = power
self.frequency = frequency
self.s11 = s11
self.s21 = s21
self.s12 = s12
self.s22 = s22
class VnaMeasurement(dut_measurement.DutMeasurement):
def __init__(self, config_data, target_accuracy):
self.delta_mag = config_data['delta_mag']
self.delta_phase = config_data['delta_phase']
self.vna = VNA.create_vna(config_data['vna_ip'], target_accuracy)
self.vna.load_config(config_data['vna_config_file'], config_data['frequency'])
self.vna.create_new_trace("Trace1", "S11")
self.vna.create_new_trace("Trace2", "S12")
self.vna.create_new_trace("Trace3", "S21")
self.vna.create_new_trace("Trace4", "S22")
def _get_trace_data(self, trace):
return self.vna.get_list_of_measurement_values(trace, "SDAT")
def get_dut_measurements(self):
# FIXME: The try/catch should be way down in the VNA class
for iteration in range(10):
try:
power = self.vna.get_current_power()
frequency = self.vna.get_current_cw_frequency()
self.vna.do_single_sweep()
s11 = self._get_trace_data("Trace1")
s12 = self._get_trace_data("Trace2")
s21 = self._get_trace_data("Trace3")
s22 = self._get_trace_data("Trace4")
return {'RF_POWER': power, 'RF_FREQUENCY': frequency,
'S11_MAGNITUDE': self.calculate_mean_magnitude_db(s11),
'S11_PHASE': self.calculate_mean_phase(s11),
'S12_MAGNITUDE': self.calculate_mean_magnitude_db(s12),
'S12_PHASE': self.calculate_mean_phase(s12),
'S21_MAGNITUDE': self.calculate_mean_magnitude_db(s21),
'S21_PHASE': self.calculate_mean_phase(s21),
'S22_MAGNITUDE': self.calculate_mean_magnitude_db(s22),
'S22_PHASE': self.calculate_mean_phase(s21)}
# exception for pyvisa error or timeout
except pyvisa.errors.VisaIOError:
# call reset function for VNA status register and error queue
self.vna.reset_status()
print('An error occurred during VNA read out')
# wait one second for next try
time.sleep(1)
# FIXME: In case we did not succeed we need something like a stop_measurement exception
raise Exception('FIXME: Throw stop_measurement here, and handle it. Don\'t crash!')
def get_dut_signal_names(self):
return ['RF_POWER', 'RF_FREQUENCY', 'S11_MAGNITUDE', 'S11_PHASE', 'S12_MAGNITUDE',
'S12_PHASE', 'S21_MAGNITUDE', 'S21_PHASE', 'S22_MAGNITUDE', 'S22_PHASE']
def get_dut_reference_signal_names(self):
return ['S21_MAGNITUDE', 'S21_PHASE']
def get_dut_max_delta_signals(self):
return [self.delta_mag, self.delta_phase]
def calculate_complex_numbers(self, values_list):
real_num = values_list[::2]
imaginary_num = values_list[1::2]
complex_numbers = []
for i, q in zip(real_num, imaginary_num):
complex_numbers.append(complex(i, q))
return complex_numbers
def calculate_magnitudes(self, values_list):
complex_numbers = self.calculate_complex_numbers(values_list)
magnitudes = [abs(val) for val in complex_numbers]
return magnitudes
def calculate_mean_magnitude(self, values_list):
magnitudes = self.calculate_magnitudes(values_list)
return numpy.mean(magnitudes)
def calculate_mean_magnitude_db(self, values_list):
return 20*math.log10(self.calculate_mean_magnitude(values_list))
def calculate_phases(self, values_list):
complex_numbers = self.calculate_complex_numbers(values_list)
phases = [math.degrees(cmath.phase(val)) for val in complex_numbers]
return phases
def calculate_mean_phase(self, values_list):
phases = self.calculate_phases(values_list)
return numpy.mean(phases)