Instrument¶
Contains modules for controlling the PSLab’s built-in instruments.
The built-in instruments are LogicAnalyzer, Multimeter,
Oscilloscope, PowerSupply, PWMGenerator, and WaveformGenerator.
LogicAnalyzer¶
- class pslab.instrument.logic_analyzer.LogicAnalyzer(device: Optional[pslab.serial_handler.SerialHandler] = None)[source]¶
Bases:
pslab.serial_handler.ADCBufferMixinInvestigate digital signals on up to four channels simultaneously.
- Parameters
device (
SerialHandler, optional) – Serial connection to PSLab device. If not provided, a new one will be created.
- trigger_channel¶
See
configure_trigger().- Type
str
- trigger_mode¶
See
configure_trigger().- Type
str
- capture(channels: Union[int, str, List[str]], events: int = 2500, timeout: float = 1, modes: List[str] = ('any', 'any', 'any', 'any'), e2e_time: Optional[float] = None, block: bool = True) Optional[List[numpy.ndarray]][source]¶
Capture logic events.
This method cannot be used at the same time as the oscilloscope.
- Parameters
channels ({1, 2, 3, 4} or str or list of str) – Number of channels to capture events on. Events will be captured on LA1, LA2, LA3, and LA4, in that order. Alternatively, the name of of a single digital input, or a list of two names of digital inputs can be provided. In that case, events will be captured only on that or those specific channels.
events (int, optional) – Number of logic events to capture on each channel. The default and maximum value is 2500.
timeout (float, optional) – Timeout in seconds before cancelling measurement in blocking mode. If the timeout is reached, the events captured up to that point will be returned. The default value is 1 second.
modes (List[str], optional) – List of strings specifying the type of logic level change to capture on each channel. See
DigitalInputfor available modes. The default value is (“any”, “any”, “any”, “any”).e2e_time (float, optional) – The maximum time between events in seconds. This is only required in three and four channel mode, which uses 16-bit counters as opposed to 32-bit counters which are used in one and two channel mode. The 16-bit counter normally rolls over after 1024 µs, so if the time between events is greater than that the timestamp calculations will be incorrect. By setting this to a value greater than 1024 µs, the counter will be slowed down by a prescaler, which can extend the maximum allowed event-to-event time gap to up to 262 ms. If the time gap is greater than that, three and four channel mode cannot be used. One and two channel mode supports timegaps up to 67 seconds.
block (bool, optional) – Whether to block while waiting for events to be captured. If this is False, this method will return None immediately and the captured events must be manually fetched by calling
fetch_data(). The default value is True.
- Returns
events – List of numpy.ndarrays containing timestamps in microseconds when logic events were detected, or None if block is False. The length of the list is equal to the number of channels that were used to capture events, and each list element corresponds to a channel.
- Return type
list of numpy.ndarray or None
- Raises
ValueError if too many events are requested, or –
ValueError if too many channels are selected. –
- configure_trigger(trigger_channel: str, trigger_mode: str)[source]¶
Set up trigger channel and trigger condition.
- Parameters
trigger_channel ({"LA1", "LA2", "LA3", "LA4"}) – The digital input on which to trigger.
trigger_mode ({"disabled", "falling", "rising"}) – The type of logic level change on which to trigger.
- count_pulses(channel: str = 'FRQ', interval: float = 1, block: bool = True) Optional[int][source]¶
Count pulses on a digital input.
The counter is 16 bits, so it will roll over after 65535 pulses. This method can be used at the same time as the oscilloscope.
- Parameters
channel ({"LA1", "LA2", "LA3", "LA4", "FRQ"}, optional) – Digital input on which to count pulses. The default value is “FRQ”.
interval (float, optional) – Time in seconds during which to count pulses. The default value is 1 second.
block (bool, optional) – Whether to block while counting pulses or not. If False, this method will return None, and the pulses must be manually fetched using
fetch_pulse_count(). Additionally, the interval argument has no meaning if block is False; the counter will keep counting even after the interval time has expired. The default value is True.
- Returns
Number of pulses counted during the interval, or None if block is False.
- Return type
Union[int, None]
- fetch_data() List[numpy.ndarray][source]¶
Collect captured logic events.
It is possible to call fetch_data while the capture routine is still running. Doing so will not interrupt the capture process. In multi-channel mode, the number of timestamps may differ between channels when fetch_data is called before the capture is complete.
- Returns
data – List of numpy.ndarrays holding timestamps in microseconds when logic events were detected. The length of the list is equal to the number of channels that were used to capture events, and each list element corresponds to a channel.
- Return type
list of numpy.ndarray
- fetch_pulse_count() int[source]¶
Return the number of pulses counted since calling
count_pulses().- Returns
Number of pulses counted since calling
count_pulses().- Return type
int
- get_initial_states() Dict[str, bool][source]¶
Return the initial state of each digital input at the beginning of capture.
- Returns
dict of four str – Dictionary containing pairs of channel names and the corresponding initial state, e.g. {‘LA1’: True, ‘LA2’: True, ‘LA3’: True, ‘LA4’: False}. True means HIGH, False means LOW.
- Return type
bool pairs
- get_progress() int[source]¶
Return the number of captured events per channel held in the buffer.
- Returns
progress – Number of events held in buffer. If multiple channels have events in buffer, the lowest value will be returned.
- Return type
int
- get_states() Dict[str, bool][source]¶
Return the current state of the digital inputs.
- Returns
dict of four str – Dictionary containing pairs of channel names and the corresponding current state, e.g. {‘LA1’: True, ‘LA2’: True, ‘LA3’: True, ‘LA4’: False}. True means HIGH, False means LOW.
- Return type
bool pairs
- get_xy(timestamps: List[numpy.ndarray], initial_states: Optional[Dict[str, bool]] = None) List[numpy.ndarray][source]¶
Turn timestamps into plottable data.
- Parameters
timestamps (list of numpy.ndarray) – List of timestamps as returned by
capture()orfetch_data().initial_states (dict of str, bool) – Initial states of digital inputs at beginning of capture, as returned by
get_initial_states(). If no additional capture calls have been issued before callingget_xy(), this can be omitted.
- Returns
List of x, y pairs suitable for plotting using, for example, matplotlib.pyplot.plot. One pair of x and y values is returned for each list of timestamps given as input.
- Return type
list of numpy.ndarray
- measure_duty_cycle(channel: str, timeout: float = 1) Tuple[float][source]¶
Measure duty cycle and wavelength.
This method cannot be used at the same time as the oscilloscope.
- Parameters
channel ({"LA1", "LA2", "LA3", "LA4"}) – Digital input on which to measure.
timeout (float, optional) – Timeout in seconds before cancelling measurement. The default value is 1 second.
- Returns
wavelength (float) – Wavelength in microseconds.
duty_cycle (float) – Duty cycle as a value between 0 - 1.
- measure_frequency(channel: str, simultaneous_oscilloscope: bool = False, timeout: float = 1) float[source]¶
Measure the frequency of a signal.
- Parameters
channel ({"LA1", "LA2", "LA3", "LA4"}) – Name of the digital input channel in which to measure the frequency.
simultaneous_oscilloscope (bool, optional) – Set this to True if you need to use the oscilloscope at the same time. Uses firmware instead of software to measure the frequency, which may fail and return 0. Will not give accurate results above 10 MHz. The default value is False.
timeout (float, optional) – Timeout in seconds before cancelling measurement. The default value is 1 second.
- Returns
frequency – The signal’s frequency in Hz.
- Return type
float
- measure_interval(channels: List[str], modes: List[str], timeout: float = 1) float[source]¶
Measure the time between two events.
This method cannot be used at the same time as the oscilloscope.
- Parameters
channels (List[str]) – A pair of digital inputs, LA1, LA2, LA3, or LA4. Both can be the same.
modes (List[str]) – Type of logic event to listen for on each channel. See
DigitalInputfor available modes.timeout (float, optional) – Timeout in seconds before cancelling measurement. The default value is 1 second.
- Returns
interval – Time between events in microseconds. A negative value means that the event on the second channel happend first.
- Return type
float
Multimeter¶
- class pslab.instrument.multimeter.Multimeter(device: Optional[pslab.serial_handler.SerialHandler] = None)[source]¶
Bases:
pslab.instrument.oscilloscope.OscilloscopeMeasure voltage, resistance and capacitance.
- Parameters
device (Handler) – Serial interface for communicating with the PSLab device. If not provided, a new one will be created.
- calibrate_capacitance()[source]¶
Calibrate stray capacitance.
Correctly calibrated stray capacitance is important when measuring small capacitors (picofarad range).
Stray capacitace should be recalibrated if external wiring is connected to the CAP pin.
- measure_capacitance() float[source]¶
Measure the capacitance of a capacitor connected between CAP and GND.
- Returns
capacitance – Capacitance in Farad.
- Return type
float
- measure_resistance() float[source]¶
Measure the resistance of a resistor connected between RES and GND.
- Returns
resistance – Resistance in ohm.
- Return type
float
- measure_voltage(channel: str = 'VOL') float[source]¶
Measure the voltage on the selected channel.
- Parameters
channel ({"CH1", "CH2", "CH3", "MIC", "CAP", "RES", "VOL"}, optional) – The name of the analog input on which to measure the voltage. The default channel is VOL.
- Returns
voltage – Voltage in volts.
- Return type
float
Oscilloscope¶
- class pslab.instrument.oscilloscope.Oscilloscope(device: Optional[pslab.serial_handler.SerialHandler] = None)[source]¶
Bases:
pslab.serial_handler.ADCBufferMixinCapture varying voltage signals on up to four channels simultaneously.
- Parameters
device (
SerialHandler, optional) – Serial interface for communicating with the PSLab device. If not provided, a new one will be created.
- capture(channels: int, samples: int, timegap: float, trigger: Optional[Union[float, bool]] = None, trigger_channel: Optional[str] = None, block: bool = True) List[numpy.ndarray][source]¶
Capture an oscilloscope trace from the specified input channels.
- Parameters
channels (str or {1, 2, 3, 4}) – Number of channels to sample from simultaneously, or the name (CH1, CH2, CH3, MIC, CAP, RES, VOL) of a single channel to sample from. If channel is an integer, the oscilloscope will sample the first one, two, three, or four channels in the aforementioned list.
samples (int) – Number of samples to fetch. Maximum 10000 divided by number of channels.
timegap (float) –
Time gap between samples in microseconds. Will be rounded to the closest 1 / 8 µs. The minimum time gap depends on the type of measurement:
Simultaneous channels
No trigger (10-bit)
Trigger (10-bit)
No trigger (12-bit)
1
0.5 µs
0.75 µs
1 µs
2
0.875 µs
0.875 µs
N/A
4
1.75 µs
1.75 µs
N/A
Sample resolution is set automatically based on the above limitations; i.e. to get 12-bit samples only one channel may be sampled, there must be no active trigger, and the time gap must be 1 µs or greater.
trigger (float or bool, optional) – Voltage at which to trigger sampling. Triggering is disabled by default. Trigger settings persist between calls; disable by setting trigger=False.
trigger_channel (str, optional) – Wait for the voltage level on this channel to cross the trigger value before sampling. Same as the first sampled channel by default.
block (bool, optional) – Whether or not to block while sampling. If False, return timestamps immediately without waiting for corresponding voltages. User is responsible for waiting an appropriate amount of time before collecting samples with
fetch_data(). True by default.
Example
>>> from pslab import Oscilloscope >>> scope = Oscilloscope() >>> x, y = scope.capture(1, 3200, 1)
- Returns
List of numpy arrays holding timestamps and corresponding voltages. In non-blocking mode, only timestamps are returned; voltages must be fetched using
fetch_data().- Return type
list of numpy.ndarray
- Raises
ValueError – If :channels: is not 1, 2, 3, 4, or one of CH1, CH2, CH3, MIC, CAP, RES, VOL, or :samples: > 10000 / :channels:, or :timegap: is too low.
- configure_trigger(channel: Optional[str] = None, voltage: float = 0, prescaler: int = 0, enable: bool = True)[source]¶
Configure trigger parameters for 10-bit capture routines.
The capture routines will wait until a rising edge of the input signal crosses the specified level. The trigger will timeout within 8 ms, and capture will start regardless.
To disable the trigger after configuration, set the trigger_enabled attribute of the Oscilloscope instance to False.
- Parameters
channel ({'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'RES', 'VOL'}, optional) – The name of the trigger channel. First sampled channel by default.
voltage (float, optional) – The trigger voltage in volts. The default value is 0.
prescaler (int, optional) – The default value is 0.
enable_trigger (bool, optional) – Set this to False to disable the trigger. True by default.
Examples
>>> from pslab import Oscilloscope >>> scope = Oscilloscope() >>> scope.configure_trigger(channel='CH1', voltage=1.1) >>> x, y = scope.capture(channels=1, samples=800, timegap=2) >>> diff = abs(y[0] - 1.1) # Should be small unless a timeout occurred.
- Raises
TypeError – If the trigger channel is set to a channel which cannot be sampled.
- fetch_data() List[numpy.ndarray][source]¶
Fetch captured samples.
Example
>>> from pslab import Oscilloscope >>> scope = Oscilloscope() >>> scope.capture_nonblocking(channels=2, samples=1600, timegap=1) >>> y1, y2 = scope.fetch_data()
- Returns
List of numpy arrays holding sampled voltages.
- Return type
list of numpy.ndarray
- progress() Tuple[bool, int][source]¶
Return the status of a capture call.
- Returns
A boolean indicating whether the capture is complete, followed by the number of samples currently held in the buffer.
- Return type
bool, int
- select_range(channel: str, voltage_range: Union[int, float])[source]¶
Set appropriate gain automatically.
Setting the right voltage range will result in better resolution.
- Parameters
channel ({'CH1', 'CH2'}) – Channel on which to apply gain.
voltage_range ({16, 8, 4, 3, 2, 1.5, 1, .5}) –
Examples
Set 2x gain on CH1. Voltage range ±8 V:
>>> from pslab import Oscilloscope >>> scope = Oscilloscope() >>> scope.select_range('CH1', 8)
- property trigger_channel: str¶
Name of channel to trigger on.
- Type
str
- property trigger_enabled: bool¶
Wait for trigger condition before capture start.
- Type
bool
- property trigger_voltage: float¶
Trigger when voltage crosses this value.
- Type
float
PowerSupply¶
- class pslab.instrument.power_supply.PowerSupply(device: Optional[pslab.serial_handler.SerialHandler] = None)[source]¶
Bases:
objectControl the PSLab’s programmable voltage and current sources.
An instance of PowerSupply controls three programmable voltage sources on pins PV1, PV2, and PV3, as well as a programmable current source on pin PCS. The voltage/current on each source can be set via the voltage/current properties of each source.
- Parameters
device (
SerialHandler) – Serial connection with which to communicate with the device. A new instance will be created automatically if not specified.
- property pcs¶
Current on PCS; range [0, 3.3e-3] A.
Notes
The maximum available current that can be output by the current source is dependent on load resistance:
I_max = 3.3 V / (1 kΩ + R_load)
For example, the maximum current that can be driven across a 100 Ω load is 3.3 V / 1.1 kΩ = 3 mA. If the load is 10 kΩ, the maximum current is only 3.3 V / 11 kΩ = 300 µA.
Be careful to not set a current higher than available for a given load. If a current greater than the maximum for a certain load is requested, the actual current will instead be much smaller. For example, if a current of 3 mA is requested when connected to a 1 kΩ load, the actual current will be only a few hundred µA instead of the maximum available 1.65 mA.
- Type
float
- property pv1¶
Voltage on PV1; range [-5, 5] V.
- Type
float
- property pv2¶
Voltage on PV2; range [-3.3, 3.3] V.
- Type
float
- property pv3¶
Voltage on PV3; range [0, 3.3] V.
- Type
float
PWMGenerator¶
- class pslab.instrument.waveform_generator.PWMGenerator(device: Optional[pslab.serial_handler.SerialHandler] = None)[source]¶
Bases:
objectGenerate PWM signals on SQ1, SQ2, SQ3, and SQ4.
- Parameters
device (
SerialHandler) – Serial connection with which to communicate with the device. A new instance will be created automatically if not specified.
Examples
Output 40 kHz PWM signals on SQ1 and SQ3 phase shifted by 50%. Set the duty cycles to 75% and 33%, respectivelly:
>>> from pslab import PWMGenerator >>> pwmgen = PWMGenerator() >>> pwmgen.generate(["SQ1", "SQ2"], 4e4, [0.75, 0.33], 0.5)
Output a 32 MHz PWM signal on SQ4 with a duty cycle of 50%:
>>> pwmgen.map_reference_clock(["SQ4"], 2)
Set SQ2 high:
>>> pwmgen.set_states(sq2=True)
- property frequency: float¶
Get the common frequency for all digital outputs in Hz.
- generate(channels: Union[str, List[str]], frequency: float, duty_cycles: Union[float, List[float]], phases: Union[float, List[float]] = 0)[source]¶
Generate PWM signals on SQ1, SQ2, SQ3, and SQ4.
- Parameters
channels ({1, 2, 3, 4} or {'SQ1', 'SQ2', 'SQ3', 'SQ4'} or list of the same) – Pin name or list of pin names on which to generate PWM signals. Pins which are not included in the argument will not be affected.
frequency (float) – Frequency in Hz. Shared by all outputs.
duty_cycles (float or list of floats) –
Duty cycle between 0 and 1 as either a single value or a list of values.
If ‘duty_cycles’ is a single value, it is applied to all channels given in ‘channels’.
If ‘duty_cycles’ is a list, the values in the list will be applied to the corresponding channel in the ‘channels’ list. The lists must have the same length.
phases (float or list of floats) –
Phase between 0 and 1 as either a single value or a list of values.
If ‘phases’ is a single value, it will be the phase between each subsequent channel in ‘channels’. For example,
>>> generate(['SQ1', 'SQ2', 'SQ3', 'SQ4'], 1000, 0.5, 0.1)
SQ2 will be shifted relative to SQ1 by 10%, SQ3 will be shifted relative to SQ2 by 10% (i.e. 20% relative to SQ1), and SQ4 will be shifted relative to SQ3 by 10% (i.e. 30% relative to SQ1).
If ‘phases’ is a list, the values in the list will be applied to the corresponding channel in the ‘channels’ list. The lists must have the same length.
- map_reference_clock(channels: List[str], prescaler: int)[source]¶
Map the internal oscillator output to a digital output.
The duty cycle of the output is locked to 50%.
- Parameters
channels ({'SQ1', 'SQ2', 'SQ3', 'SQ4'} or list of the same) – Digital output pin(s) to which to map the internal oscillator.
prescaler (int) – Prescaler value in interval [0, 15]. The output frequency is 128 / (1 << prescaler) MHz.
- set_state(sq1: Optional[Union[bool, str]] = None, sq2: Optional[Union[bool, str]] = None, sq3: Optional[Union[bool, str]] = None, sq4: Optional[Union[bool, str]] = None)[source]¶
Set the digital outputs HIGH or LOW.
- Parameters
sq1 ({True, False, None, 'HIGH', 'LOW', 'PWM'}, optional) – Set the state of SQ1. True or “HIGH” sets it HIGH, False or “LOW” sets it low, and None or “PWM” leaves it in its current state. The default value is None.
sq2 ({True, False, None, 'HIGH', 'LOW', 'PWM'}, optional) – See ‘sq1’.
sq3 ({True, False, None, 'HIGH', 'LOW', 'PWM'}, optional) – See ‘sq1’.
sq4 ({True, False, None, 'HIGH', 'LOW', 'PWM'}, optional) – See ‘sq1’.
WaveformGenerator¶
- class pslab.instrument.waveform_generator.WaveformGenerator(device: Optional[pslab.serial_handler.SerialHandler] = None)[source]¶
Bases:
objectGenerate analog waveforms on SI1 or SI2.
- Parameters
device (
SerialHandler, optional) – Serial connection with which to communicate with the device. A new instance is created automatically if not specified.
Examples
Output the default function (3.3*sin(t)) on SI2 with frequency 2.5 kHz:
>>> from pslab import WaveformGenerator >>> wavegen = WaveformGenerator() >>> wavegen.generate("SI2", 2500) [2500]
Output phase shifted sine waves on SI1 and SI2:
>>> wavegen.generate(["SI1", "SI2"], 1000, 90) [1000, 1000]
Reduce the amplitude on SI1:
>>> import numpy as np >>> wavegen.load_function("SI1", lambda x: 1.5*np.sin(x), [0, 2*np.pi])
Output two superimposed sine waves on SI2:
>>> wavegen.load_function("SI2", lambda x: 2*np.sin(x) + np.sin(5*x), [0, 2*np.pi])
- generate(channels: Union[str, List[str]], frequency: Union[float, List[float]], phase: float = 0) List[float][source]¶
Generate analog waveforms on SI1 or SI2.
The default waveform is a sine wave with amplitude 3.3 V. Other waveforms can be set using
load_function()orload_table().- Parameters
channels ({1, 2} or {'SI1', 'SI2', ['SI1', 'SI2']}) – Pin(s) on which to generate a waveform.
frequency (float or list of floats) – Frequency in Hz. Can be a list containing two different values when ‘channel’ is [‘SI1’, ‘SI2’]. Must be greater than 0.1 Hz. For frequencies below 1 Hz the signal is noticably attenuated by AC coupling.
phase (float, optional) – Phase between waveforms when generating waveforms on both SI1 and SI2 in degrees. The default is 0.
- Returns
frequency – The actual frequency may differ from the requested value due to the device-interal integer representation. The actual frequency is therefore returned as a list. The length of the list is equal to the number of channels used to generate waveforms.
- Return type
List[float]
- load_function(channel: str, function: Union[str, Callable], span: Optional[List[float]] = None)[source]¶
Load a custom waveform function.
- Parameters
channel ({'SI1', 'SI2'}) – The output pin on which to generate the waveform.
function (Union[str, Callable]) –
A callable function which takes a numpy.ndarray of x values as input and returns a corresponding numpy.ndarray of y values. The y-values should be voltages in V, and should lie between -3.3 V and 3.3 V. Values outside this range will be clipped.
Alternatively, ‘function’ can be a string literal ‘sine’ or ‘tria’, for a sine wave or triangle wave with amplitude 3.3 V.
span (List[float], optional) – The minimum and maximum x values between which to evaluate ‘function’. Should typically correspond to one period. Omit if ‘function’ is ‘sine’ or ‘tria’.
- load_table(channel: str, points: numpy.ndarray)[source]¶
Load a custom waveform as a table.
- Parameters
channel ({'SI1', 'SI2'}) – The output pin on which to generate the waveform.
points (np.ndarray) – Array of voltage values which make up the waveform. Array length must be 512. Values outside the range -3.3 V to 3.3 V will be clipped.