element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Personal Blogs
  • Community Hub
  • More
Personal Blogs
Gough Lui's Blog Digilent ADP3450 In-Depth – Ch6: WaveForms SDK for Python
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Gough Lui
  • Date Created: 9 Jan 2022 3:30 AM Date Created
  • Views 3850 views
  • Likes 6 likes
  • Comments 1 comment
  • RoadTest
  • test
  • Mixed Domain Oscilloscope
  • mixed signal oscilloscope
  • analog discovery pro
  • test equipment
  • education
  • mdo
  • ADP3450
  • wavegen
  • ethernet
  • mso
  • usb oscilloscope
  • usb
  • oscilloscope
  • roadtest review
  • test and measurement
  • digilent
  • ethernet oscilloscope
  • review
  • ADP3250
  • lab
  • analog discovery
  • awg
Related
Recommended

Digilent ADP3450 In-Depth – Ch6: WaveForms SDK for Python

Gough Lui
Gough Lui
9 Jan 2022

What makes a piece of test equipment truly useful is the ability to automate measurements. Instead of interactively twiddling knobs and pushing buttons (even if they are on-screen), the ability for the instrument to be controlled through a program or script can be a great time-saver, reducing the chances for error and allowing for measurement regimes that would not otherwise be humanly possible (or time-efficient). To this end, the ADP3450 has the ability to be automated, although instead of using the older and more archaic SCPI standard commands, it has its own SDK and API which supports devices that work with the WaveForms software.

WaveForms SDK

The WaveForms SDK is installed with the main WaveForms package. The SDK consists of the WaveForms Runtime which depends on the DWF Dynamic Library and a number of other configuration files. The SDK supports C, C#, Python and Visual Basic. In the context of the Analog Discovery Pro ADP3450, the SDK works as shown in the block diagram provided in WaveForms Help tab:

image

The WaveForms SDK is documented online in the WaveForms SDK Reference Manual, however, the latest version is a PDF file which is contained within the SDK install folder. The SDK also comes with a number of example files which make it easier to get started with basic tasks. The example files can be found at the following paths depending on your operating system:

  • Windows 32-bit: C:\Program Files\Digilent\WaveFormsSDK\samples
  • Windows 64-bit: C:\Program Files (x86)\Digilent\WaveFormsSDK\samples
  • Linux: /usr/share/digilent/waveforms/samples
  • OS X: /Applications/WaveForms.app/Contents/Resources/SDK/

A list of the included sample files are as follows –

