• 0

Triggering Analog Channels on AD2


Question

I am trying to trigger the AD2 analog channels.   I am having great difficulty surpassing 500 trigger events per second.  I'm working with Python 3.7 to 3.9.  I am working on a Windows 10 Pro PC with 8 GB of RAM.    The amount of data seems not to be the issue (only about a 1000 samples per trigger event).   It seems more to do with the re-arming time or reading the done status.

I tried the sample script AnalongIn_Trigger.py, and modified it with a digital out signal as the input trigger to the analog channel.   About 500 triggers a second was the maximum it could do.   I tried so many variations on this that they are too numerous to show here.   Since external triggering did not work for Analog channels, I thought maybe I would play with the digital side more.  I then tried using the AnalogInDigitalIn_Acquistion.py script.   See the changes I made below.   I attempted to obtain 4000 trigger per second rate.    I got 350 triggers per second -- worse overall than the Analog-only Trigger.

Is there anything I can do to speed up the trigger rate?   In the example code below, if I throw away the digital data (which I don't need) and set the second parameter in dwf.FDwfDigitalInStatus to 0 (dwf.FDwfDigitalInStatus(hdwf, c_int(0), byref(sts)) ), I get a speed up to about 500 triggers per second.    If I set the second parameter of dwf.FDwfAnalogInStatus to 0, I get to about 1400 triggers per second.  But the data is nonsense on the Analog channel -- a bunch of noisy spikes.      So I can't use that setting.  

I also found that when I set the triggers to over 500 triggers per second (for example, to 2000 or 4000), my triggering time is not consistent in the AD2.  I thought I might get a consistent 0.002 seconds when the triggering rate max'ed out, but it is not.   The trigger intervals fluctuate all over the place.      So bottom line, I can't get even a 500 trigger per second performance at a consistent periodic value.  This means I can't take FFT's on the data collected over time, which is used in Doppler processing.

Does anyone know what the maximum trigger rate of the AD2 is?    If that is greater than 500 triggers/s, what do I do to maximize trigger rates through code?    Can the code below be improved?    

Sorry for the novella, but I've invested a lot of time in this and was trying to be thorough.

Modified AnalogInDigitalIn_Acquisition.py:

from ctypes import *
import math
import time
import matplotlib.pyplot as plt
import sys

if sys.platform.startswith("win"):
    dwf = cdll.dwf
elif sys.platform.startswith("darwin"):
    dwf = cdll.LoadLibrary("/Library/Frameworks/dwf.framework/dwf")
else:
    dwf = cdll.LoadLibrary("libdwf.so")

hdwf = c_int()
sts = c_byte()
cSamples = 1200
rgdAnalog = (c_double*cSamples)()
rgwDigital = (c_uint16*cSamples)()

version = create_string_buffer(16)
dwf.FDwfGetVersion(version)
print("DWF Version: "+str(version.value))

#open device
print("Opening first device")
dwf.FDwfDeviceOpen(c_int(-1), byref(hdwf))

if hdwf.value == 0:
    szerr = create_string_buffer(512)
    dwf.FDwfGetLastErrorMsg(szerr)
    print(str(szerr.value))
    print("failed to open device")
    quit()


print("Generating signal on DIO 0")
# generate on DIO-0 25khz pulse (100MHz/10000/(7+3)), 30% duty (7low 3high)    
dwf.FDwfDigitalOutEnableSet(hdwf, c_int(0), c_int(1))    
dwf.FDwfDigitalOutDividerSet(hdwf, c_int(0), c_int(20))   #<--Note that this row and the next yields a 200 ns pulse @ 4000 times per sec
dwf.FDwfDigitalOutCounterSet(hdwf, c_int(0), c_int(1249), c_int(1))
dwf.FDwfDigitalOutConfigure(hdwf, c_int(1))


# For synchronous analog/digital acquisition set DigitalInTriggerSource to AnalogIn, start DigitalIn then AnalogIn

# configure DigitalIn
dwf.FDwfDigitalInTriggerSourceSet(hdwf, c_ubyte(4)) # trigsrcAnalogIn
#sample rate = system frequency / divider, 100MHz/1
dwf.FDwfDigitalInDividerSet(hdwf, c_int(1))
# 16bit per sample format
dwf.FDwfDigitalInSampleFormatSet(hdwf, c_int(16))
# set number of sample to acquire
dwf.FDwfDigitalInBufferSizeSet(hdwf, c_int(cSamples))
dwf.FDwfDigitalInTriggerPositionSet(hdwf, c_int(int(cSamples/2))) # trigger position in middle of buffer

# configure AnalogIn
dwf.FDwfAnalogInFrequencySet(hdwf, c_double(1e8))
dwf.FDwfAnalogInBufferSizeSet(hdwf, c_int(cSamples)) 
dwf.FDwfAnalogInTriggerPositionSet(hdwf, c_double(0)) # trigger position in middle of buffer
dwf.FDwfAnalogInChannelEnableSet(hdwf, c_int(0), c_bool(True))
dwf.FDwfAnalogInChannelOffsetSet(hdwf, c_int(0), c_double(-2.0))
dwf.FDwfAnalogInChannelRangeSet(hdwf, c_int(0), c_double(5.0))

#trigger on digital signal
dwf.FDwfAnalogInTriggerSourceSet(hdwf, c_byte(3)) # trigsrcDetectorDigitalIn
dwf.FDwfDigitalInTriggerSet(hdwf, c_int(0), c_int(0), c_int(1), c_int(0)) # DIO-0 rising edge

# trigger on analog signal
##dwf.FDwfAnalogInTriggerSourceSet(hdwf, c_byte(2)) # trigsrcDetectorAnalogIn
##dwf.FDwfAnalogInTriggerTypeSet(hdwf, c_int(0)) # trigtypeEdge
##dwf.FDwfAnalogInTriggerChannelSet(hdwf, c_int(1)) # first channel
##dwf.FDwfAnalogInTriggerLevelSet(hdwf, c_double(1.5)) # 1.5V
##dwf.FDwfAnalogInTriggerConditionSet(hdwf, c_int(0))  # trigcondRisingPositive

#wait at least 2 seconds for the offset to stabilize
time.sleep(2)

# start DigitalIn and AnalogIn
dwf.FDwfDigitalInConfigure(hdwf, c_int(True), c_int(True))   #Set 2nd param to True to reset Auto trigger timeout
dwf.FDwfAnalogInConfigure(hdwf, c_int(True), c_int(True))   #Set 2nd param to True to reset Auto trigger timeout

iTrigger = 0
StartT=time.time()
for iTrigger in range(128):
    while True:
        #time.sleep(1)
        dwf.FDwfDigitalInStatus(hdwf, c_int(1), byref(sts))
        if sts.value == 2 : # done
           dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
           break

    # read data
    #dwf.FDwfDigitalInStatusData(hdwf, rgwDigital, c_int(sizeof(c_uint16)*cSamples)) 
    dwf.FDwfAnalogInStatusData(hdwf, c_int(0), rgdAnalog, c_int(cSamples)) # get channel 1 data
    #dwf.FDwfAnalogInStatusData(hdwf, 1, rgdAnalog, cSamples) # get channel 2 data

EndT = time.time()
DeltaT=EndT-StartT
print('Delta Time = ', DeltaT)
print('Measured PRF = ', 128/DeltaT)

 

Link to post
Share on other sites

3 answers to this question

Recommended Posts

  • 0

Hi @eradarhughes

You should not call FDwfAnalogInStatus again when done. This would be required only if you called it previously with argument 0 (do not read data) but this double call would increase the latency.

See the: AnalogIn_Trigger.py For maximum performance use:

...
    while True:
        dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
        if sts.value == DwfStateDone.value :
            break
    
    dwf.FDwfAnalogInStatusData(hdwf, 0, rgdSamples, ...

I've just measure and on my laptop I get about 800 acquisitions / sec in average, 1.2ms/capture.
The latency between captures depends on the congestion of USB, other running application and services may cause periodic lags.
Connecting the AD2 directly to the computer (root hub) should give better result than with external hub, and there could be difference in computer ports too (which may use different controllers).

Link to post
Share on other sites
  • 0

Thanks for the quick reply.    

I wasn't calling it twice, but that doesn't matter.   You did answer the question on speed.   I can't get anywhere close to your 800 per second.   It is hard to believe that its the USB since I'm only transferring KB/S.   I get the same result with any number of data captures.   

However, I did try setting up 8192 samples and lowered the sampling rate.    I could capture continuously and then download and sort the data into trigger arrays.     Unfortunately the short memory depth makes this approach unusable as I can't still collect enough triggers.       By my calculations, I need 100,000 samples.    I looked up the Analog Discovery Pro 3000 and it appears to have a memory depth of 128 M samples in record mode and 32k samples in repeat mode.    Even 32k would be useful.   Does the SDK allow 32k memory samples to be stored for the AD Pro?

Edited by eradarhughes
Link to post
Share on other sites
  • 0

Hi @eradarhughes

Right, you are calling Analog and DigitalInStatus, not Analog twice.

The bottleneck is mostly with the latency and not with the bandwidth.
In my earlier test I got 1.25ms/analog-acquisition (800Hz) on average. Calling analog+digital would probably be around 2.5ms (400Hz)

I've just tested ADP3450, the analog-acquisition over USB with 32ksamples is about 8ms, 64ksamples is about 14.5ms
Over Gb Ethernet 4.4ms w 32kS and 8.3ms w 64kS.
Currently the capture data for all channels are fetched (like 32k*4Ch), I will optimize this method in the near future.

On the other hand ADP can record 128M samples at up to 125MHz on one channel.
The device can also be used in embedded Linux mode with higher transfer rate and lower latency.

 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now