• 0

Create Single Wave Pulse with Python -- Analog Digital 2


Question

Hi!

My goal is to use the Analog Digital 2 in order to move a piezoelectric via stick slip motion. I want to program this into a python script so that I can move the stage one step, record data for x amount of time, move the stage one step, record data, etc.

In order to do this, I want to output a specific number of sawtooth wave periods (one to two) at a certain frequency.

From these posts (https://forum.digilentinc.com/topic/4084-analog-discovery-2-waveform-generator/ , https://forum.digilentinc.com/topic/2609-how-to-create-one-pulse-via-sdk/#comment-9014), I have figured out how to do this through the GUI. I have also followed the example scripts and can output standing wave forms, just not pulses. So now, I am looking for some guidance in putting these together.

Can you give me some suggestions, advice, or code snippets that might allow me to accomplish this? Are there any functions in the dwf module that might work?

Any help is welcome and appreciated!
Thanks, Harry :)

 

digilentScreenCap

Link to post
Share on other sites

18 answers to this question

Recommended Posts

  • 0

Hi @hgriffin

You can generate pulses like this:
 

dwf.FDwfAnalogOutNodeFunctionSet(hdwf, channel, AnalogOutNodeCarrier, funcRampUp)
dwf.FDwfAnalogOutNodeSymmetrySet(hdwf, channel, AnalogOutNodeCarrier, c_double(100.0) # 100% sawtooth
dwf.FDwfAnalogOutNodeFrequencySet(hdwf, channel, AnalogOutNodeCarrier, c_double(50000.0))
dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1.0))
dwf.FDwfAnalogOutNodeOffsetSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1.0))

dwf.FDwfAnalogOutIdleSet(hdwf, channel, c_int(2)) # 2 = DwfAnalogOutIdleInitial, 1V offset - 1V of ramp amplitude = 0V
dwf.FDwfAnalogOutRunSet(hdwf, channel, c_double(1.0/50000.0)) # for 2 pulses set 2/frequency

# this will run once:
dwf.FDwfAnalogOutRepeatSet(hdwf, channel, c_int(1)) # repeat once

# this will repeat after wait:
dwf.FDwfAnalogOutRepeatSet(hdwf, channel, c_int(0)) # infinite repeat
dwf.FDwfAnalogOutWaitSet(hdwf, channel, c_double(0.5)) # 500ms wait before run

# start:
dwf.FDwfAnalogOutConfigure(hdwf, channel, c_bool(True))

 

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

Hi Attila! Thanks for such a quick response!

This is the code I am running right now. Trying to get one pulse.

from ctypes import *
import time
from dwfconstants import *
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")

#declare ctype variables
hdwf = c_int()
channel = c_int(0)

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

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


if hdwf.value == hdwfNone.value:
    print "failed to open device"
    quit()

dwf.FDwfAnalogOutNodeFunctionSet(hdwf, channel, AnalogOutNodeCarrier, funcRampUp)
#dwf.FDwfAnalogOutNodeSymmetrySet(hdwf, channel, c_double(100.0) # 100% sawtooth
dwf.FDwfAnalogOutNodeFrequencySet(hdwf, channel, AnalogOutNodeCarrier, c_double(50000.0))
dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1.0))
dwf.FDwfAnalogOutNodeOffsetSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1.0))

dwf.FDwfAnalogOutIdleSet(hdwf, channel, c_int(2)) # 2 = DwfAnalogOutIdleInitial, 1V offset - 1V of ramp amplitude = 0V
dwf.FDwfAnalogOutRunSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1.0/50000.0)) # for 2 pulses set 2/frequency

# this will run once:
dwf.FDwfAnalogOutRepeatSet(hdwf, channel, AnalogOutNodeCarrier, c_int(1)) # repeat once

dwf.FDwfDeviceClose(hdwf)

Firstly, the FDwfAnalogOutNodeSymmetrySet throws a syntax error, unsure why.

Also the pulse seems strange. Attached is an image from the oscilloscope I'm using to monitor it. Any thoughts?

Cheers,
Harry

3 5 18 14 52 Office Lens.jpg

Link to post
Share on other sites
  • 0

Hi @hgriffin

