|
| 1 | +''' |
| 2 | + Exercise in which a DAQ board will generate hardware-timed continuous analog output from two |
| 3 | + channels without using a callback function |
| 4 | +
|
| 5 | + scan_waveform_output |
| 6 | +
|
| 7 | + Purpose |
| 8 | + You will do hardware-timed continuous analog output using sample regeneration instead of a callback function. |
| 9 | + The buffer contents is played out repeatedly: once the end of the buffer is reached, the DAQ returns to the |
| 10 | + beginning and resumes from there. |
| 11 | +
|
| 12 | + Monitoring the output |
| 13 | + If you lack an oscilloscope you may physically connect the analog output to |
| 14 | + an analog input and monitor this using the NI MAX test panel. You likely will need |
| 15 | + to select RSE: http://www.ni.com/white-paper/3344/en/ |
| 16 | + Ask MAX to display "AI0:1" |
| 17 | + |
| 18 | + Instructions |
| 19 | + - Wire AO0 to AO0 or to an osciloscope. Wire AO1 to AO1 or to an osciloscope. |
| 20 | + - You will need to edit the lines at the locations marked by the string ### EDIT |
| 21 | + - There may be hints and instructions around those lines |
| 22 | +
|
| 23 | +
|
| 24 | + Run the code at the command line thus: |
| 25 | + python scan_waveform_output |
| 26 | +
|
| 27 | +
|
| 28 | +
|
| 29 | + |
| 30 | +For more: |
| 31 | +https://github.com/tenss/Python_DAQmx_examples |
| 32 | +
|
| 33 | +''' |
| 34 | + |
| 35 | +import nidaqmx |
| 36 | +from nidaqmx.constants import (AcquisitionType,RegenerationMode) |
| 37 | +import numpy as np |
| 38 | + |
| 39 | +class scan_waveform_output(): |
| 40 | + |
| 41 | + # Properties of the class defined here |
| 42 | + |
| 43 | + # Parameters for the acquisition (device and channels) |
| 44 | + dev_name = '' ### EDIT (The name of the DAQ device as shown in MAX) |
| 45 | + |
| 46 | + # Task configuration |
| 47 | + sample_rate = 5000 # Sample Rate in Hz |
| 48 | + galvo_amplitude = 5 # Scanner amplitude (defined as peak-to-peak/2) |
| 49 | + pixels_per_line = 256 # Number pixels per line for a sawtooth waveform (for sine wave this defines wavelength) |
| 50 | + |
| 51 | + |
| 52 | + x_waveform = [] # Vector containing the waveform for the x mirror (fast axis) |
| 53 | + y_waveform = [] # Vector containing the waveform for the y mirror (slow axis) |
| 54 | + |
| 55 | + daq_waveforms = [] # Will contain the x and y waveform data to be sent to the DAQ |
| 56 | + |
| 57 | + num_samples_per_channel = [] #The length of the waveform |
| 58 | + |
| 59 | + h_task = [] # DAQmx task handle |
| 60 | + |
| 61 | + |
| 62 | + def __init__(self, autoconnect=False): |
| 63 | + # This method is the constructor and runs once when the class is instantiated |
| 64 | + |
| 65 | + self.generate_waveforms() |
| 66 | + if autoconnect: |
| 67 | + self.create_task() |
| 68 | + #close constructor |
| 69 | + |
| 70 | + |
| 71 | + def generate_waveforms(self): |
| 72 | + ###EDIT -- complete this method |
| 73 | + self.y_waveform = |
| 74 | + self.x_waveform = |
| 75 | + |
| 76 | + # This must be a two column matrix. The first column is the waveform sent to AO0 |
| 77 | + # and the second column is the waveform sent to AO1. |
| 78 | + self.daq_waveforms = np.stack() ###EDIT |
| 79 | + #close generate_waveforms |
| 80 | + |
| 81 | + |
| 82 | + def create_task(self): |
| 83 | + # This method sets up an NI Task that will play out the waveforms |
| 84 | + |
| 85 | + # * Create a DAQmx task |
| 86 | + # http://zone.ni.com/reference/en-XX/help/370471AE-01/daqmxcfunc/daqmxcreatetask/ |
| 87 | + self.h_task = nidaqmx.Task('scanwave') |
| 88 | + |
| 89 | + |
| 90 | + # * Set up analog output on channels 0 and 1 |
| 91 | + # C equivalent - DAQmxCreateAOVoltageChan |
| 92 | + # http://zone.ni.com/reference/en-XX/help/370471AE-01/daqmxcfunc/daqmxcreateaovoltagechan/ |
| 93 | + # https://nidaqmx-python.readthedocs.io/en/latest/ao_channel_collection.html |
| 94 | + connect_at = '%s/ao0:1' % self.dev_name |
| 95 | + self.h_task.ao_channels.add_ao_voltage_chan(connect_at) |
| 96 | + |
| 97 | + |
| 98 | + |
| 99 | + # * Configure the sampling rate and the number of samples |
| 100 | + # C equivalent - DAQmxCfgSampClkTiming |
| 101 | + # http://zone.ni.com/reference/en-XX/help/370471AE-01/daqmxcfunc/daqmxcfgsampclktiming/ |
| 102 | + # https://nidaqmx-python.readthedocs.io/en/latest/timing.html |
| 103 | + self.num_samples_per_channel = len(self.waveform) # The number of samples to be stored in the buffer per channel |
| 104 | + buffer_length = self.num_samples_per_channel*4 # TODO -- IS THIS NEEDED?? |
| 105 | + self.h_task.timing.cfg_samp_clk_timing(rate = self.sample_rate, \ |
| 106 | + samps_per_chan = buffer_length, \ |
| 107 | + sample_mode = AcquisitionType.CONTINUOUS) |
| 108 | + |
| 109 | + |
| 110 | + # * Set up sample regeneration: i.e. the buffer contents will play continuously |
| 111 | + # http://zone.ni.com/reference/en-XX/help/370471AE-01/mxcprop/attr1453/ |
| 112 | + # For more on DAQmx write properties: http://zone.ni.com/reference/en-XX/help/370469AG-01/daqmxprop/daqmxwrite/ |
| 113 | + # For a discussion on regeneration mode in the context of analog output tasks see: |
| 114 | + # https://forums.ni.com/t5/Multifunction-DAQ/Continuous-write-analog-voltage-NI-cDAQ-9178-with-callbacks/td-p/4036271 |
| 115 | + self.h_task.out_stream.regen_mode = RegenerationMode.ALLOW_REGENERATION |
| 116 | + print('Regeneration mode is set to: %s' % str(self.h_task.out_stream.regen_mode)) |
| 117 | + |
| 118 | + |
| 119 | + |
| 120 | + # * Write the waveform to the buffer with a 5 second timeout in case it fails |
| 121 | + # Writes doubles using DAQmxWriteAnalogF64 |
| 122 | + # http://zone.ni.com/reference/en-XX/help/370471AG-01/daqmxcfunc/daqmxwriteanalogf64/ |
| 123 | + self.h_task.write(, timeout=2). ###EDIT |
| 124 | + #close create_task |
| 125 | + |
| 126 | + |
| 127 | +#close class scan_waveform_output |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | +if __name__ == '__main__': |
| 132 | + print('\nRunning demo for hardwareContinuousVoltageNoCallback_twoChannels\n\n') |
| 133 | + AO = hardwareContinuousVoltageNoCallback_twoChannels() |
| 134 | + AO.create_task() |
| 135 | + AO.h_task.start() |
| 136 | + input('press return to stop') |
| 137 | + AO.h_task.start() |
0 commit comments