diff --git a/Software/Integrationtests/Integrationtest.py b/Software/Integrationtests/Integrationtest.py index 4213936..77d2b9e 100644 --- a/Software/Integrationtests/Integrationtest.py +++ b/Software/Integrationtests/Integrationtest.py @@ -9,6 +9,7 @@ testmodules = [ 'tests.TestCalibration', 'tests.TestGenerator', 'tests.TestSASweep', + 'tests.TestRST', ] suite = unittest.TestSuite() diff --git a/Software/Integrationtests/tests/TestRST.py b/Software/Integrationtests/tests/TestRST.py new file mode 100644 index 0000000..9ed9c4c --- /dev/null +++ b/Software/Integrationtests/tests/TestRST.py @@ -0,0 +1,246 @@ +import re +from tests.TestBase import TestBase + +float_re = re.compile(r'^[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]\d+)?$') +int_re = re.compile(r'^\d+$') +lowerq_re = re.compile('[a-z?]') + +queries = [ + # Limits used to validate other parameters + ("float", "DEVice:INFo:LIMits:MINFrequency?"), + ("float", "DEVice:INFo:LIMits:MAXFrequency?"), + ("float", "DEVice:INFo:LIMits:MINIFBW?"), + ("float", "DEVice:INFo:LIMits:MAXIFBW?"), + ("int", "DEVice:INFo:LIMits:MAXPoints?"), + ("float", "DEVice:INFo:LIMits:MINPOWer?"), + ("float", "DEVice:INFo:LIMits:MAXPOWer?"), + ("float", "DEVice:INFo:LIMits:MINRBW?"), + ("float", "DEVice:INFo:LIMits:MAXRBW?"), + + # Settable parameters without query arguments + ("str", "DEVice:MODE?"), + ("str", "DEVice:REFerence:IN?"), + ("str", "DEVice:REFerence:OUT?"), + ("float", "GENerator:FREQuency?"), + ("float", "GENerator:LVL?"), + ("int", "GENerator:PORT?"), + ("int", "SA:ACQuisition:AVG?"), + ("str", "SA:ACQuisition:DETector?"), + ("float", "SA:ACQuisition:RBW?"), + ("bool", "SA:ACQuisition:RUN?"), + ("bool", "SA:ACQuisition:SINGLE?"), + ("str", "SA:ACQuisition:WINDow?"), + ("float", "SA:FREQuency:CENTer?"), + ("float", "SA:FREQuency:SPAN?"), + ("float", "SA:FREQuency:START?"), + ("float", "SA:FREQuency:STOP?"), + ("bool", "SA:TRACKing:ENable?"), + ("float", "SA:TRACKing:LVL?"), + ("bool", "SA:TRACKing:NORMalize:ENable?"), + ("float", "SA:TRACKing:NORMalize:LVL?"), + ("float", "SA:TRACKing:OFFset?"), + ("int", "SA:TRACKing:Port?"), + ("int", "VNA:ACQuisition:AVG?"), + ("float", "VNA:ACQuisition:IFBW?"), + ("int", "VNA:ACQuisition:POINTS?"), + ("bool", "VNA:ACQuisition:RUN?"), + ("bool", "VNA:ACQuisition:SINGLE?"), + ("str", "VNA:CALibration:ACTivate?"), + ("int", "VNA:DEEMBedding:NUMber?"), + ("float", "VNA:FREQuency:CENTer?"), + ("float", "VNA:FREQuency:SPAN?"), + ("float", "VNA:FREQuency:START?"), + ("float", "VNA:FREQuency:STOP?"), + ("float", "VNA:POWer:START?"), + ("float", "VNA:POWer:STOP?"), + ("float", "VNA:STIMulus:FREQuency?"), + ("float", "VNA:STIMulus:LVL?"), + ("str", "VNA:SWEEP?"), +] + + +class TestRST(TestBase): + def query_settings(self) -> dict: + result = dict() + for qtype, query in queries: + resp = self.vna.query(query) + if qtype == "float": + self.assertTrue(float_re.match(resp), + f"Expected float from {query}; got: '{resp}'") + value = float(resp) + elif qtype == "int": + self.assertTrue(int_re.match(resp), + f"Expected int from {query}; got: '{resp}'") + value = int(resp) + elif qtype == "bool": + self.assertTrue(resp == "TRUE" or resp == "FALSE", + f"Expected bool from {query}; got: '{resp}'") + value = True if resp == "TRUE" else False + elif qtype == "str": + value = resp + else: + assert False, "invalid type in table" + + query = re.sub(lowerq_re, r'', query) + result[query] = value + + return result + + def validate_settings(self, settings): + # Copy limits into local vars + f_min = settings["DEV:INF:LIM:MINF"] + f_max = settings["DEV:INF:LIM:MAXF"] + ifbw_min = settings["DEV:INF:LIM:MINIFBW"] + ifbw_max = settings["DEV:INF:LIM:MAXIFBW"] + points_max = settings["DEV:INF:LIM:MAXP"] + pwr_min = settings["DEV:INF:LIM:MINPOW"] + pwr_max = settings["DEV:INF:LIM:MAXPOW"] + rbw_min = settings["DEV:INF:LIM:MINRBW"] + rbw_max = settings["DEV:INF:LIM:MAXRBW"] + + # Validate select settings + self.assertEqual(settings["DEV:MODE"], "VNA") + self.assertEqual(settings["DEV:REF:IN"], "INT") + self.assertEqual(settings["DEV:REF:OUT"], "OFF") # can't source pwr + + f = settings["GEN:FREQ"] + self.assertGreaterEqual(f, f_min) + self.assertLessEqual(f, f_max) + + pwr = settings["GEN:LVL"] + self.assertGreaterEqual(pwr, pwr_min) + self.assertLessEqual(pwr, pwr_max) + + self.assertEqual(settings["SA:ACQ:AVG"], 1) + + rbw = settings["SA:ACQ:RBW"] + self.assertGreaterEqual(rbw, rbw_min) + self.assertLessEqual(rbw, rbw_max) + + f_center = settings["SA:FREQ:CENT"] + f_span = settings["SA:FREQ:SPAN"] + f_start = settings["SA:FREQ:START"] + f_stop = settings["SA:FREQ:STOP"] + self.assertGreaterEqual(f_start, f_min) + self.assertLessEqual(f_start, f_stop) + self.assertLessEqual(f_stop, f_max) + f_granularity = (f_max - f_min) / points_max + self.assertTrue(abs(f_stop - f_start - f_span) < f_granularity) + self.assertTrue(abs((f_start + f_stop) / 2 - f_center) < f_granularity) + + self.assertFalse(settings["SA:TRACK:EN"]) + pwr = settings["SA:TRACK:LVL"] + self.assertGreaterEqual(pwr, pwr_min) + self.assertLessEqual(pwr, pwr_max) + + pwr = settings["SA:TRACK:NORM:LVL"] + self.assertGreaterEqual(pwr, pwr_min) + self.assertLessEqual(pwr, pwr_max) + + self.assertGreaterEqual(settings["SA:TRACK:P"], 1) + + ifbw = settings["VNA:ACQ:IFBW"] + self.assertGreaterEqual(ifbw, ifbw_min) + self.assertLessEqual(ifbw, ifbw_max) + + points = settings["VNA:ACQ:POINTS"] + self.assertGreaterEqual(points, 1) + self.assertLessEqual(points, points_max) + + # TODO-check: In standard SCPI, the instrument does not source + # power from its ports after *RST. Automation program enables + # the output only after completing its setup. + #self.assertFalse(settings["VNA:ACQ:RUN"]) # can't source pwr + self.assertEqual(settings["VNA:DEEMB:NUM"], 0) + + f_center = settings["VNA:FREQ:CENT"] + f_span = settings["VNA:FREQ:SPAN"] + f_start = settings["VNA:FREQ:START"] + f_stop = settings["VNA:FREQ:STOP"] + self.assertGreaterEqual(f_start, f_min) + self.assertLessEqual(f_start, f_stop) + self.assertLessEqual(f_stop, f_max) + self.assertTrue(abs(f_stop - f_start - f_span) < f_granularity) + self.assertTrue(abs((f_start + f_stop) / 2 - f_center) < f_granularity) + + pwr_start = settings["VNA:POW:START"] + pwr_stop = settings["VNA:POW:STOP"] + self.assertGreaterEqual(pwr_start, pwr_min) + self.assertLess(pwr_start, pwr_stop) + self.assertLessEqual(pwr_stop, pwr_max) + + f = settings["VNA:STIM:FREQ"] + self.assertGreaterEqual(f, f_min) + self.assertLessEqual(f, f_max) + + pwr = settings["VNA:STIM:LVL"] + self.assertGreaterEqual(pwr, pwr_min) + self.assertLessEqual(pwr, pwr_max) + + self.assertEqual(settings["VNA:SWEEP"], "FREQUENCY") + + def test_rst_basic(self): + self.vna.cmd("*RST") + settings = self.query_settings() + self.validate_settings(settings) + + def test_rst_hard(self): + self.vna.cmd("*RST") + settings1 = self.query_settings() + self.validate_settings(settings1) + + # Get limits. + f_min = settings1["DEV:INF:LIM:MINF"] + f_max = settings1["DEV:INF:LIM:MAXF"] + f_1_3 = (2 * f_min + f_max) / 3 + f_1_2 = (f_min + f_max) / 2 + f_2_3 = (f_min + 2 * f_max) / 3 + ifbw_min = settings1["DEV:INF:LIM:MINIFBW"] + ifbw_max = settings1["DEV:INF:LIM:MAXIFBW"] + ifbw_1_2 = (ifbw_min + ifbw_max) / 2 + points_max = settings1["DEV:INF:LIM:MAXP"] + pwr_min = settings1["DEV:INF:LIM:MINPOW"] + pwr_max = settings1["DEV:INF:LIM:MAXPOW"] + pwr_1_3 = (2 * pwr_min + pwr_max) / 3 + pwr_2_3 = (pwr_min + 2 * pwr_max) / 3 + pwr_1_2 = (pwr_min + pwr_max) / 2 + rbw_min = settings1["DEV:INF:LIM:MINRBW"] + rbw_max = settings1["DEV:INF:LIM:MAXRBW"] + rbw_1_2 = (rbw_max + rbw_max) / 2 + + # Change parameters. + self.vna.cmd("DEV:MODE SA") + self.vna.cmd("DEV:REF:IN AUTO") + self.vna.cmd("DEV:REF:OUT 10") + self.vna.cmd(f"GEN:FREQ {f_1_2}") + self.vna.cmd(f"GEN:LVL {pwr_1_2}") + self.vna.cmd("GEN:PORT 2") + self.vna.cmd("SA:ACQ:AVG 3") + self.vna.cmd("SA:ACQ:DET -PEAK") + self.vna.cmd(f"SA:ACQ:RBW {rbw_1_2}") + self.vna.cmd("SA:ACQ:SINGLE TRUE") + self.vna.cmd("SA:ACQ:WIND HANN") + self.vna.cmd(f"SA:FREQ:START {f_1_3} STOP {f_2_3}") + self.vna.cmd("SA:TRACK:EN TRUE") + self.vna.cmd(f"SA:TRACK:LVL {pwr_1_2}") + self.vna.cmd("SA:TRACK:NORM:EN TRUE") + self.vna.cmd("SA:TRACK:NORM:LVL {pwr_1_3}") + self.vna.cmd("SA:TRACK:OFF 1.0e+6;PORT 2") + self.vna.cmd("VNA:ACQ:AVG 10") + self.vna.cmd(f"VNA:ACQ:IFBW {ifbw_1_2}") + self.vna.cmd(f"VNA:ACQ:POINTS 100") + self.vna.cmd("VNA:ACQ:SINGLE TRUE") + self.vna.cmd(f"VNA:FREQ:START {f_1_2};STOP {f_max}") + self.vna.cmd(f"VNA:POW:START {pwr_1_3};STOP {pwr_2_3}") + self.vna.cmd(f"VNA:STIM:FREQ {f_1_3}") + self.vna.cmd(f"VNA:STIM:LVL {pwr_min}") + self.vna.cmd("VNA:SWEEP POWER") + + # Reset and verify all settings revert. + self.vna.cmd("*RST") + settings2 = self.query_settings() + for key, value in settings1.items(): + # TODO-check: *RST does not reset this parameter. + if key == "DEV:REF:OUT": + continue + self.assertEqual(value, settings2[key])