I forgot to add the node argument:
dwf.FDwfAnalogOutNodeSymmetrySet(hdwf, channel, AnalogOutNodeCarrier, c_double(100.0) # 100% sawtooth

On device open the analog circuitry is enabled and on close it is disabled, this could lead to the seen spike on the output.
The input/output offsets need about a second to settle.

After device open and before starting the operations wait a bit:
dwf.FDwfDeviceOpen(c_int(-1), byref(hdwf))
# set parameters... 
time.sleep(2)
# start the instrument:
dwf.FDwfAnalogOutConfigure(hdwf, channel, c_bool(True))
# leave the application running until you want to use the device, device close or process exit will stop the device
time.sleep(10)

Link to post
Share on other sites
  • 0

Hello, thanks for the response!

I finally seem to be getting some signal. The waiting time seems to work. However, it isn't the ramp I'm expecting.

I have a couple of further questions though.

I actually don't want an offset. I want the starting voltage to be 0V, ramp up to 1V, then drop back down to 0V. It's easy enough to change the offset in the FDwfAnalogOutNodeOffsetSet function, but I was wondering how the function FDwfAnalogOutIdleSet works, and how it would change if I change the offset or amplitude?

Also, to get it to go back to 0 V after the ramp, we could perhaps run to periods, but I don't see any change in behavior when I change the FDwfAnalogOutRunSet.

Here is my current code:

#defining parameters for wave
dwf.FDwfAnalogOutNodeFunctionSet(hdwf, channel, AnalogOutNodeCarrier, funcRampUp)
dwf.FDwfAnalogOutNodeSymmetrySet(hdwf, channel, AnalogOutNodeCarrier, c_double(100.0)) # 100% sawtooth
dwf.FDwfAnalogOutNodeFrequencySet(hdwf, channel, AnalogOutNodeCarrier, c_double(50000.0))
dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1.0))
dwf.FDwfAnalogOutNodeOffsetSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1))

dwf.FDwfAnalogOutIdleSet(hdwf, channel, c_int(2)) # 2 = DwfAnalogOutIdleInitial, 1V offset - 1V of ramp amplitude = 0V
dwf.FDwfAnalogOutRunSet(hdwf, channel, AnalogOutNodeCarrier, c_double(1/50000.0)) # for 2 pulses set 2/frequency

# this will run once:
dwf.FDwfAnalogOutRepeatSet(hdwf, channel, AnalogOutNodeCarrier, c_int(1)) # repeat once

dwf.FDwfAnalogOutConfigure(hdwf, channel, c_bool(True))

print 'closing...'
for i in range(1, 4):
    print i
    time.sleep(1)
dwf.FDwfDeviceClose(hdwf)


Thanks so much for the timely responses, this is helping a lot!

3 6 18 10 07 Office Lens.jpg

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

Hi @hgriffin

I looks like it was too late for me when I first replied to your question... Sorry for the mistakes.

The Run and Repeat functions have no node argument.
dwf.FDwfAnalogOutRunSet(hdwf, channel, c_double(1/50000.0)) # for 2 pulses set 2/frequency 
dwf.FDwfAnalogOutRepeatSet(hdwf, channel, c_int(1)) # repeat once

Idle output: selects the output while not running (Waiting, Ready, Stopped, or Done states). 
- Initial: The idle output voltage level has the initial waveform value of the current configuration. This depends on the selected signal type, Offset, Amplitude, and Amplitude Modulator configuration. 
- Offset: The idle output is the configured Offset level. 

Take a look at the AnalogOut_Custom.py example for custom waveforms.

Link to post
Share on other sites
  • 0

Thanks for the information, and no problem.

I keep getting this asymptotic increase to the offset voltage, as shown in the image in the above post. Even if I change the function, and try Sine, I get the identical behavior. 

Any thoughts on why this is happening?

If I change the offsets to 0, then I don't seem to get any signal.

Thanks!

Link to post
Share on other sites
  • 0

Hi Attila, this works perfectly! Exactly what I was looking for.

One quick question, in the FunctionSet function, where/how do we define "funcCustom" ? This sawtooth is what I want, but just so I know for future reference.

Thanks so much!
Harry

Link to post
Share on other sites
  • 0

Hi @hgriffin

Here is the custom waveform constructed, which happens to be a sawtooth:
cSamples = 4096
rgdSamples = (c_double*cSamples)()
# samples between -1 and +1
for i in range(0,len(rgdSamples)):
    rgdSamples = 1.0*i/cSamples;

custom function selected:
dwf.FDwfAnalogOutNodeFunctionSet(hdwf, channel, AnalogOutNodeCarrier, funcCustom) 
custom waveform configured:
dwf.FDwfAnalogOutNodeDataSet(hdwf, channel, AnalogOutNodeCarrier, rgdSamples, c_int(cSamples))
 

Link to post
Share on other sites
  • 0

I want to iterate through this single pulse, so I have tried various loops.

However, I can't generate anything after the initial pulse. Does the device have to be opened and closed between each? I've tried looping the whole set up, and just the configure function, but no luck. Any suggestions?