+---c
|       analogin_acquisition.cpp
|       analogin_record.cpp
|       analogin_sample.cpp
|       analogin_trigger.cpp
|       analogio_analogdiscovery2_power.cpp
|       analogio_analogdiscovery2_systemmonitor.cpp
|       analogio_analogdiscovery_power.cpp
|       analogio_analogdiscovery_systemmonitor.cpp
|       analogoutin.cpp
|       analogout_custom.cpp
|       analogout_custom_am.cpp
|       analogout_sine.cpp
|       analogout_sweep.cpp
|       analogout_sync.cpp
|       device_enumeration.cpp
|       digitalin_acquisition.cpp
|       digitalin_record.cpp
|       digitalio.cpp
|       digitalout_binarycounter.cpp
|       digitalout_phase.cpp
|       digitalout_pins.cpp
|       digitalout_walking1.cpp
|       readme.txt
|       sample.h
|       
+---cs
|       dwf.cs
|       
+---dwfcmd
|       analogin.txt
|       analoginout.txt
|       analoginoutcustom.txt
|       analoginoutsync.txt
|       analogintrigger.txt
|       analogplay.txt
|       analogplay2.txt
|       analogplayrecord.txt
|       analogrecord.txt
|       analogrecordoutsine.txt
|       dwfcmd.cpp
|       dwfcmd.exe
|       
+---py
|       AnalogImpedance_Analyzer.py
|       AnalogImpedance_Compensation.py
|       AnalogImpedance_Input.py
|       AnalogImpedance_Measure.py
|       AnalogImpedance_Meter.py
|       AnalogImpedance_OffsetSweep.py
|       AnalogImpedance_OffsetSweepCp.py
|       AnalogImpedance_ThinkSpeak.py
|       AnalogInDigitalIn_Acquisition.py
|       AnalogIn_Acquisition.py
|       AnalogIn_Logger.py
|       AnalogIn_Record.py
|       AnalogIn_Record1.py
|       AnalogIn_Record_int16.py
|       AnalogIn_Record_Trigger.py
|       AnalogIn_Record_Trigger_int16.py
|       AnalogIn_Record_Wave_Mono.py
|       AnalogIn_Sample.py
|       AnalogIn_ShiftScreen.py
|       AnalogIn_Trigger.py
|       AnalogIO_ADP5250_DMM.py
|       AnalogIO_AnalogDiscovery2_Power.py
|       AnalogIO_AnalogDiscovery2_SystemMonitor.py
|       AnalogIO_AnalogDiscovery_Power.py
|       AnalogIO_AnalogDiscovery_SystemMonitor.py
|       AnalogIO_DigitalDiscovery.py
|       AnalogIO_ElectronicsExplorer.py
|       AnalogNetwork_Analyzer.py
|       AnalogOutIn.py
|       AnalogOutIn_PlayRecord.py
|       AnalogOutIn_PlayRecordStereo.py
|       AnalogOutIn_Synchronization.py
|       AnalogOut_Custom.py
|       AnalogOut_Pattern.py
|       AnalogOut_Phase.py
|       AnalogOut_Play.py
|       AnalogOut_Pulse.py
|       AnalogOut_Sine.py
|       AnalogOut_Sweep.py
|       AnalogOut_Sync.py
|       Analog_Transistor.py
|       Device_Enumeration.py
|       Device_Info.py
|       Device_InfoEx.py
|       Device_Speed.py
|       Device_Synchronization.py
|       DigitalDiscovery_Play.py
|       DigitalDiscovery_PlayRecord.py
|       DigitalDiscovery_RecordToFile.py
|       DigitalDiscovery_RecordToFile16.py
|       DigitalIn_Acquisition.py
|       DigitalIn_Acquisition_8x100k.py
|       DigitalIn_Acquisition_8x256M.py
|       DigitalIn_PulseTrigger.py
|       DigitalIn_Record.py
|       DigitalIn_Record_Compress.py
|       DigitalIn_Spi_Spy.py
|       DigitalIn_Sync.py
|       DigitalIn_Trigger.py
|       DigitalIO.py
|       DigitalOut_BinrayCounter.py
|       DigitalOut_Clock.py
|       DigitalOut_Custom.py
|       DigitalOut_CustomBus.py
|       DigitalOut_Duty.py
|       DigitalOut_Phase.py
|       DigitalOut_Pins.py
|       DigitalOut_Pulse.py
|       DigitalOut_ResetPattern.py
|       DigitalOut_ROM_Mux.py
|       DigitalOut_SPI.py
|       Digital_Can.py
|       Digital_I2c.py
|       Digital_I2c_PmodAcl.py
|       Digital_I2c_PmodGyro.py
|       Digital_I2c_Spy.py
|       Digital_Spi.py
|       Digital_Spi_Dual.py
|       Digital_Spi_Quad.py
|       Digital_Spi_Siso.py
|       Digital_Spi_Spy.py
|       Digital_Spi_Spy_DD.py
|       Digital_Uart.py
|       Digital_Uart_RX.py
|       dwfconstants.py
|       Enumerate.py
|       
\---vb
        dwf.vb

WaveForms SDK for Python

As Python is amongst my favourite programming languages and seeing the sheer number of Python examples, I felt it most appropriate that I use the SDK to automate the testing that would be required for the following applications and instrument performance chapters.

My Experience with the SDK

Getting started with a new SDK can be a very daunting experience as it’s like trying to learn how to walk all over again, especially if you already know SCPI as this does not follow such conventions. I feel that the use of the SDK rather than SCPI is likely to be related to the hardware itself and can have some benefits in terms of performance. To learn to use the SDK effectively requires quite a bit of time commitment, or furious reference to examples and the reference manual punctuated by repeated head-scratching moments, as I had myself experienced. However, I also feel it to be a missed opportunity to have users learn a useful programming language of SCPI that would help them work with many other instruments from “big-box” vendors and is a standard of its own. Working with this SDK limits you to WaveForms-compatible devices from Digilent, but perhaps they see this as a way to maintain a form of competitive advantage in the form of vendor lock-in.

