def range(self, val): rng = unit_scale(str(val)) if not rng == round(rng, -int(floor(log10(rng)))): raise ParameterError() if str(rng)[0] != "2": raise ParameterError() if not 2000e-9 <= rng <= 200e6: raise ParameterError() self._range = val self._write("RANG {}".format(unit_convert(rng, 2, 2000)))
def __init__(self, instrument): """ The self._ values indicate the user values as entered if valid. The self.__ values are the sanitised values used internally in the system to parse between functions Limitations: The function generator switches internal relays at certain thresholds. Try to avoid these ranges in design if the function generator is loaded with a relatively low impedance Table of ranges on the same relay arrangement Min mVpp Max mVpp 4 60 60.1 199.9 200 599.9 600 2000 2001 6000 6001 20000 :param instrument: :return: """ super().__init__(instrument) self.instrument.query_delay = 0.2 self.instrument.timeout = 1000 # Rigol Restrictions self.__restr_bandwidth = { "min": unit_scale("4uHz"), "max": unit_scale("20MHz") } self.__restr_phase = {"min": -180, "max": 180} self.__restr_amplitude = { "min": unit_scale("4mVpp"), "max": unit_scale("20Vpp") } self._amplitude = None self._store = {"ch1_duty": "50", "ch2_duty": "50"} self.api = [ # WAVEFORM SELECTION: # Channel 1: ( "channel1.waveform.sin", self.store_and_write, ( "FUNC SIN", # base_str { "ch1_waveform_handler": None })), # handler ("channel1.waveform.square", self.store_and_write, ("FUNC SQU\r\nFUNC:SQU:DCYC {self._store[ch1_duty]}", { "ch1_waveform_handler": "channel1.waveform.square" })), ("channel1.waveform.ramp", self.store_and_write, ("FUNC RAMP", { "ch1_waveform_handler": None })), ("channel1.waveform.pulse", self.store_and_write, ("FUNC PULS\r\nPULS:DCYC {self._store[ch1_duty]}", { "ch1_waveform_handler": "channel1.waveform.pulse" })), ("channel1.waveform.arb", self.store_and_write, ("FUNC USER", { "ch1_waveform_handler": None })), ("channel1.waveform.triangle", self.store_and_write, ("FUNC TRI", { "ch1_waveform_handler": None })), ("channel1.waveform.noise", self.store_and_write, ("FUNC NOIS", { "ch1_waveform_handler": None })), ("channel1.waveform.dc", self.store_and_write, ("FUNC DC", { "ch1_waveform_handler": None })), # Channel 2: ( "channel2.waveform.sin", self.store_and_write, ( "FUNC:CH2 SIN", # base_str { "ch2_waveform_handler": None })), # handler ("channel2.waveform.square", self.store_and_write, ("FUNC:CH2 SQU\r\nFUNC:SQU:DCYC:CH2 {self._store[ch2_duty]}", { "ch2_waveform_handler": "channel2.waveform.square" })), ("channel2.waveform.ramp", self.store_and_write, ("FUNC:CH2 RAMP", { "ch2_waveform_handler": None })), ("channel2.waveform.pulse", self.store_and_write, ("FUNC:CH2 PULS\r\nPULS:DCYC {self._store[ch2_duty]}", { "ch2_waveform_handler": "channel2.waveform.pulse" })), ("channel2.waveform.arb", self.store_and_write, ("FUNC:CH2 USER", { "ch2_waveform_handler": None })), ("channel2.waveform.triangle", self.store_and_write, ("FUNC:CH2 TRI", { "ch2_waveform_handler": None })), ("channel2.waveform.noise", self.store_and_write, ("FUNC:CH2 NOIS", { "ch2_waveform_handler": None })), ("channel2.waveform.dc", self.store_and_write, ("FUNC:CH2 DC", { "ch2_waveform_handler": None })), # CHANNEL CONFIGURATION: # Channel 1: ("channel1.vrms", self.write, "VOLT:UNIT VRMS\r\nVOLT {value}"), ("channel1.vpp", self.write, "VOLT:UNIT VPP\r\nVOLT {value}"), ("channel1.dbm", self.write, "VOLT:UNIT DBM\r\nVOLT {value}"), ("channel1.offset", self.write, "VOLT:OFFS {value}"), ("channel1.phase", self.write, "PHAS {value}"), ("channel1.duty", self.store_and_execute, ({ "ch1_duty": "{value}" }, "ch1_waveform_handler")), ("channel1.frequency", self.write, "FREQ {value}"), # Channel 2: ("channel2.vrms", self.write, "VOLT:UNIT:CH2 VRMS\r\nVOLT {value}" ), ("channel2.vpp", self.write, "VOLT:UNIT:CH2 VPP\r\nVOLT {value}"), ("channel2.dbm", self.write, "VOLT:UNIT:CH2 DBM\r\nVOLT {value}"), ("channel2.offset", self.write, "VOLT:OFFS:CH2 {value}"), ("channel2.phase", self.write, "PHAS:CH2 {value}"), ("channel2.duty", self.store, { "ch2_duty": "{value}" }), ("channel2.frequency", self.write, "FREQ:CH2 {value}"), # CHANNEL ACTIVATION: ("channel1._call", self.write, "OUTP {value}" ), # True won't work here needs to be ON or 1, OFF or 0 ("channel2._call", self.write, "OUTP:CH2 {value}" ), # True won't work here needs to be ON or 1, OFF or 0 # SYNC CONFIGURATION: ("sync.polarity.normal", self.write, ""), ("sync.mode.normal", self.write, ""), ("sync.mode.source", self.write, ""), ("sync._call", self.write, "OUTP {value}"), # TRIGGER CONFIGURATION: ("trigger.immediate", self.write, "TRIG:SOUR IMM"), ("trigger.external._call", self.write, "TRIG:SOUR EXT"), ("trigger.external.rising", self.write, "TRIG:SOUR EXT\r\n TRIG1:SLOP POS"), ("trigger.external.falling", self.write, "TRIG:SOUR EXT\r\n TRIG1:SLOP NEG"), ("trigger.manual", self.write, "TRIG:SOUR BUS"), ("trigger.delay", self.write, "TRIG:DEL {seconds}"), ("trigger.out.off", self.write, "OUTP:TRIG OFF"), ("trigger.out._call", self.write, "OUTP:TRIG {output}"), ("trigger.out.rising", self.write, "OUTP:TRIG:SLOP POS"), ("trigger.out.falling", self.write, "OUTP:TRIG:SLOP NEG"), # Modulate # Channel 1: ("channel1.modulate.am._call", self.store, { "ch1_modulate_state": "AM", "ch1_modulate_setting": "FREQ" }), ("channel1.modulate.fm._call", self.store, { "ch1_modulate_state": "FM", "ch1_modulate_setting": "FREQ" }), ("channel1.modulate.pm._call", self.store, { "ch1_modulate_state": "PM", "ch1_modulate_setting": "FREQ" }), ("channel1.modulate.fsk._call", self.store, { "ch1_modulate_state": "FSK", "ch1_modulate_setting": "RATE" }), ("channel1.modulate.bpsk._call", self.store, { "ch1_modulate_state": "BPSK", "ch1_modulate_setting": "RATE" }), ("channel1.modulate.sum._call", self.store, { "ch1_modulate_state": "SUM", "ch1_modulate_setting": "RATE" }), # MODULATE SOURCES: ("channel1.modulate.source.internal._call", self.store_and_write, ("{self._store[ch1_modulate_state]}:SOUR INT", { "ch1_modulate_source": "INT" })), ("channel1.modulate.source.external", self.store_and_write, ("{self._store[ch1_modulate_state]}:SOUR EXT", { "ch1_modulate_source": "EXT" })), # MODULATE ACTIVATION: # Channel 1: ("channel1.modulate._call", self.write, "{self._store[ch1_modulate_state]}:STAT {value}\r\n{self._store[ch1_modulate_state]}:SOUR" "{self._store[ch1_modulate_source]}"), # MODULATE OPTIONS: # Channel 1: ("channel1.modulate.am.depth", self.write, "AM:DEPT {value}"), ("channel1.modulate.fm.freq_dev", self.write, "FM:DEV {value}"), ("channel1.modulate.pm.phase_dev", self.write, "PM:DEV{value}"), ("channel1.modulate.fsk.hop_freq", self.write, "FSK:FREQ {value}"), ("channel1.modulate.fsk.rate", self.write, "FSK:INT:RATE {value}"), # MODULATE SHAPES: # Channel 1: ("channel1.modulate.source.internal.shape.sin", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC SIN"), ("channel1.modulate.source.internal.shape.square", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC SQU"), ("channel1.modulate.source.internal.shape.triangle", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC TRI"), ("channel1.modulate.source.internal.shape.up_ramp", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC RAMP"), ("channel1.modulate.source.internal.shape.down_ramp", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC NRAMP"), ("channel1.modulate.source.internal.shape.noise", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC NOIS"), # BURST # Channel 1: ("channel1.burst.gated._call", self.write, "BURS:MODE GAT"), ("channel1.burst._call", self.write, "BURS:STAT {value}"), ("channel1.burst.ncycle._call", self.write, "BURS:MODE TRIG"), ("channel1.burst.ncycle.cycles._call", self.write, "BURS:NCYC {cycles}"), ("channel1.burst.ncycle.cycles.infinite", self.write, "BURS:NCYC INF"), ("channel1.burst.ncycle.burst_period", self.write, "BURS:INT:PER {seconds}"), ("channel1.burst.gated.positive", self.write, "BURS:GATE:POL NORM"), ("channel1.burst.gated.negative", self.write, "BURS:GATE:POL INV"), ("channel1.burst.phase", self.write, "BURS:PHAS {degrees}"), # Modulate Frequency ("channel1.modulate.source.internal.frequency", self.write, "{self._store[ch1_modulate_state]}:INT:{self._store[ch1_modulate_setting]} {value}" ), # LOAD: # channel1: ("channel1.load._call", self.write, "OUTP:LOAD {ohms}"), ("channel1.load.infinite", self.write, "OUTP:LOAD INF"), # channel2: ("channel2.load._call", self.write, "OUTP:LOAD:CH2 {ohms}"), ("channel2.load.infinite", self.write, "OUTP:LOAD:CH2 INF"), ] # ----------------------------------------------------------------------------------------------------------------------- self.init_api()
def __init__(self, instrument): """ The self._ values indicate the user values as entered if valid. The self.__ values are the sanitised values used internally in the system to parse between functions Limitations: The function generator switches internal relays at certain thresholds. Try to avoid these ranges in design if the function generator is loaded with a relatively low impedance Table of ranges on the same relay arrangement Min mVpp Max mVpp 4 60 60.1 199.9 200 599.9 600 2000 2001 6000 6001 20000 :param instrument: :return: """ super().__init__(instrument) self.instrument.query_delay = 0.2 self.instrument.timeout = 1000 # Rigol Restrictions self.__restr_bandwidth = { "min": unit_scale("4uHz"), "max": unit_scale("20MHz") } self.__restr_phase = {"min": -180, "max": 180} self.__restr_amplitude = { "min": unit_scale("4mVpp"), "max": unit_scale("20Vpp"), } self._amplitude = None self._store = { "ch1_duty": "50", "ch2_duty": "50", "ch1_modulate_source": "INT" } self.api = [ # waveform selection # Channel 1: ( "channel1.waveform.sin", self.store_and_write, ("SOUR1:FUNC SIN", { "ch1_waveform_handler": None }), ), ( "channel1.waveform.square", self.store_and_write, ( "SOUR1:FUNC SQU\r\nSOUR1:FUNC:SQU:DCYC {self._store[ch1_duty]}", { "ch1_waveform_handler": "channel1.waveform.square" }, ), ), ( "channel1.waveform.ramp", self.store_and_write, ("SOUR1:FUNC RAMP", { "ch1_waveform_handler": None }), ), ( "channel1.waveform.pulse", self.store_and_write, ( "SOUR1:FUNC PULS\r\nPULS:DCYC {self._store[ch1_duty]}", { "ch1_waveform_handler": "channel1.waveform.pulse" }, ), ), ( "channel1.waveform.arb", self.store_and_write, ("SOUR1:FUNC ARB", { "ch1_waveform_handler": None }), ), ( "channel1.waveform.triangle", self.store_and_write, ("SOUR1:FUNC TRI", { "ch1_waveform_handler": None }), ), ( "channel1.waveform.noise", self.store_and_write, ("SOUR1:FUNC NOIS", { "ch1_waveform_handler": None }), ), ( "channel1.waveform.dc", self.store_and_write, ("SOUR1:FUNC DC", { "ch1_waveform_handler": None }), ), ( "channel1.waveform.prbs", self.store_and_write, ("SOUR1:FUNC PRBS", { "ch1_waveform_handler": None }), ), # Channel Configuration # Channel 1: ("channel1.vrms", self.write, "SOUR1:VOLT:UNIT VRMS\r\nVOLT {value}"), ("channel1.vpp", self.write, "SOUR1:VOLT:UNIT VPP\r\nVOLT {value}"), ("channel1.dbm", self.write, "SOUR1:VOLT:UNIT DBM\r\nVOLT {value}"), ("channel1.offset", self.write, "SOUR1:VOLT:OFFS {value}"), ("channel1.phase", self.write, "SOUR1:PHAS {value}"), ( "channel1.duty", self.store_and_execute, ({ "ch1_duty": "{value}" }, "ch1_waveform_handler"), ), ("channel1.frequency", self.write, "SOUR1:FREQ {value}"), # Channel Activation ("channel1._call", self.write, "OUTP {value}"), # Sync Configuration ("sync.polarity.normal", self.write, ""), ("sync.mode.normal", self.write, ""), # Sync Mode source only works on one. Need to manually override so that only channel 1 being passed works ("sync.mode.source", self.write, ""), ("sync._call", self.write, "OUTP {value}"), # Trigger Configuration ("trigger.immediate", self.write, "TRIG1:SOUR IMM"), ("trigger.external._call", self.write, "TRIG1:SOUR EXT"), ( "trigger.external.rising", self.write, "TRIG1:SOUR EXT\r\n TRIG1:SLOP POS", ), ( "trigger.external.falling", self.write, "TRIG1:SOUR EXT\r\n TRIG1:SLOP NEG", ), ("trigger.manual._call", self.write, "TRIG1:SOUR BUS"), ("trigger.manual.initiate", self.write, "TRIG1:SOUR BUS"), ("trigger.timer", self.write, "TRIG:SOUR TIM\r\n TRIG1:TIM {seconds}"), ("trigger.delay", self.write, "TRIG1:DEL {seconds}"), ("trigger.out._call", self.write, "OUTP:TRIG"), ("trigger.out.off", self.write, "OUTP:TRIG OFF"), ("trigger.out.rising", self.write, "OUTP:TRIG ON\r\n OUTP:TRIG:SLOP POS"), ("trigger.out.falling", self.write, "OUTP:TRIG ON\r\n OUTP:TRIG:SLOP NEG"), # Modulate # Channel 1: ( "channel1.modulate.am._call", self.store, { "ch1_modulate_state": "AM", "ch1_modulate_setting": "FREQ" }, ), ( "channel1.modulate.fm._call", self.store, { "ch1_modulate_state": "FM", "ch1_modulate_setting": "FREQ" }, ), ( "channel1.modulate.pm._call", self.store, { "ch1_modulate_state": "PM", "ch1_modulate_setting": "FREQ" }, ), ( "channel1.modulate.fsk._call", self.store, { "ch1_modulate_state": "FSK", "ch1_modulate_setting": "RATE" }, ), ( "channel1.modulate.bpsk._call", self.store, { "ch1_modulate_state": "BPSK", "ch1_modulate_setting": "RATE" }, ), ( "channel1.modulate.sum._call", self.store, { "ch1_modulate_state": "SUM", "ch1_modulate_setting": "FREQ" }, ), # MODULATE SOURCES: ( "channel1.modulate.source.internal._call", self.write, "SOUR1:{self._store[ch1_modulate_state]}:" "SOUR INT", ), ( "channel1.modulate.source.external", self.write, "SOUR1:{self._store[ch1_modulate_state]}:SOUR EXT", ), # MODULATE ACTIVATION: # Channel 1: ( "channel1.modulate._call", self.write, "{self._store[ch1_modulate_state]}:SOUR {self._store[ch1_modulate_source]}\r\n" "{self._store[ch1_modulate_state]}:STAT {value}", ), # MODULATE OPTIONS: # Channel 1: ("channel1.modulate.am.depth", self.write, "SOUR1:AM:DEPT {value}" ), ("channel1.modulate.am.dssc", self.write, "SOUR1:AM:DSSC ON"), ("channel1.modulate.fm.freq_dev", self.write, "SOUR1:FM:DEV {value}"), ("channel1.modulate.pm.phase_dev", self.write, "SOUR1:PM:DEV {value}"), ("channel1.modulate.fsk.hop_freq", self.write, "SOUR1:FSK:FREQ {value}"), ("channel1.modulate.fsk.rate", self.write, "SOUR1:FSK:INT:RATE {value}"), ( "channel1.modulate.sum.modulate_percent", self.write, "SOUR1:SUM:AMPL {percent}", ), # Internal ( "channel1.modulate.source.internal.shape.sin", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC SIN", ), ( "channel1.modulate.source.internal.shape.square", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC SQU", ), ( "channel1.modulate.source.internal.shape.triangle", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC TRI", ), ( "channel1.modulate.source.internal.shape.up_ramp", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC RAMP", ), ( "channel1.modulate.source.internal.shape.down_ramp", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC NRAMP", ), ( "channel1.modulate.source.internal.shape.noise", self.write, "{self._store[ch1_modulate_state]}:INT:FUNC NOIS", ), # Modulate Frequency ( "channel1.modulate.source.internal.frequency", self.write, "SOUR1:{self._store[ch1_modulate_state]}:INT:{self._store[ch1_modulate_setting]} {value}", ), # LOAD: # channel1: ("channel1.load._call", self.write, "OUTP1:LOAD {ohms}"), ("channel1.load.infinite", self.write, "OUTP1:LOAD INF"), # BURST # Channel 1: ("channel1.burst.gated._call", self.write, "SOUR1:BURS:MODE GAT"), ("channel1.burst._call", self.write, "SOUR1:BURS:STAT {value}"), ("channel1.burst.ncycle._call", self.write, "SOUR1:BURS:MODE TRIG"), ( "channel1.burst.ncycle.cycles._call", self.write, "SOUR1:BURS:NCYC {cycles}", ), ( "channel1.burst.ncycle.cycles.infinite", self.write, "SOUR1:BURS:NCYC INF", ), ( "channel1.burst.ncycle.burst_period", self.write, "SOUR1:BURS:INT:PER {seconds}", ), ("channel1.burst.gated.positive", self.write, "SOUR1:BURS:GATE:POL NORM"), ("channel1.burst.gated.negative", self.write, "SOUR1:BURS:GATE:POL INV"), ("channel1.burst.phase", self.write, "SOUR1:BURS:PHAS {degrees}"), ] # ---------------------------------------------------------------------------------------------------------------------- self.init_api()
def test_none(self): self.assertEqual(unit_scale(None), None)
def test_mega_scale(self): self.assertAlmostEqual(unit_scale("10MV", ["V"]), 10e6)
def test_invalid_string(self): with self.assertRaises(InvalidScalarQuantityError): self.assertEqual(unit_scale("blah 4 uAsd", ["V"]), 10e0)
def test_milli_scale(self): self.assertAlmostEqual(unit_scale("10mV", ["V"]), 10e-3)
def test_number_invalid_unit(self): with self.assertRaises(InvalidScalarQuantityError): self.assertEqual(unit_scale("10kHz", ["V"]), 10e3)
def test_number_in_unit_set(self): self.assertEqual(unit_scale("10kHz", ["V", "Hz"]), 10e3)
def test_no_scale_no_units(self): self.assertEqual(unit_scale("10", ["V"]), 10e0)
def test_number_invalid_suffix(self): with self.assertRaises(InvalidScalarQuantityError): self.assertEqual(unit_scale("10 abcd", ["V"]), 10e0)
def test_giga_scale_no_units(self): self.assertAlmostEqual(unit_scale("10G", ["V"]), 10e9)
def test_nano_scale_no_units(self): self.assertAlmostEqual(unit_scale("10n", ["V"]), 10e-9)
def test_micro_scale_no_units(self): self.assertAlmostEqual(unit_scale("10u", ["V"]), 10e-6)
def test_kilo_scale_no_units(self): self.assertAlmostEqual(unit_scale("10k", ["V"]), 10e3)
def test_no_scale(self): self.assertEqual(unit_scale("10V", ["V"]), 10)