for j in range(1,4):   
    #Setting up the parameters for waveform    
    print "Generating custom waveform..."
    dwf.FDwfAnalogOutNodeEnableSet(hdwf, channel, AnalogOutNodeCarrier, c_bool(True))
    dwf.FDwfAnalogOutNodeFunctionSet(hdwf, channel, AnalogOutNodeCarrier, funcCustom) #Define custom waveform; funcCustom
    dwf.FDwfAnalogOutNodeDataSet(hdwf, channel, AnalogOutNodeCarrier, rgdSamples, c_int(cSamples))  
    dwf.FDwfAnalogOutNodeFrequencySet(hdwf, channel, AnalogOutNodeCarrier, c_double(hzFreq)) #Set frequency attribute in Hz
    dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, channel, AnalogOutNodeCarrier, c_double(4.0)) #Set amplitude attribute in Volts

    dwf.FDwfAnalogOutRunSet(hdwf, channel, c_double(1.0/hzFreq)) # run for 1 periods
    dwf.FDwfAnalogOutWaitSet(hdwf, channel, c_double(1.0/hzFreq)) # wait one pulse time
    dwf.FDwfAnalogOutRepeatSet(hdwf, channel, c_int(1)) # repeat 1 times
    
    print 'Generating pulse in:'
    for k in range(1, 4):
        print 4-k
        time.sleep(k)
   
    print 'pulse no. ' + str(j)
    
    dwf.FDwfAnalogOutConfigure(hdwf, channel, c_bool(True))
    time.sleep(1)
    
print "done."
dwf.FDwfDeviceCloseAll() 
Link to post
Share on other sites
  • 0

Hi atilla, it turns out my scope wasn't sensitive enough to see the quick pulses. It looks like it is working okay now though!

Is there any way to use the scope feature of the Analog Discovery while controlling it via python. Based on what I've seen you can only interface with it one way at a time, but I was wondering if there are any work arounds to use the GUI scope feature while running python scripts? 

Thanks for all the help and timely responses.

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

Hello,

I was looking at the AnalogIn_Acquisition.py example. 

This is a good base for what I want. The goal is to iterate through a list, and average the output (rgpy in example) at each iteration, and store this in a list.

However, I when I try nesting the functions inside lists, it doesn't appear to be reacquiring data. 

How do the AnalogInConfigure and Status work, and how could I acquire data in a loop?

Thanks!

 

for ii in range(0,5):

    #set up acquisition
    dwf.FDwfAnalogInFrequencySet(hdwf, c_double(20000000.0))
    dwf.FDwfAnalogInBufferSizeSet(hdwf, c_int(4000)) 
    dwf.FDwfAnalogInChannelEnableSet(hdwf, c_int(0), c_bool(True))
    dwf.FDwfAnalogInChannelRangeSet(hdwf, c_int(0), c_double(5))
    
    #wait at least 2 seconds for the offset to stabilize

    time.sleep(2)

    #begin acquisition
    dwf.FDwfAnalogInConfigure(hdwf, c_bool(False), c_bool(True))
    print "   waiting to finish"
    
    while True:
        dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
        print "STS VAL: " + str(sts.value) + "STS DONE: " + str(DwfStateDone.value)
        if sts.value == DwfStateDone.value :
            break
        time.sleep(0.1)
    print "Acquisition finished"
    
    dwf.FDwfAnalogInStatusData(hdwf, 0, rgdSamples, 4000) # get channel 1 data
    #dwf.FDwfAnalogInStatusData(hdwf, 1, rgdSamples, 4000) # get channel 2 data
    dwf.FDwfDeviceCloseAll()
    
    #plot window
    dc = sum(rgdSamples)/len(rgdSamples)
    print "DC: "+str(dc)+"V"
    
    rgpy=[0.0]*len(rgdSamples)
    for i in range(0,len(rgpy)):
        rgpy[i]=rgdSamples[i]

    rg_slice = rgpy
    buffer = len(rg_slice) / 4
    
    del rg_slice[buffer*4 - buffer:buffer*4] 
    del rg_slice[0:buffer]
    voltage = sum(rg_slice) / len(rg_slice)
    print voltage
Link to post
Share on other sites
  • 0

Hi @hgriffin

Notice that you have included the device close function in the loop, so in the first iteration the device will be closed and further iterations will fail...
See the AnalogIn_Trigger.py for multiple acquisitions.

print "   starting repeated acquisitions"

# begin acquisition
dwf.FDwfAnalogInConfigure(hdwf, c_bool(False), c_bool(True))

for iTrigger in range(1,101):
    # new acquisition is started automatically after done state 

    while True:
        dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
        if sts.value == DwfStateDone.value :
            break
        time.sleep(0.001)
    
    dwf.FDwfAnalogInStatusData(hdwf, 0, rgdSamples, 8192) # get channel 1 data
    #dwf.FDwfAnalogInStatusData(hdwf, 1, rgdSamples, 8192) # get channel 2 data
    
    dc = sum(rgdSamples)/len(rgdSamples)
    print "Acquisition #"+str(iTrigger)+" average: "+str(dc)+"V"

 

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