Some of the head-scratching I experienced had to do with the accuracy of the documentation – for example:

image

It seems that the authors may have confused dwf with dfw and thus introduce an inconsistency in the table. In other cases, while functions are listed in the document along with their arguments, the expected values for the arguments or valid values that can be supplied to these arguments are missing, thus causing some confusion. In some cases, one must use a specific read/enumerate function first to understand what the hardware is capable of and then write the appropriate value, but this is not something that is demonstrated by much of the example code. Some of the example code is also hardware-specific, thus will not run on the ADP3450.

image image

One confusion I had was simply how to configure the digital bus voltage (which is the only “power supply” the ADP3450 has). I looked up the reference and found that the node and channel definitions for the ADP3450 were not included in the online documentation.

image

I ended up guessing the value, however, it was only later that I realised that the online version of the reference manual was not the most up-to-date. Instead, a PDF document is provided with the SDK that had this information included. The inconsistency in documentation across sources was confusing, especially as the reference manual and tutorials for the ADP3450 were available only from the website and not as downloadable PDFs.

image

Some of the examples also had subtle errors, for example in the AnalogIO Pattern and Custom examples, line 30 in this case seems to be missing a print function declaration – I suspect they meant print(“Opening first device…”) as the current code doesn’t seem to be valid. While looking through the examples, I did find some variations in the code which initialises the device as some perform more diagnostic printing than others, but the examples could have been better documented to aid understanding. This is probably best illustrated by looking at a typical code example from the SDK.

Examining an Example: AnalogIn_Record.py

Below is the code for one of the examples, AnalogIn_Record.py as provided by Digilent.

"""
   DWF Python Example
   Author:  Digilent, Inc.
   Revision:  2018-07-19

   Requires:                       
       Python 2.7, 3
"""

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

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()
sts = c_byte()
hzAcq = c_double(100000)
nSamples = 200000
rgdSamples = (c_double*nSamples)()
cAvailable = c_int()
cLost = c_int()
cCorrupted = c_int()
fLost = 0
fCorrupted = 0

#print(DWF version
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 == hdwfNone.value:
    szerr = create_string_buffer(512)
    dwf.FDwfGetLastErrorMsg(szerr)
    print(str(szerr.value))
    print("failed to open device")
    quit()

print("Generating sine wave...")
dwf.FDwfAnalogOutNodeEnableSet(hdwf, c_int(0), AnalogOutNodeCarrier, c_bool(True))
dwf.FDwfAnalogOutNodeFunctionSet(hdwf, c_int(0), AnalogOutNodeCarrier, funcSine)
dwf.FDwfAnalogOutNodeFrequencySet(hdwf, c_int(0), AnalogOutNodeCarrier, c_double(1))
dwf.FDwfAnalogOutNodeAmplitudeSet(hdwf, c_int(0), AnalogOutNodeCarrier, c_double(2))
dwf.FDwfAnalogOutConfigure(hdwf, c_int(0), c_bool(True))

#set up acquisition
dwf.FDwfAnalogInChannelEnableSet(hdwf, c_int(0), c_bool(True))
dwf.FDwfAnalogInChannelRangeSet(hdwf, c_int(0), c_double(5))
dwf.FDwfAnalogInAcquisitionModeSet(hdwf, acqmodeRecord)
dwf.FDwfAnalogInFrequencySet(hdwf, hzAcq)
dwf.FDwfAnalogInRecordLengthSet(hdwf, c_double(nSamples/hzAcq.value)) # -1 infinite record length

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

print("Starting oscilloscope")
dwf.FDwfAnalogInConfigure(hdwf, c_int(0), c_int(1))

cSamples = 0

