Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Python - Force same Clock between two different device

Hello to all of you,

 

I have developed some small python codes allowing me to acquire signals.

I transmit one pusle per second at a sampling frequency of 44100 Hz using a SCB68A box and I record in parallel using two NI 44-98 cards mounted on a PXI 10 33 chassis.

 

I realize that my pules are shifting by one sample every 3 seconds, which is an important source of error in the field in which I work.

I think that the problem comes from a shift between the two sampling frequencies and that little by little my signals are shifting by half an index.

 

I can't figure out how to set the same time line between my two instruments; the doc is quite complicated about this;

 

An example of a script:


samplerate, data1 = wavfile.read('E:\Source/Ricker_alon.wav')
samplerate, data2 = wavfile.read('E:\Source/Ricker_alon.wav')
data1 = data1.astype('float64')
data1=data1/np.amax(abs(data1))
data2 = data2.astype('float64')
data2=data2/np.amax(data2)
data2=data1.copy()
D=np.zeros((2,data1.size))
D[0,:]=data1
D[1,:]=data2
cont_mode = AcquisitionType.CONTINUOUS
sampling_freq_in = samplerate # in Hz
buffer_in_size = samplerate*10
bufsize_callback = samplerate
buffer_in_size_cfg = samplerate*10#round(buffer_in_size) *10 # clock configuration * 10 ?
chans_in = 1 # number of chan
refresh_rate_plot = 100000 # in Hz

def cfg_read_task(acquisition):
        acquisition.ai_channels.add_ai_accel_chan("PXI1Slot2/ai0",
        min_val=- 5.0, max_val=5.0,
        units=nidaqmx.constants.AccelUnits(10186),
       sensitivity=sai0,
       sensitivity_units=nidaqmx.constants.AccelSensitivityUnits(12509),
       current_excit_source=nidaqmx.constants.ExcitationSource(10200), #10200
       current_excit_val=0.002)

      acquisition.timing.cfg_samp_clk_timing(rate=sampling_freq_in, sample_mode=constants.AcquisitionType.CONTINUOUS,
      samps_per_chan=buffer_in_size_cfg)

 

def reading_task_callback(task_idx, event_type, num_samples, callback_data):
       global data
       global buffer_in
       if running:
          path=r'E:\Experience\Gaussian_Monitoring/Acc/'
          isExist = os.path.exists(path)
          if not isExist:
             os.makedirs(path)
          buffer_in = np.zeros((chans_in, num_samples)) # double definition ???
          stream_in.read_many_sample(buffer_in, num_samples, timeout=constants.WAIT_INFINITELY)
          data = np.append(data, buffer_in, axis=1) # appends buffered data to total variable data
          filename=path+'Acc_'+str(datetime.now().strftime("%m%d%h%H%M%S%f"))
          extension = '.npy'
          np.save(filename + extension,buffer_in)
          data = np.zeros((chans_in, 1))
          return 0

def cfg_read_task_source(Source):
      D[0,:]=data1
      D[1,:]=data2
      Source.ao_channels.add_ao_voltage_chan('Dev1/ao1:2')
      Source.timing.cfg_samp_clk_timing(rate= samplerate, sample_mode=constants.AcquisitionType.CONTINUOUS , samps_per_chan= buffer_in_size_cfg)
      Source_Writer1 = nidaqmx.stream_writers.AnalogMultiChannelWriter(Source.out_stream, auto_start=False)
      Source_Writer1.write_many_sample(D)

 

 

task_in = nidaqmx.Task()
task_out = nidaqmx.Task()

stream_in = AnalogMultiChannelReader(task_in.in_stream)
cfg_read_task(task_in)
cfg_read_task_source(task_out)

task_in.register_every_n_samples_acquired_into_buffer_event(bufsize_callback, reading_task_callback)
# Start threading to prompt user to stop
thread_user = threading.Thread(target=ask_user)
thread_user.start()
T=str(datetime.now().strftime("%m%d%h%H%M%S%f"))
np.save(r'E:\Experience\Gaussian_Monitoring/Acc/time',T)

# Main loop
running = True
time_start = datetime.now()
task_in.start()
task_out.start()hour_setting=1/60 #5 # time / 60 , time is in min
print('running during ...', 60*60*hour_setting , ' seconds')

while running:
         if (time.time() - start_time)>60*60*hour_setting :
             task_in.close()
             task_out.close()
             sys.exit()


I tried to link the two clocks by options such as :

#Source.triggers.start_trigger.cfg_dig_edge_start_trig("/PXI1Slot2/ai/StartTrigger")

 

#acquisition.timing.ref_clk_src="/Dev1/a0/SampleClock"
#acquisition.timing.ref_clk_rate = 10.0e6

 

or

Source.timing.cfg_samp_clk_timing(rate= samplerate, source="/PXI1Slot2/ai/SampleClock" , samps_per_chan= buffer_in_size_cfg)

 

but i take this error :

No registered trigger lines could be found between the devices in the route.
If you have a PXI chassis, identify the chassis correctly in MAX, and make sure it has been configured properly. If you are using PCI devices, make sure they are connected with a RTSI cable and that the RTSI cable is registered in MAX. Otherwise, make sure there is an available trigger line on the trigger bus shared between the devices.
Source Device: PXI1Slot2
Source Terminal: ai/SampleClock
Destination Device: Dev1
Destination Terminal: ao/SampleClock

 

Is there a way to have the clocks set to the same time line in my case?

 

Thanks for reading

 

 

0 Kudos
Message 1 of 2
(1,077 Views)

I don't know the python syntax, but you're going to need to link your clocks differently.  The methods you're trying depend on DAQmx to auto-route the timing signals from one device to another.  It appears that your AO device is either a desktop or USB device while your AI devices are in a PXI chassis.

    As the error message said, there are *no* inherent timing connections available between them, thus auto-routing cannot succeed.

 

You'll need to do the routing more manually, and it's gonna require physical wiring as well.  You'll need to export from "/Dev1/ao/SampleClock" out to some PFI line on the SCB-68.  They you'll need to physically wire that PFI line (and probably also Dig Gnd) to a chosen PFI line on each of your PXI AI devices.  And then you'll need to configure those AI devices to get their sample clock from those respective PFI lines.

 

By sharing the sample clock signal, you'll maintain sync across all 3 devices.  A trigger alone wouldn't do it.  The 2 PXI devices would stay in sync with one another because both are controlled by a common PXI chassis clock.  But the other device would be free to drift away from them as you've already seen.

 

Note: clock specs are often something like 50 ppm.  1 sample every 3 seconds at 44 kHz corresponds to about 8 ppm.  So yeah, it sure seems like clock accuracy is driving the discrepancy you see.  Sharing a sample clock will lock all the devices into the timing defined by the AO device.  The accuracy spec still holds true, but it won't affect sync.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy coming to an end (finally!). Permanent license pricing remains WIP. Tread carefully.
0 Kudos
Message 2 of 2
(1,069 Views)