Source code for pylab_ml.scope.natinst.pxie51xx

import os
from pylab_ml.collate_instrument import Interface
from pylab_ml.base_instrument import InvalidInstrumentConnection
from pylab_ml.baseclass.base_natinst import NatInst
from pylab_ml.base_instrument import logger
from matplotlib import pyplot as plt
import unittest
import hightime


[docs] class PXIe51xx(NatInst): """Interface to the Oscilloscopes NI PXIe-51xx (e.q. 5122) until now only initialisation on poor basic functions for more function see: https://nimi-python.readthedocs.io/en/master/niscope.html call with: scope.inst.thefunctionname Initialization arguments: addr name from the PXI-Slot e.q. PXI1Slot4 instName instance Name from top Example: Initialization >>> scope = PXIe4138('PXI1Slot4',instName='scope') # connect and initialize instrument >>> scope.trig_channel = 1 >>> scope.trig_level = 1.5 >>> scope.trig_slope = "POS" >>> scope.trig_mode = "norm" >>> scope.tdiv = 1e-3 >>> scope.tdelay = -3e-3 >>> scope.channel = 1 >>> scope.trace = True >>> scope.vdiv = 1.0 >>> scope.offs = 0 Methods: reset() reset identify() instrument message, reflect address & interfade message("") instrument message ("string") or () close() terminate interface missing: get_waveform(n) get waveform data from channel n missing: trig_oneshot(t) single measurement trigger to waveform or timeout after t s Properties: missing: memsize missing: tdiv missing: tdelay missing: trig_mode missing: trig_channel missing: channel missing: trace missing: vdiv missing: offs missing: waveform for more properties or functios see: https://nimi-python.readthedocs.io/en/master/niscope.html scope.inst.functionname """ try: import niscope has_scope = True except ImportError: has_scope = False if os.sys.platform != "win32": logger.error("import niscope not found") else: logger.info("no import niscope can be found on non Windows platforms") # Create functions or property and wrap it to the inst.funcname: # If state != necessary state -> switch to the necessary state # Property/Function name -> (inst.funcname (get,set), Range, Call_Functions) # inst.funcname (get,set): Available in 'https://nimi-python.readthedocs.io/en/master/niscope.html' # Range: None, Enum or Range value # Call_Functions: see help in attributes _properties = { # 'aperture_time_units': ('aperture_time_units', 'backend.ApertureTimeUnits', {'sac': 'checkstate(uncommitted)'}), "probeAttenuation": ("probe_attenuation", [1, 100], None), "couplings": ("vertical_coupling", "backend.VerticalCoupling", None), "onoff": ("channel_enabled", {"on": True, "off": False, 1: True, 0: False, True: True, False: False}, None), "sampleRate": ("min_sample_rate", [2_000, 2_000_000_000], None), "numberOfRecords": ("horz_num_records", [1, 1_000_000_000], None), "numberOfPoints": ("horz_min_num_pts", [1, 1_000_000_000], None), "numberOfSamples": ("horz_sample_rate", None, None), "referencePosition": ("horz_record_ref_position", [0, 100], None), "enforceRealtime": ("horz_enforce_realtime", {"on": True, "off": False}, None), "triggerType": ("trigger_type", "backend.TriggerType", None), "triggerModifier": ("trigger_modifier", "backend.TriggerModifier", None), "triggerSource": ("trigger_source", {0: "0", 1: "1", "TRIG": "TRIG"}, None), "triggerHysteresis": ("trigger_hysteresis", [0, 100], None), "triggerLevel": ("trigger_level", [-100, 100], None), "triggerDelay": ("trigger_delay_time", [0.0, 171.8], None), "triggerHoldoff": ("trigger_holdoff", [0.0, 171.8], None), "triggerSlope": ("trigger_slope", "backend.TriggerSlope", None), "triggerCoupling": ("trigger_coupling", "backend.TriggerCoupling", None), "terminals": ("channel_terminal_configuration", "backend.TerminalConfiguration", None), "impedance": ("trigger_impedance", [50, 1000000], None), "bandwidth": ("max_input_frequency", {"Full": -1.0, "Default": 0.0, "20MHz": 20_000_000.0, "125MHz": 125_000_000.0}, None), "range": ("vertical_range", {0.04: 0.04, 0.1: 0.1, 0.2: 0.2, 0.4: 0.4, 1.0: 1.0, 2.0: 2.0, 4.0: 4.0, 10.0: 10.0, 20.0: 20.0, 40.0: 40.0}, None), "offset": ("vertical_offset", [-30, 30], None), } interchoices = [Interface.pxie]
[docs] def __init__(self, addr=None, identify=False, instName=None): if not self.has_scope: msg = "\nPXIe50xx not usable!! missing nidscope\n" msg = msg + "for installing niscope:\n" msg = msg + " Start anaconda prompt and write: python –m pip install niscope\n" msg = msg + "For more infomation see: http://nimi-python.readthedocs.io\n" raise InvalidInstrumentConnection(msg) kwargs = {"addr": addr, "backend": self.niscope, "identify": identify, "instName": instName} super().__init__(**kwargs) logger.debug("Class {}".format(self.__class__.__name__)) self.msg_row_col = (1, 20) self.setup_inst() inputTimeOut = 10
# minTimeOut = (self.numberOfSamples * (self.numberOfRecords + 1)) / self.sampleRate # self.timeout = max(inputTimeOut, minTimeOut)
[docs] def setup_inst(self): """Setup instrument settings""" super().setup_inst() self.mqtt_all = [""] channels = [] if self.channels is None: self.channels = "0,1" temp = self.channels.split(",") for ch in temp: channels.append(int(ch)) self.channels = channels self._create_channelinst(channels) self.channel = channels[0]
[docs] def measure(self, channel=[0, 1], num_of_record=1, start_record=0, num_of_samples=None, offset=0): """Start to fetch data from the Scope. Parameters ---------- channel : TYPE, (list or int) DESCRIPTION. The default is [0, 1] to measure from both the channels. Can also give '0' or '1' to measure from separate channel. num_of_record : TYPE, int DESCRIPTION. The default is 1. Number of records to fetch. Use -1 to fetch all configured records. start_record : TYPE, int DESCRIPTION. The default is 0. Zero-based index of the first record to fetch. num_of_samples : TYPE, int DESCRIPTION. The default is None. The maximum number of samples to fetch for each waveform. If the acquisition finishes with fewer points than requested, some devices return partial data if the acquisition finished, was aborted. If it fails to complete within the timeout period, the method raises. offset : TYPE, int DESCRIPTION. The default is 0. Offset in samples to start fetching data within each record. The offset can be positive or negative. Returns ------- x : list Contains list of Time values. y : list Contains list of Voltage values. """ if isinstance(channel, list): channel_map = map(str, channel) temp = "-".join(list(channel_map)) else: temp = str(channel) waveforms = self.inst.channels[temp].fetch( num_samples=num_of_samples, record_number=start_record, offset=offset, num_records=num_of_record, timeout=hightime.timedelta(seconds=20) ) if isinstance(channel, int): x = [] for i in range(0, len(waveforms[0].samples)): temp = i * waveforms[0].x_increment x.append(temp) y = waveforms[0].samples.tolist() elif len(channel) == 2: x1 = [] x2 = [] x = [] y = [] for i in range(0, len(waveforms[0].samples)): temp1 = i * waveforms[0].x_increment x1.append(temp1) y1 = waveforms[0].samples.tolist() for i in range(0, len(waveforms[1].samples)): temp2 = i * waveforms[1].x_increment x2.append(temp2) y2 = waveforms[1].samples.tolist() x.extend([x1, x2]) y.extend([y1, y2]) return x, y
[docs] def plot_scope_data(self, time, voltage): """Plot graph between Time and Voltage. Parameters ---------- time : list Input a list of Time values for x-axis. voltage : list Input a list of Voltage values for y-axis. Returns ------- None. """ if any(isinstance(i, list) for i in voltage): plt.figure(figsize=(6.4, 4.8), dpi=300) plt.plot(time[0], voltage[0], "bo", markersize=0.1, alpha=0.1, label="Channel 0") plt.plot(time[1], voltage[1], "ro", markersize=0.1, alpha=0.1, label="Channel 1") plt.title("Scope Measurements") plt.xlabel("Time (s)") plt.ylabel("Voltage (V)") plt.legend() plt.grid(linestyle="--") plt.show() else: plt.figure(figsize=(6.4, 4.8), dpi=300) plt.plot(time, voltage, "bo", markersize=0.1, alpha=0.1) plt.title("Scope Measurements") plt.xlabel("Time (s)") plt.ylabel("Voltage (V)") plt.grid(linestyle="--") plt.show()
[docs] def reset(self): super().reset()
[docs] class PXIe5114(PXIe51xx): _properties = { "sampleRate": ("min_sample_rate", [200_000_000, 200_000_000], None), "bandwidth": ("max_input_frequency", {"Full": -1.0, "Default": 0.0, "20MHz": 20_000_000.0, "125MHz": 125_000_000.0}, None), "range": ("vertical_range", {0.04: 0.04, 0.1: 0.1, 0.2: 0.2, 0.4: 0.4, 1.0: 1.0, 2.0: 2.0, 4.0: 4.0, 10.0: 10.0, 20.0: 20.0, 40.0: 40.0}, None), "offset": ("vertical_offset", [-30, 30], None), # Max Offset values for Range values : {0.04: 0.8, 0.1: 0.8, 0.2: 0.8, 0.4: 0.8, 1.0: 8.0, 2.0: 8.0, 4.0: 8.0, 10.0: 30.0, 20.0: 25.0, 40.0: 15.0} "probeAttenuation": ("probe_attenuation", [1, 100], None), "couplings": ("vertical_coupling", "backend.VerticalCoupling", None), "output": ("channel_enabled", {"on": True, "off": False}, None), "numberOfRecords": ("horz_num_records", [1, 100_000], None), "numberOfPoints": ("horz_min_num_pts", [1, 100_000], None), "numberOfSamples": ("horz_sample_rate", None, None), "referencePosition": ("horz_record_ref_position", [0, 100], None), "enforceRealtime": ("horz_enforce_realtime", {"on": True, "off": False}, None), "triggerType": ("trigger_type", "backend.TriggerType", None), "triggerSource": ("trigger_source", {"CH1": "0", "CH2": "1", "CH3": "2", "CH4": "3"}, None), "triggerHysteresis": ("trigger_hysteresis", [0, 100], None), "triggerLevel": ("trigger_level", [-100, 100], None), "triggerDelay": ("trigger_delay_time", [0.0, 171.8], None), "triggerHoldoff": ("trigger_holdoff", [0.0, 171.8], None), "triggerSlope": ("trigger_slope", "backend.TriggerSlope", None), "triggerCoupling": ("trigger_coupling", "backend.TriggerCoupling", None), "terminals": ("channel_terminal_configuration", "backend.TerminalConfiguration", None), "impedance": ("trigger_impedance", [50, 1000000], None), }
[docs] def __init__(self, addr=None, identify=False, instName=None): if not self.has_scope: msg = "\nPXIe51xx not usable!! missing nidscope\n" msg = msg + "for installing niscope:\n" msg = msg + " Start anaconda prompt and write: python –m pip install niscope\n" msg = msg + "For more infomation see: http://nimi-python.readthedocs.io\n" raise InvalidInstrumentConnection(msg) super().__init__(addr=addr, identify=identify, instName=instName) logger.debug("Class {}".format(self.__class__.__name__)) self.msg_row_col = (1, 20) self.sampleRate = 200_000_000 self.bandwidth = "125MHz"
[docs] class PXIe5122(PXIe51xx): _properties = { "sampleRate": ("min_sample_rate", [100_000_000, 100_000_000], None), "bandwidth": ("max_input_frequency", {"Full": -1.0, "Default": 0.0, "20MHz": 20_000_000.0, "100MHz": 100_000_000.0}, None), "range": ("vertical_range", {0.2: 0.2, 0.4: 0.4, 1.0: 1.0, 2.0: 2.0, 4.0: 4.0, 10.0: 10.0, 20.0: 20.0}, None), "offset": ("vertical_offset", [-5, 5], None), # Max Offset values for Range values : {0.2: 0.1, 0.4: 0.2, 1.0: 0.5, 2.0: 1.0, 4.0: 2.0, 10.0: 5.0, 20.0: 0} "probeAttenuation": ("probe_attenuation", [1, 100], None), "couplings": ("vertical_coupling", "backend.VerticalCoupling", None), "output": ("channel_enabled", {"on": True, "off": False}, None), "numberOfRecords": ("horz_num_records", [1, 100_000], None), "numberOfPoints": ("horz_min_num_pts", [1, 100_000], None), "numberOfSamples": ("horz_sample_rate", None, None), "referencePosition": ("horz_record_ref_position", [0, 100], None), "enforceRealtime": ("horz_enforce_realtime", {"on": True, "off": False}, None), "triggerType": ("trigger_type", "backend.TriggerType", None), "triggerSource": ("trigger_source", {"CH1": "0", "CH2": "1", "CH3": "2", "CH4": "3"}, None), "triggerHysteresis": ("trigger_hysteresis", [0, 100], None), "triggerLevel": ("trigger_level", [-100, 100], None), "triggerDelay": ("trigger_delay_time", [0.0, 171.8], None), "triggerHoldoff": ("trigger_holdoff", [0.0, 171.8], None), "triggerSlope": ("trigger_slope", "backend.TriggerSlope", None), "triggerCoupling": ("trigger_coupling", "backend.TriggerCoupling", None), "terminals": ("channel_terminal_configuration", "backend.TerminalConfiguration", None), "impedance": ("trigger_impedance", [50, 1000000], None), }
[docs] def __init__(self, addr=None, identify=False, instName=None): if not self.has_scope: msg = "\nPXIe51xx not usable!! missing nidscope\n" msg = msg + "for installing niscope:\n" msg = msg + " Start anaconda prompt and write: python –m pip install niscope\n" msg = msg + "For more infomation see: http://nimi-python.readthedocs.io\n" raise InvalidInstrumentConnection(msg) super().__init__(addr=addr, identify=identify, instName=instName) logger.debug("Class {}".format(self.__class__.__name__)) self.msg_row_col = (1, 20) self.sampleRate = 100_000_000 self.bandwidth = "20MHz"
[docs] class PXIe5172(PXIe51xx): _properties = { "sampleRate": ("min_sample_rate", [250_000_000, 250_000_000], None), "bandwidth": ("max_input_frequency", {"Full": -1.0, "Default": 0.0, "20MHz": 20_000_000.0, "100MHz": 100_000_000.0}, None), "range": ("vertical_range", {0.2: 0.2, 0.4: 0.4, 1.0: 1.0, 2.0: 2.0, 4.0: 4.0, 10.0: 10.0, 20.0: 20.0, 40.0: 40.0}, None), "offset": ("vertical_offset", [-20, 20], None), # Max Offset values for Range values : {0.2: 0.5, 0.4: 0.5, 1.0: 0.5, 4.0: 4.5, 10.0: 4.5, 40.0: 20.0} "probeAttenuation": ("probe_attenuation", [1, 100], None), "couplings": ("vertical_coupling", "backend.VerticalCoupling", None), "output": ("channel_enabled", {"on": True, "off": False}, None), "numberOfRecords": ("horz_num_records", [1, 100_000], None), "numberOfPoints": ("horz_min_num_pts", [1, 100_000], None), "numberOfSamples": ("horz_sample_rate", None, None), "referencePosition": ("horz_record_ref_position", [0, 100], None), "enforceRealtime": ("horz_enforce_realtime", {"on": True, "off": False}, None), "triggerType": ("trigger_type", "backend.TriggerType", None), "triggerSource": ("trigger_source", {"CH1": "0", "CH2": "1", "CH3": "2", "CH4": "3"}, None), "triggerHysteresis": ("trigger_hysteresis", [0, 100], None), "triggerLevel": ("trigger_level", [-100, 100], None), "triggerDelay": ("trigger_delay_time", [0.0, 171.8], None), "triggerHoldoff": ("trigger_holdoff", [0.0, 171.8], None), "triggerSlope": ("trigger_slope", "backend.TriggerSlope", None), "triggerCoupling": ("trigger_coupling", "backend.TriggerCoupling", None), "terminals": ("channel_terminal_configuration", "backend.TerminalConfiguration", None), "impedance": ("trigger_impedance", [50, 1000000], None), }
[docs] def __init__(self, addr=None, identify=False, instName=None): if not self.has_scope: msg = "\nPXIe51xx not usable!! missing nidscope\n" msg = msg + "for installing niscope:\n" msg = msg + " Start anaconda prompt and write: python –m pip install niscope\n" msg = msg + "For more infomation see: http://nimi-python.readthedocs.io\n" raise InvalidInstrumentConnection(msg) super().__init__(addr=addr, identify=identify, instName=instName) logger.debug("Class {}".format(self.__class__.__name__)) self.msg_row_col = (1, 20) self.sampleRate = 250_000_000 self.bandwidth = "20MHz"
[docs] class TestClass(unittest.TestCase): def test_probeAttenuation(self): scope.probeAttenuation = 10.0 self.assertEqual(scope.probeAttenuation, 10.0) scope.probeAttenuation = 101.0 self.assertNotEqual(scope.probeAttenuation, 101.0) def test_couplings(self): scope.couplings = "DC" self.assertEqual(scope.couplings, scope.niscope.VerticalCoupling.DC) def test_onoff(self): scope.onoff = "on" self.assertTrue(scope.inst.channel_enabled) scope[2].onoff = False self.assertFalse(scope.inst.channels[1].channel_enabled) def test_sampleRate(self): scope.sampleRate = 1_000_000 self.assertEqual(scope.sampleRate, 1000000) def test_numberOfRecords(self): scope.numberOfRecords = 10 self.assertEqual(scope.numberOfRecords, 10) scope.numberOfRecords = 100000 self.assertEqual(scope.numberOfRecords, 100000) def test_numberOfPoints(self): scope.numberOfPoints = 100_000 self.assertEqual(scope.numberOfPoints, 100000) scope.numberOfPoints = 100_000_000 self.assertNotEqual(scope.numberOfPoints, 100000000) def test_referencePosition(self): scope.referencePosition = 10 self.assertEqual(scope.referencePosition, 10) scope.referencePosition = 101 self.assertNotEqual(scope.referencePosition, 101) def test_enforceRealtime(self): scope.enforceRealtime = "off" self.assertFalse(scope.inst.horz_enforce_realtime) def test_triggerType(self): scope.triggerType = "DIGITAL" self.assertEqual(scope.triggerType, scope.niscope.TriggerType.DIGITAL) def test_triggerSource(self): scope.triggerSource = "CH3" self.assertEqual(scope.triggerSource, str("CH3")) def test_triggerHysteresis(self): scope.triggerHysteresis = 10 self.assertEqual(scope.triggerHysteresis, 10) scope.triggerHysteresis = 101 self.assertNotEqual(scope.triggerHysteresis, 101) def test_triggerLevel(self): scope.triggerLevel = 10 self.assertEqual(scope.triggerLevel, 10) scope.triggerLevel = 101 self.assertNotEqual(scope.triggerLevel, 101) def test_triggerDelay(self): scope.triggerDelay = 50 self.assertEqual(scope.triggerDelay, 50) scope.triggerDelay = 172 self.assertNotEqual(scope.triggerDelay, 172) def test_triggerHoldoff(self): scope.triggerHoldoff = 75 self.assertEqual(scope.triggerHoldoff, 75) scope.triggerHoldoff = 172 self.assertNotEqual(scope.triggerHoldoff, 172) def test_triggerSlope(self): scope.triggerSlope = "FALLING" self.assertEqual(scope.triggerSlope, scope.niscope.TriggerSlope.FALLING) def test_triggerCoupling(self): scope.triggerCoupling = "HF_REJECT" self.assertEqual(scope.triggerCoupling, scope.niscope.TriggerCoupling.HF_REJECT) def test_terminals(self): scope.terminals = "SINGLE_ENDED" self.assertEqual(scope.terminals, scope.niscope.TerminalConfiguration.SINGLE_ENDED) def test_bandwidth(self): scope.bandwidth = "20MHz" self.assertEqual(scope.bandwidth, str("20MHz")) def test_range(self): scope.range = 20 self.assertEqual(scope.range, 20) scope.range = 25 self.assertNotEqual(scope.range, 25) scope.range = 50 self.assertNotEqual(scope.range, 50) def test_offset(self): scope.offset = 15 self.assertEqual(scope.offset, 15) scope.offset = 50 self.assertNotEqual(scope.offset, 50)
if __name__ == "__main__": from pylab_ml.base_instrument import logsetup # import scope logsetup() scope = PXIe51xx("PXI1Slot4", instName="scope") scope.abort() # scope_5114 = PXIe5114('PXI1Slot4', instName='scope_5114') # scope_5122 = PXIe5122('PXI1Slot4', instName='scope_5122') # scope_5172 = PXIe5172('PXI1Slot4', instName='scope_5172') scope.onoff = "on" scope[1].range = 4.0 scope[2].range = 20.0 # scope.triggerSource = 0 scope.bandwidth = "125MHz" scope.triggerType = "IMMEDIATE" scope.triggerSlope = "RISING" scope.triggerLevel = 0.5 scope.triggerCoupling = "DC" scope.sampleRate = 100_000 scope.numberOfPoints = 300_000 scope.numberOfRecords = 1 scope.initiate() # time, voltage = scope.measure(1, 5000, num_of_samples=4, filter='mfilter') time, voltage = scope.measure(0) scope.abort() scope.plot_scope_data(time, voltage) # unittest.main() scope.close() # scope_5114.close() # scope_5122.close() # scope_5172.close()