Waveform Generator
If a device provides waveform generator functionality, such as the NV200 amplifier, you can use the
WaveformGenerator
class to access this functionality.
For example the NV200 provides an arbitrary waveform generator that can be used to generate a variety of waveforms.
The arbitrary waveform generator can generate a single or repetitive setpoint signal. The curve shape
can be freely defined by up to 1024 samples.
The following example demonstrates how to use the nv200.waveform_generator
module with the
NV200Device
from the nv200.nv200_device
. It covers setting up the WaveformGenerator
,
generating a sine wave, and starting the waveform generator.
import asyncio
from nv200.nv200_device import NV200Device
from nv200.telnet_protocol import TelnetProtocol
from nv200.waveform_generator import WaveformGenerator
async def waveform_generator_test():
# Create the device client using Telnet protocol
transport = TelnetProtocol(MAC="00:80:A3:79:C6:18")
device = NV200Device(transport)
await device.connect()
# Initialize the waveform generator with the NV200 device
waveform_generator = WaveformGenerator(device)
# Generate a sine wave with a frequency of 1 Hz, low level of 0, and high level of 80 µm
sine = waveform_generator.generate_sine_wave(freq_hz=1, low_level=0, high_level=80)
print(f"Sample factor {sine.sample_factor}")
# Transfer the waveform data to the device
await waveform_generator.set_waveform(sine)
# Start the waveform generator with 1 cycle and starting index of 0
await waveform_generator.start(cycles=1, start_index=0)
# Wait until the waveform generator finishes the move
await waveform_generator.wait_until_finished()
# Close the device client connection
await device.close()
if __name__ == "__main__":
asyncio.run(waveform_generator_test())
Step by step guide to using the Waveform Generator
This guide will walk you through the steps to set up and use the waveform generator using the given example code.
Step 1: Import Necessary Modules
To get started, you’ll need to import the relevant modules.
The WaveformGenerator
class is imported from the nv200.waveform_generator
module,
along with other necessary components such as NV200Device
and TelnetProtocol
.
import asyncio
from nv200.nv200_device import NV200Device
from nv200.telnet_protocol import TelnetProtocol
from nv200.waveform_generator import WaveformGenerator
Step 2: Create the NV200Device
To interact with the NV200 device, you must create a NV200Device
instance. This client communicates with the device using the TelnetProtocol
,
which requires the device’s MAC address for connection.
# Create the device client using Telnet protocol
transport = TelnetProtocol(MAC="00:80:A3:79:C6:18")
device = NV200Device(transport)
await device.connect()
Step 3: Initialize the Waveform Generator
After setting up the device client, initialize the WaveformGenerator
with the
device instance. This allows you to interact with the waveform generation
functionality.
# Initialize the waveform generator with the NV200 device
waveform_generator = WaveformGenerator(device)
Step 4: Generate the Waveform
In this example, we will generate a sine wave using the generate_sine_wave
method of
the WaveformGenerator
class. You can specify the frequency, low level (minimum value),
and high level (maximum value) of the sine wave. Optionally, you can also apply a
phase shift to the waveform.
# Generate a sine wave with a frequency of 1 Hz, low level of 0, and high level of 80 µm
sine = waveform_generator.generate_sine_wave(freq_hz=1, low_level=0, high_level=80)
print(f"Sample factor {sine.sample_factor}")
Step 5: Transfer the Waveform to the Device
Once the sine wave has been generated, you need to transfer the waveform data to the device.
The set_waveform
method is used for this purpose, which takes in the generated waveform data
and uploads it to the connected device.
# Transfer the waveform data to the device
await waveform_generator.set_waveform(sine)
Important
Transferring the waveform data to the device may take some seconds, depending on the size of the waveform. Ensure that you wait for the transfer to complete before proceeding with any further operations.
Step 6: Start the Wavform Generator
With the waveform data uploaded to the device, you can now start the waveform generator. You can specify the number of cycles for the waveform to repeat and the starting index of the waveform data. In this example, we are starting the generator with one cycle, using an index of 0.
# Start the waveform generator with 1 cycle and starting index of 0
await waveform_generator.start(cycles=1, start_index=0)
Step 7: Wait for the Waveform to Finish
After starting the waveform generator, you can wait for the waveform to finish its cycle.
The WaveformGenerator.wait_until_finished
method can be used to wait until the waveform generator has
completed its operation. It waits until the is_running
function returns false.
# Wait until the waveform generator finishes the move
await waveform_generator.wait_until_finished()
Step 8: Close the Device Connection
Once the waveform has finished executing, it is good practice to close the connection to the device to free up resources.
# Close the device client connection
await device.close()
API Reference
WaveformGenerator module for controlling waveform generation on a connected NV200 device.
This module defines the WaveformGenerator
class, which provides methods to configure and control waveform generation,
including the ability to generate sine waves, set cycles, adjust sampling times, and manage waveform buffers. It supports
asynchronous interaction with the device for real-time control of waveform generation.
- Classes:
WaveformGenerator
: Manages waveform generation and configuration on the NV200 device.WaveformData
: Represents waveform data with time, amplitude, and sample time.
- class WaveformGenerator[source]
Bases:
object
WaveformGenerator is a class responsible for generating waveforms using a connected device.
- class WaveformData[source]
Bases:
TimeSeries
WaveformData is a NamedTuple that represents waveform data.
- property cycle_time_ms
Returns the cycle of a single cycle in milliseconds.
- property sample_factor
Returns the sample factor used to calculate the sample time from the base sample time.
- __init__(device: NV200Device)[source]
Initializes the WaveformGenerator instance with the specified device client.
- Parameters:
device (DeviceClient) – The device client used for communication with the hardware.
- async configure_waveform_loop(start_index: int, loop_start_index: int, loop_end_index: int)[source]
Sets the start and end indices for the waveform loop. The start index is the index where the waveform generator starts when it is started. The loop start index is the index where the waveform generator starts in the next cycle and the loop end index is the index where the waveform generator jumps to the next cycle.
- classmethod generate_constant_wave(freq_hz: float, constant_level: float) WaveformData [source]
Generates a constant waveform at a specified frequency and level. This method creates a waveform where all sample values are set to a constant level, sampled at intervals determined by the specified frequency.
- Parameters:
freq_hz (float) – The frequency in Hertz at which to generate the waveform samples.
constant_level (float) – The constant value for all samples in the waveform.
- Returns:
An object containing the generated constant waveform values and the sample time in milliseconds.
- Return type:
- classmethod generate_sine_wave(freq_hz: float, low_level: float, high_level: float, phase_shift_rad: float = 0.0) WaveformData [source]
Generates a sine wave based on the specified frequency and amplitude levels.
- Parameters:
freq_hz (float) – The frequency of the sine wave in Hertz (Hz).
low_level (float) – The minimum value (low level) of the sine wave.
high_level (float) – The maximum value (high level) of the sine wave.
- Returns:
- An object containing the generated sine wave data, including:
x_time (List[float]): A list of time points in ms corresponding to the sine wave samples.
y_values (List[float]): A list of amplitude values for the sine wave at each time point.
sample_time_us (float): The time interval between samples in microseconds (µs).
- Return type:
Notes
The method calculates an optimal sample time based on the desired frequency and the hardware’s base sample time.
The buffer size is adjusted to ensure the generated waveform fits within one period of the sine wave.
The sine wave is scaled and offset to match the specified low and high levels.
- classmethod generate_square_wave(freq_hz: float, low_level: float, high_level: float, phase_shift_rad: float = 0.0, duty_cycle: float = 0.5) WaveformData [source]
Generates a square wave (or PWM waveform) using NumPy for efficient computation.
- Parameters:
freq_hz (float) – Frequency of the waveform in Hz.
low_level (float) – Output level during the “low” part of the cycle.
high_level (float) – Output level during the “high” part of the cycle.
duty_cycle (float, optional) – Duty cycle as a fraction between 0.0 and 1.0. Defaults to 0.5 (i.e., 50%).
phase_shift_rad (float, optional) – Phase shift in radians. Defaults to 0.0.
- Returns:
- An object containing:
values (List[float]): Amplitude values of the waveform.
sample_time_ms (float): Time between samples in milliseconds.
- Return type:
- classmethod generate_time_samples_array(freq_hz: float) ndarray [source]
Generates a NumPy array of time samples (in milliseconds) for one period of a waveform at the specified frequency.
- Parameters:
freq_hz (float) – The frequency of the waveform in Hertz.
- Returns:
Time samples (in milliseconds).
- Return type:
np.ndarray
- classmethod generate_time_samples_list(freq_hz: float) List[float] [source]
Generates a list of time samples (in milliseconds) for one period of a waveform at the specified frequency. Sampling is adjusted based on hardware base sample time and buffer constraints.
- Parameters:
freq_hz (float) – The frequency of the waveform in Hertz.
- Returns:
Time samples (in milliseconds).
- Return type:
List[float]
- classmethod generate_triangle_wave(freq_hz: float, low_level: float, high_level: float, phase_shift_rad: float = 0.0) WaveformData [source]
Generates a triangle wave based on the specified frequency and amplitude levels.
- Parameters:
freq_hz (float) – The frequency of the triangle wave in Hertz (Hz).
low_level (float) – The minimum value (low level) of the triangle wave.
high_level (float) – The maximum value (high level) of the triangle wave.
phase_shift_rad (float, optional) – Phase shift in radians. Defaults to 0.0.
- Returns:
- An object containing the generated triangle wave data, including:
values (List[float]): A list of amplitude values for the triangle wave at each time point.
sample_time_ms (float): The time interval between samples in milliseconds (ms).
- Return type:
Notes
The method calculates an optimal sample time based on the desired frequency and the
hardware’s base sample time. - The waveform is normalized between -1 and 1, then scaled and offset to fit between low_level and high_level. - The waveform is generated over one full period.
- classmethod generate_waveform(waveform_type: WaveformType, freq_hz: float, low_level: float, high_level: float, phase_shift_rad: float = 0.0, duty_cycle: float = 0.5) WaveformData [source]
Generates a waveform based on the specified type and parameters.
- Parameters:
waveform_type (Waveform) – The type of waveform to generate (SINE, TRIANGLE, SQUARE).
freq_hz (float) – Frequency of the waveform in Hertz.
low_level (float) – Minimum value of the waveform.
high_level (float) – Maximum value of the waveform.
phase_shift_rad (float, optional) – Phase shift in radians. Defaults to 0.0.
duty_cycle (float, optional) – Duty cycle for square wave. Defaults to 0.5.
- Returns:
The generated waveform data.
- Return type:
- async is_running() bool [source]
Checks if the waveform generator is currently running.
- Returns:
True if the waveform generator is running, False otherwise.
- Return type:
bool
- async set_cycles(cycles: int = 0)[source]
Sets the number of cycles to run. - WaveformGenerator.NV200_INFINITE_CYCLES - 0 = infinitely - 1…65535
- async set_loop_end_index(end_index: int)[source]
Sets the end index for arbitrary waveform generator output. The loop end index is the index where the waveform generator jumps to the next cycle or finishes if only one cycle is used.
- async set_loop_start_index(start_index: int)[source]
Sets the start index for the waveform generator loop. If you use multiple cycles, the loop start index is the index defines the index where the waveform generator starts in the next cycle.
- async set_output_sampling_time(sampling_time: int)[source]
Sets the output sampling time for the waveform generator. The output sampling time can be given in multiples of 50 µs from 1 * 50µs to 65535 * 50µs. If the sampling time is not a multiple of 50, it will be rounded to the nearest multiple of 50µs. The calculated sampling time is returned in microseconds.
- Returns:
The set sampling time in microseconds.
- Return type:
int
Note: Normally you do not need to set the sampling time manually because it is set automatically calculated when the waveform is generated.
- async set_start_index(index: int)[source]
Sets the offset index when arbitrary waveform generator gets started. That means after the start() function is called, the arbitrary waveform generator starts at the index defined by set_start_index() and runs until the index defined by set_loop_end_index(). In all successive cycles, the arbitrary waveform generator starts at set_loop_start_index(). This is repeated until the number of cycles reaches the value given by set_cycles().
- async set_waveform(waveform: WaveformData, unit: WaveformUnit = WaveformUnit.PERCENT, adjust_loop: bool = True, on_progress: ProgressCallback | None = None)[source]
Sets the waveform data in the device. The WaveformData object should contain the waveform values and the sample time.
- Parameters:
waveform (WaveformData) – The waveform data to be set.
unit (WaveformUnit) – The unit of the waveform values. Defaults to WaveformUnit.PERCENT.
adjust_loop (bool) – If True, adjusts the loop indices based on the waveform data, if false, the loop indices are not adjusted. If the loop indices are adjusted, then they will be set to the following value: - start_index = 0 (first waveform value) - loop_start_index = 0 (first waveform value) - loop_end_index = last waveform value
on_progress (Optional[ProgressCallback]) – Optional callback for progress updates.
- Raises:
ValueError – If the waveform data is invalid.
- async set_waveform_buffer(buffer: list[float], unit: WaveformUnit = WaveformUnit.PERCENT, on_progress: ProgressCallback | None = None)[source]
Writes a full waveform buffer to the device by setting each value using set_waveform_value. The buffer should contain waveform values in percent (0-100). In closed loop mode, the value is interpreted as a percentage of the position range (i.e. 0 - 80 mra) and in open loop mode, the value is interpreted as a percentage of the voltage range (i.e. -20 - 130 V).
- Parameters:
buffer (list of float) – The waveform values in percent (0-100).
unit (WaveformUnit) – The unit of the waveform values. Defaults to WaveformUnit.PERCENT.
on_progress (Optional[ProgressCallback]) – Optional callback for progress updates.
- Raises:
ValueError – If the buffer size exceeds the maximum buffer length.
- async set_waveform_from_samples(time_samples: Sequence[float] | ndarray, values: Sequence[float] | ndarray, unit: WaveformUnit = WaveformUnit.PERCENT, adjust_loop: bool = True)[source]
Sets the waveform data in the device from separate time samples and values. The waveform data should contain the time samples in milliseconds and the corresponding amplitude values. in percent (0-100). In closed loop mode, the value is interpreted as a percentage of the position range (i.e. 0 - 80 mra) and in open loop mode, the value is interpreted as a percentage of the voltage range (i.e. -20 - 130 V).
- Parameters:
time_samples (Sequence[float] or np.ndarray) – Time samples in milliseconds.
values (Sequence[float] or np.ndarray) – Corresponding waveform amplitude values in percent (0-100).
unit (WaveformUnit, optional) – The unit of the waveform values. Defaults to WaveformUnit.PERCENT.
adjust_loop (bool) – If True, adjusts loop indices based on data length.
- Raises:
ValueError – If inputs are invalid or lengths mismatch.
- async set_waveform_value_percent(index: int, percent: float)[source]
Sets the value of the waveform at the specified index in percent from 0 - 100% In closed loop mode, the value is interpreted as a percentage of the position range (i.e. 0 - 80 mra) and in open loop mode, the value is interpreted as a percentage of the voltage range (i.e. -20 - 130 V).
- async start(start: bool = True, cycles: int = -1, start_index: int = -1)[source]
Starts / stops the waveform generator
- Parameters:
start (bool, optional) – If True, starts the waveform generator. If False, stops it. Defaults to True.
cycles (int, optional) – The number of cycles to run the waveform generator. If set to -1, the value configured via set_cycles() will be used.
- async wait_until_finished(timeout_s: float = 10.0)[source]
Waits until the waveform generator is finished running.
- Parameters:
timeout_s (float) – The maximum time to wait in seconds. Defaults to 10 seconds.
- Returns:
True if the waveform generator finished running, False if timed out.
- Return type:
bool
- class WaveformType[source]
Bases:
Enum
Enumeration for different waveform types supported by the generator.
- class WaveformUnit[source]
Bases:
Enum
Enumeration for different waveform units used in the generator.
- calculate_sampling_time_ms(time_samples: Sequence[float] | ndarray) float [source]
Calculates the sampling time in milliseconds from a sequence of time samples.
- Parameters:
time_samples (Union[Sequence[float], np.ndarray]) – A list or NumPy array of time samples in milliseconds.
- Returns:
The sampling time in milliseconds.
- Return type:
float
- Raises:
ValueError – If the sequence has fewer than 2 time samples.