Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

synchronizing analog output and digital output

I just want to output waves from the USB6421 ao0 and DIO0, but I find there is a delay between the analog and digital waves. I generated the  analog and digital waves with same sampling rate.

 

Generated analog and digital waves:

 

 

71968aab-d60f-4430-a48d-f18b258b519a.png

 

Output analog and digital waves by USB6421 measure by Oscilloscope:

 

IMG_5957.jpg

This my code

import nidaqmx
import numpy as np
from nidaqmx.constants import AcquisitionType,Edge
import matplotlib.pyplot as plt  

# 参数配置
fs = 1000                      
duration = 1                   
num_samples = fs * duration    
wave_amplitude = 2.0           
wave_period = 0.5             
symmetry = 0.5                 

 
t = np.linspace(0, duration, num_samples, endpoint=False)

# ==============================================
# Generate the Triangular Analog wave  
# ==============================================
phase = (t % wave_period) / wave_period  
 
rise_samples = int(wave_period * fs * symmetry)  
fall_samples = int(wave_period * fs * (1 - symmetry))  
 
galvo_data = np.zeros_like(t)
for i in range(len(t)):
    cycle_pos = int((phase[i] * (rise_samples + fall_samples)) % (rise_samples + fall_samples))
    if cycle_pos < rise_samples:
        #from -A to +A
        galvo_data[i] = wave_amplitude * (-1 + 2 * (cycle_pos / rise_samples))
    else:
        # from +A to -A
        galvo_data[i] = wave_amplitude * (1 - 2 * ((cycle_pos - rise_samples) / fall_samples))

# ==============================================
# Generate Digital Square Wave  
# ==============================================
dove_data = (t % 0.5) < 0.25    
 
plt.figure(figsize=(10, 4))
plt.plot(galvo_data) 
plt.plot(camera_data) 
plt.show()


with nidaqmx.Task() as ao_task, nidaqmx.Task() as do_task:
 
    
    ao_task.ao_channels.add_ao_voltage_chan("Dev1/ao0")
    ao_task.timing.cfg_samp_clk_timing(
        rate=fs,
         source="",
         active_edge=Edge.RISING,
         sample_mode=AcquisitionType.CONTINUOUS,
         samps_per_chan=num_samples
     )

   
     do_task.do_channels.add_do_chan("Dev1/port0/line0")
     do_task.timing.cfg_samp_clk_timing(
         rate=fs,
         source="/Dev1/ao/SampleClock",
         active_edge=Edge.RISING,
         sample_mode=AcquisitionType.CONTINUOUS,
         samps_per_chan=num_samples
     )
    ao_task.write(galvo_data)
    do_task.write(camera_data.astype(np.bool))  
    
    ao_task.start()
    do_task.start()
    input("press stop")
    ao_task.stop()
    do_task.stop()
0 Kudos
Message 1 of 3
(53 Views)

What's missing is that you need to sync the tasks to start at the same time.  Right now there's an offset due to the execution time needed to get the tasks started under software timing control.  You need to sync their start times via hardware instead.

 

Because both your tasks are on the same device, a "start trigger" will be sufficient.  My recommendation: configure both tasks for a start trigger from one of the PFI terminals that serves double duty as a DIO line.  Then even after the software calls to start the tasks, signals won't start generating your waveforms until the hardware trigger signal asserts.

 

You can control the trigger with a separate DO task that you'll start *after* starting the other two tasks.  A quick toggle high and low will make your AO and your other DO get started in sync.  The fact that they're on the same device means that they derive their sample clock from the same internal clock so they'll *stay* in sync.  (This wouldn't be true if they were on different devices.  Small tolerances in clock frequency would make them drift apart over time.  A pretty common clock spec would allow an error of about 3 millisec per minute of acquisition.)

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 2 of 3
(26 Views)

Hello,

 

Some indication to port into python the solution explained in previous post:

I note that you are configuring "source" through cfg_samp_clk_timing. If you had 2 or more separate devices and a connection between the 2 through RTSI or PFI, the framework would share the clock from master device to slave device and they would stay in sync (I am doing clock sharing through RTSI). Here you are on same device so works without extra cable

 

To share the start trigger, I am doing:

for slave_task in all_slave_tasks:
   slave_task.triggers.start_trigger.cfg_dig_edge_start_trig("/" + master_task.devices[0].name + "/ai/StartTrigger") # this will be /Dev1/ai/StartTrigger, you need to adapt to your terminal, like ao or do. Well, no do/StartTrigger in https://www.ni.com/docs/en-US/bundle/ni-daqmx/page/termnames.html so ao may need to be the trigger or here is some concept I don't know

 

Then:

for slave_task in all_slave_tasks:

   slave_task.start()

master_task.start()

 

slave_task will start upon receiving master_task trigger

 

 

 

Message 3 of 3
(12 Views)