while cSamples < nSamples:
    dwf.FDwfAnalogInStatus(hdwf, c_int(1), byref(sts))
    if cSamples == 0 and (sts == DwfStateConfig or sts == DwfStatePrefill or sts == DwfStateArmed) :
        # Acquisition not yet started.
        continue

    dwf.FDwfAnalogInStatusRecord(hdwf, byref(cAvailable), byref(cLost), byref(cCorrupted))
    
    cSamples += cLost.value

    if cLost.value :
        fLost = 1
    if cCorrupted.value :
        fCorrupted = 1

    if cAvailable.value==0 :
        continue

    if cSamples+cAvailable.value > nSamples :
        cAvailable = c_int(nSamples-cSamples)
    
    dwf.FDwfAnalogInStatusData(hdwf, c_int(0), byref(rgdSamples, sizeof(c_double)*cSamples), cAvailable) # get channel 1 data
    #dwf.FDwfAnalogInStatusData(hdwf, c_int(1), byref(rgdSamples, sizeof(c_double)*cSamples), cAvailable) # get channel 2 data
    cSamples += cAvailable.value

dwf.FDwfAnalogOutReset(hdwf, c_int(0))
dwf.FDwfDeviceCloseAll()

print("Recording done")
if fLost:
    print("Samples were lost! Reduce frequency")
if fCorrupted:
    print("Samples could be corrupted! Reduce frequency")

f = open("record.csv", "w")
for v in rgdSamples:
    f.write("%s\n" % v)
f.close()
  
plt.plot(numpy.fromiter(rgdSamples, dtype = numpy.float))
plt.show()


As a rather typical example of the code provided, I felt that the examples had limited amounts of commenting and used a number of magic number values which makes the code less easily understood. Looking up references for the FDwf functions is almost mandatory if the user is to understand what each argument value actually means, and even then, some of these values do not seem to be well documented in the reference. The code seems to require the use of ctypes, thus values are all wrapped with their corresponding C type declarations, thus making things a little more cluttered and unpythonic. Some examples also require a number of libraries, some hefty, to be installed for the full experience – this one, for example, expects matplotlib and numpy. There are occasional formatting or comment typographical errors as well suggesting that these examples may have been quickly compiled, although the sheer number of examples is definitely appreciated. Not all examples will run on the ADP3450 because of the hardware-specific limitations and also because of differences in the hardware values used in certain functions (e.g. AnalogIO Node/Channel Numbers).

Conclusion

The WaveForms SDK makes the ADP3450 a much more useful and versatile instrument. By enabling the possibility to automate the instrument through programs interfacing with the WaveForms SDK, it becomes possible to automate processes which would otherwise take lots of time to manually achieve. The SDK is automatically installed with every installation of WaveForms and supports C, C#, Python and Visual Basic.

It should be noted that their SDK is quite different compared to traditional SCPI commands and VISA automation, being a set of functions which are hardware-specific to WaveForms-compatible hardware. This may have advantages in terms of performance and ease of implementation, but I also feel it to be a missed opportunity to teach users the “standardised” SCPI as used by big-box instruments and may represent an element of vendor lock-in.

My experience with the SDK was aided greatly by the number of Python-based examples which covered many use cases, thus allowing more rapid implementation of programs that combine both WaveForms SDK equipment and SCPI-standard equipment in later experiments. Considering that I have never explored the WaveForms SDK, the learning curve was not too bad. Unfortunately, the documentation did have some minor inconsistencies with the online version of the SDK Reference Manual missing data relevant to the ADP3450 which was present only in the PDF document version of the reference. The sample code did occasionally contain errors, some files are hardware-specific, but all had limited comments and magic numbers scattered in the code, requiring furious reference to the documentation to understand the specific configuration value which is used. At times, these values are not as well documented in the reference as desired, leading to some experimentation being necessary. I also found that the SDK features heavy use of ctypes variables due to the interfacing with a (presumably) C-based library, which makes for unpythonic code clutter. Some examples also require the installation of some hefty libraries such as matplotlib and numpy to run.

However, it is still undoubtedly a very powerful API to have as it allows for the same code to automate the ADP3450, whether run “on-device” in Linux Mode, on host connected via USB, Ethernet or Wi-Fi without any changes. I found the performance of the API to be stable for the simple experiments I have conducted.

---

This post is a part of the Digilent Analog Discovery Pro ADP3450 USB/Ethernet Mixed Signal Oscilloscope RoadTest Review.

  • Sign in to reply
  • DAB
    DAB over 3 years ago

    Nice honest assessment of the SDK.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube