Question

I am trying to find the script commands to access the Spectrum Analyzer in the Analog Discovery 2. I would like to specifically access the THD function to read a series of values at different frequencies (using the Wavegen), plot them and save them to a file. I am generally familiar with the use of scripts and have made them work on the scope, wavegen, etc. but cannot seem to find the commands to access the Spectrum Analyzer in Waveforms 2015. I have also used the debug function as well as the plot function so what I need are the specific access routines for the spectrum analyzer and its subfunctions (like THD, SNR, etc.)

Share this post


Link to post
Share on other sites

16 answers to this question

Recommended Posts

  • 0
On 8/28/2017 at 3:08 AM, attila said:

Hi @abzza @tomtektest

With WF 3.6.8 you can access Spectrum measurements, like:

print(Spectrum1.Trace1.measureFreq("FF")+" Hz") // fundamental frequency
print(Spectrum1.Trace1.measure("FF")+" dBV") // magnitude
print(Spectrum1.Trace1.measure("THD")+" dBc") // total harmonic distortion

Excellent, thank you!

@tomtektest - I'm working on a Python script to at least do some basic automation of THD analysis across the 20hz-20khz spectrum. It won't be as pretty as the Audio Analyzer Suite, but it will get the job done. Will send it to you when it's ready to go!

Share this post


Link to post
Share on other sites
  • 0
6 hours ago, abzza said:

Excellent, thank you!

@tomtektest - I'm working on a Python script to at least do some basic automation of THD analysis across the 20hz-20khz spectrum. It won't be as pretty as the Audio Analyzer Suite, but it will get the job done. Will send it to you when it's ready to go!

I'm glad to see someone working on this; please keep us informed of your progress. I have not yet found a list of the new SA commands in 3.6.8, have you found them? I also look forward to seeing your script and would appreciate getting a copy (or access to it through the Digilent Forum) I have experience (commercial with languages like Java Script but have only used Python in small applications to help my granddaughters with some Raspberry Pi projects.

Share this post


Link to post
Share on other sites
  • 0

Hi @tomtektest, @abzza

With WaveForms Script THD and other measurement logging and plotting can be automated, like this:

i1.thumb.png.fb3fee13e1cbab2218dc54ae72bd0a47.png

function doTHD(){
    var rgTHD = []
    var rgFreq = []
    for(var idx = 1; idx <= 100; idx++){
       Wavegen1.Channel1.Simple.Frequency.value = 1000*idx
       Wavegen1.run() // start AWG
       wait(0.01) // settle time for the external circuit, expressed in seconds
       Spectrum1.Frequency.Stop.value = 20*Wavegen1.Channel1.Simple.Frequency.value // adjust analyzer stop frequency
       Spectrum1.single() // start acquisition
       if(!Spectrum1.wait()){ // wait to finish
          return;
       }
       rgFreq.push(Spectrum1.Trace1.measureFreq("FF"))
       rgTHD.push(Spectrum1.Trace1.measure("THD"))
    }
    Wavegen1.stop()
    print(rgFreq, rgTHD) // print data for copy paste
    // draw in plot1, View / Add plot
    plot1.X.Units.text = "Hz"
    plot1.Y1.Units.text = "dBc"
    plot1.X.data = rgFreq
    plot1.Y1.data = rgTHD
}
doTHD();

 

Edited by attila

Share this post


Link to post
Share on other sites
  • 0

My question is for attila, I tried your script, and it appears to work, but...

I chose linear db average with a count of 10 for the spectrum traces, but your script behaves like in sample mode, it takes the first reading only.

Is there a way to modify the wait sequence so that the spectrum does the 10 measurement and averaging?

Share this post


Link to post
Share on other sites
  • 0

Hi, i modified attila script slightly so that the thd values are in % and the range is in the usual audio band.

Hope it could be useful for others.

 

function doTHD(){

var rgTHD = []

var rgFreq = []

for(var idx = 20; idx <= 20000; idx+=19980/30){

Wavegen1.Channel1.Simple.Frequency.value = idx

Wavegen1.run() // start AWG

wait(0.01) // settle time for the external circuit, expressed in seconds

Spectrum1.Frequency.Stop.value = 20*Wavegen1.Channel1.Simple.Frequency.value // adjust analyzer stopfrequency

 

Spectrum1.single() // start acquisition

if(!Spectrum1.wait()){ // wait to finish

return;

}

rgFreq.push(Spectrum1.Trace1.measureFreq("FF"))

rgTHD.push(100*Math.pow(10,Spectrum1.Trace1.measure("THD")/20))

}

Wavegen1.stop()

print(rgFreq, rgTHD) // print data for copy paste

// draw in plot1, View / Add plot

plot1.X.Units.text = "Hz"

plot1.Y1.Units.text = "%"

plot1.X.data = rgFreq

plot1.Y1.data = rgTHD

}

doTHD();

Share this post


Link to post
Share on other sites
  • 0

Thanks @BaffleChallenged - I did much the same, although I incremented the script 1hz at a time for 20000 readings across the spectrum:

for(var idx = 20; idx <= 20000; idx++) // 20hz to 20khz, 1hz increments

The script takes about ~10 minutes to complete. Here was the output from a little LM1875 chip kit driving an 8 ohm dummy load. Neat! This was before I added the conversion from dB to % for THD (thanks this website for the explanation!), but it worked out to an average of -62dB, or 0.079% THD. Not too shabby for an eBay kit running in the open air.

Another useful addition I added was to average all the THD values to give you a single value to compare against, as well as formatting the output into something more CSV friendly in case the results need to be saved and plotted elsewhere. I'll upload my script changes as well when I'm back at my laptop.

Test-Setup.jpg

Screen---THD-Graph.jpg

Share this post


Link to post
Share on other sites
  • 0

here is another version of the script i am working on,

it does both channel

it does scale the frequencies logarithmically

it does the averaging if trace 1 type allows count to be enabled.

it saves to a desktor CSV file for data manipulation in a speadsheet.

 

 

//taken from https://stackoverflow.com/questions/846221/logarithmic-slider

// and modified to suit my needs
function logslider(position, maxp) {
  // position will be between 0 and 100
  var minp = 0;
  //var maxp = 50;

  // The result should be between 100 an 10000000
  var minv = Math.log(20);
  var maxv = Math.log(20000);

  // calculate adjustment factor
  var scale = (maxv-minv) / (maxp-minp);

  return Math.exp(minv + scale*(position-minp));
}
function doTHD(){
    var freq
    var slices =30
    var rgTHD1 = []
    var rgTHD2 = []
    var rgFreq = []
    for(var idx = 0; idx <= slices; idx++){
      freq = logslider(idx, slices)
       Wavegen1.Channel1.Simple.Frequency.value = freq
       //Wavegen1.run() // start AWG
       Wavegen1.Channel2.Simple.Frequency.value = freq

       Wavegen1.run() // start AWG
       wait(0.01) // settle time for the external circuit, expressed in seconds
       Spectrum1.Frequency.Start.value = freq // adjust analyzer start frequencyTool
       Spectrum1.Frequency.Stop.value = 10*freq // adjust analyzer stop frequencyTool
       if(Spectrum1.Trace1.Config.Count.enable==true)
       {
            print ("averaging is enable");
            var avg = 0
            var avg2 = 0
            for (i=0;i<Spectrum1.Trace1.Config.Count.value;i++)
            {
                Spectrum1.single() // start acquisition
                if(!Spectrum1.wait()){ // wait to finish
                   return;
            }
            avg += Spectrum1.Trace1.measure("THD")
            avg2 += Spectrum1.Trace2.measure("THD")
         }
          avg /= Spectrum1.Trace1.Config.Count.value
          avg2 /= Spectrum1.Trace1.Config.Count.value
          rgTHD1.push(100*Math.pow(10,avg/20))
          rgTHD2.push(100*Math.pow(10,avg2/20))
       }
       else
       {
          Spectrum1.single() // start acquisition
          if(!Spectrum1.wait()){ // wait to finish
             return;
          }
          rgTHD1.push(100*Math.pow(10,Spectrum1.Trace1.measure("THD")/20))
       //rgFreq.push(Spectrum1.Trace2.measureFreq("FF"))
          rgTHD2.push(100*Math.pow(10,Spectrum1.Trace2.measure("THD")/20))
          
        }
          rgFreq.push(Spectrum1.Trace1.measureFreq("FF"))

    }
    Wavegen1.stop()
    print(rgFreq, rgTHD1, rgTHD2) // print data for copy paste
    var file = File("~/Desktop/THDvsFreq.csv")
    file.appendLine("Freq,THDN CH1, THDN ch2")
    for (i=0;i<= slices;i++)
       {file.appendLine(rgFreq+","+rgTHD1+","+rgTHD2)}
    // draw in plot1, View / Add plot
    
    plot1.X.Units.text = "Hz"
    plot1.Y1.Units.text = "%"
    plot1.Y2.Units.text = "%"
    plot1.X.data = rgFreq
    plot1.Y1.data = rgTHD1
    plot1.Y2.data = rgTHD2
    plot1.update()

}
doTHD();

thd1watt.bmp

THD_vs_Power.dwf3script

THD_vs_Freq_%.dwf3script

Edited by BaffleChallenged

Share this post


Link to post
Share on other sites
  • 0

I cannot try this right away, but I appreciate your work and will definitely look more at it in a little while. Keep up the good work and perhaps you could do a video about it at some point and post it on YouTube. Let me know if I can help in any way. I know there are many AD@ users who are looking for something like this for audio testing. tomtektest

 

Share this post


Link to post
Share on other sites
  • 0

Hi tomtektest, I do follow your YouTube channel, I personnaly did not do any video. I do posses a digital photo camera and a tripod, but no editing software. (also note that English is not my primary language)

My interest in audio measurement is sparked from my experiment in amplifier design and build. This script is just one piece of the puzzle. I still miss THD vs power, but that will be trivial to build from the THD vs Freq above, just a few changes i presume.

I do follow a certain sequence, mostly due to setup constraints, and collect information in a spread sheet.

This is still messy at present, it is a work in progress.

If I come with something manageable, perhaps I could make the content puplicly available (spreadsheet, scripts, instructions on setting up and performing measurements).

If you review this content and think it makes senses, perhaps you could do a video on it.

Regards,

Share this post


Link to post
Share on other sites
  • 0

I am very short of spare time at the present, but I intend to do some more videos at some point in the future and this is one of the topics on the list. Thank you for your technical contribution and I look forward to seeing the final result.

Share this post


Link to post
Share on other sites
  • 0

Thanks @attila!

Yeah, I'm using the BNC adapter board and some heavy duty, shielded BNC cables for both the AWG and Scope channels - found much cleaner results overall. Thanks for the heads-up though! Busy putting together a selectable 8ohm/4ohm dummy load that can just plug straight into the Analog Discovery via BNC, which will make testing amplifiers much quicker and easier.

Share this post


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