Posted Tue, 07 Nov 2023 23:25:37 GMT by Jim, Big
Hi guys,

Writing software to control a spectrometer we are building and I'm having trouble getting math command data in from the oscilloscope (DPO7354). 

I have written the math functions (which correct display in the math function group on the oscilloscope thus I know they are being written) as:
scope.write('MATH1:define "avg(CH1)"')
scope.write('MATH2:define "spectralMag(MATH1)"')

then, I set the source channel: 
scope.write('data:source MATH2')

but I get a timeout error that doesn't occur when I just read from CH1.

Here's (most) code:

scope.write('MATH1:define "avg(CH1)"')
scope.write('MATH2:define "spectralMag(MATH1)"')
#io config
scope.write('header 0')
scope.write('data:encdg SRIBINARY')
scope.write('data:source CH1') # channel
scope.write('data:start 1') # first sample
scope.write('HORIZONTAL:MODE:SCALE 200e-9')
print(scope.query('horizontal:recordlength?'))
record = int(scope.query('horizontal:recordlength?'))
print(record)
scope.write('data:stop {}'.format(record)) # last sample
scope.write('wfmoutpre:byt_n 1') # 1 byte per sample
# acq config
scope.write('acquire:state 0') # stop
scope.write('acquire:stopafter SEQUENCE') # single
scope.write('acquire:state 1') # run
t5 = time.perf_counter()
r = scope.query('*opc?') # sync
t6 = time.perf_counter()
print('acquire time: {} s'.format(t6 - t5))

I get a timeout error when I try to write the .bin data:
#bin_wave = scope.query_binary_values('curve?', datatype='b', container=np.array)
bin_wave = scope.write('CURVE?')

The commented out line works for CH1, but nothing I try works for MATH2. 
Posted Thu, 09 Nov 2023 21:54:11 GMT by Teles, Afonso
Hi,

The problem is that you can't transfer a math channel using an integer encoding, you should instead use a floating point encoding.
Posted Mon, 11 Mar 2024 22:52:23 GMT by Jim, Big
Hi Afonso,

When I pull in the SpectralMag data as floating point values, I get 100 values, even though my record length is 1k. 

Here's the code: 

scope.write('MATH1:DEFINE "AVG(CH1)"')
    scope.write('MATH2:DEFINE "SpectralMag(Math1)"')
    scope.write('MATH2:SPECTral:SPAN 100E6')
    scope.write('MATH2:SPECTral:CENTER 100E6')
    print(scope.query('MATH1:DEFINE?'))
    #scope.write('autoset EXECUTE') # autoset
    t3 = time.perf_counter()
    r = scope.query('*opc?') # sync
    t4 = time.perf_counter()
    print('autoset time: {} s'.format(t4 - t3))
   # io config
    scope.write('header 0')
    scope.write('data:encdg SRIBINARY')
    scope.write('data:source MATH2') # channel
    scope.write('data:start 1') # first sample
    record = int(scope.query('horizontal:recordlength?'))
    scope.write('data:stop {}'.format(record)) # last sample
    scope.write('wfmoutpre:byt_n 1') # 1 byte per sample
    # acq config
    scope.write('acquire:state 0') # stop
    scope.write('acquire:stopafter SEQUENCE') # single
    scope.write('acquire:state 1') # run
    t5 = time.perf_counter()
    r = scope.query('*opc?') # sync
    t6 = time.perf_counter()
    print('acquire time: {} s'.format(t6 - t5))
    print(scope.query('BUSY?'))
    scope.write('acquire:state ON') # run
    print(scope.query('BUSY?'))
    t5 = time.perf_counter()
    #r = scope.query('*opc?') # sync
    t6 = time.perf_counter()
    print('acquire time: {} s'.format(t6 - t5))
    # data query
    t7 = time.perf_counter()
    bin_wave = scope.query_binary_values('curve?', datatype='f', container=np.array)
    print("binwave:")
    print(bin_wave)
    t8 = time.perf_counter()
    print('transfer time: {} s'.format(t8 - t7))
    # retrieve scaling factors
    tscale = float(scope.query('wfmoutpre:xincr?'))
    print(tscale)
    tstart = float(scope.query('wfmoutpre:xzero?'))
    vscale = float(scope.query('wfmoutpre:ymult?')) # volts / level
    voff = float(scope.query('wfmoutpre:yzero?')) # reference voltage
    vpos = float(scope.query('wfmoutpre:yoff?')) # reference position (level)
    # error checking
    r = int(scope.query('*esr?'))
    print('event status register: 0b{:08b}'.format(r))
    r = scope.query('allev?').strip()
    print('all event messages: {}'.format(r))
    scope.close()
    rm.close()
def plotMath():
    global scaled_wave
    # create scaled vectors
    # horizontal (time)
    total_time = tscale * record
    tstop = tstart + total_time
    scaled_time = np.linspace(0, tstop, num=record, is_big_endian=False ,endpoint=False)
    # vertical (voltage)
    unscaled_wave = np.array(bin_wave, dtype='float') # data type conversion

Posted Tue, 12 Mar 2024 16:25:04 GMT by Teles, Afonso
Hi "Big" Jim,

Would you be able to share a TekVisa or NIVisa trace of the relevant VISA calls? That would be the best way for me to see what's going on.
Posted Tue, 12 Mar 2024 18:49:37 GMT by Jim, Big
Hi Afonso, 

Attached is the NI IO Trace. For some reason I'm getting a timeout error today. It was running fine yesterday and I didn't change anything this morning. It's possible someone else using the scope changed some settings but I reset it and it still is timing out.

I can get the CH1 to run fine, just not the MATH1. I also discovered I need to use SRFBinary and 4 bytes instead of 1. But neither of these changes helps the time out error.

Thanks,
"Big" Jim
Posted Tue, 12 Mar 2024 22:23:26 GMT by Jim, Big
 
"Big" Jim back with an update.

I found I needed "SELECT:MATH<x> 1" to turn the MATH to ON state. It's a shame these things aren't more clear in the manual, it takes some time to find + troubleshoot.

Now I can play with the float point settings and see if I can get everything to line up in a plot. 

Thanks,
"Big" Jim
 
 
Posted Wed, 13 Mar 2024 00:41:55 GMT by Jim, Big
Afonso,

What are exactly the settings required to get the SpectralMag(CH1) data into my python plot? I'm getting really weird values and I'm not able to match the plot that I get from saving the data from the oscilloscope directly into CSV and plotting it in excel. 

When I set:

scope.write('MATH1:DEFINE "SpectralMag(CH1)"')
scope.write('SELECT:MATH1 1')
scope.write('header 0')
scope.write('data:encdg SRFBINARY')
scope.write('data:source MATH1') # channel
scope.write('data:start 1')
record = int(scope.query('horizontal:recordlength?'))
scope.write('data:stop {}'.format(record)) # last sample
scope.write('wfmoutpre:byt_nr 4') # 1 byte per sample

and then:

bin_wave = scope.query_binary_values('curve?', datatype='f', container=np.array)

I get 640 values in my np.array with 20k record length. But the values are not matching what they should be. There's some weird conversion going on I can't solve. 

Here's my NI I/O Trace (I've been toying with the settings since I wrote above) attached but don't take this too serious.

I can post my entire code but I'd really just appreciate the commands needed to get the SpectralMag(CH1) data in proper float form.

Thank you tremendously for your help this far,
"Big" Jim



 
Posted Wed, 13 Mar 2024 17:38:50 GMT by Teles, Afonso
Hi "Big" Jim,

SRFBINARY is not a valid data encoding, perhaps you meant SFPbinary. Also note that you don't need to set byt_nr as it's automatically set by data:encdg.
Might also be worth trying FPBinary (just changes the endianess).

For future reference, I suggest querying *ESR? after every write to help pick exactly this sort of problem. I have wrapper functions that do this automatically.
For production code, after proper testing, you can remove the *ESR? queries.
Posted Wed, 13 Mar 2024 21:23:46 GMT by Jim, Big
"SRFBinary is the same as RFBinary except that the byte order is swapped, meaning that the least significant byte is transferred first. This format is useful when transferring data to PCs"
Page 2-97 from the Programming Manual DPO7000 series. 

Looks like there's a typo in this regard. 

Thanks,
"Big" Jim
Posted Wed, 13 Mar 2024 21:38:13 GMT by Jim, Big
Hi again Afonso,

Despite now having the right float binary output from the scope to my python script, I'm still getting a bad plot. Please see the attached picture. 

There is a discrepency between the .csv output by the saved math function waveform on the scope and the data I get into my python script. Firstly, I only get Y values from the FFT function. This is OK as I can create an x function via: 

X_WAVE = np.linspace(2.75*10**7, 3.24921875*10**7, num=len(Y_WAVE), endpoint=False)

However, I don't know how to get the start and stop values without checking the output csv by the scope. This is an issue.

I can solve this with some hard work. What I can't seem to solve is why the values coming in from the scope into my python script are different from the values output by the scope's CSV. They are fine when I run the normal (non-math, standard channel 1) waveform into my script, but when I alter what I described above (encoding, bin_wave datatype, np.array datatype) to float binary anticipation it's not giving me the values I expect. 

With a 30MHz waveform that should fourier transform to a peak with an x-value at 30MHz, I get a plot as shown in attached image. 

Thus, my two inquiries are: how do I get the starting and ending x-values for the fourier transform data? In the csv generated by the scope, both x and y are included. When I get the waveform data in my python script, only incorrect y values are included. What am I doing wrong to get the wrong y-values from the math channel? I've changed the encoding type, changed the bytes expected to 4, changed the query_binary_values datatype to float, changed the np.array values to float, and still no dice.

Thanks,
"Big" Jim

 
Posted Wed, 13 Mar 2024 21:38:23 GMT by Teles, Afonso

Hi "Big" Jim,

Indeed, that's an error in the manual. I'm submitting a report to have it fixed, thank you for bringing it to our attention!

Posted Wed, 13 Mar 2024 21:41:08 GMT by Jim, Big
Afonso, 

Please make sure you read my lengthy inquiry above your comment. You posted right after me so I just want to make sure you see it. It is most important to solve this for our research applications.

I have been able to fourier transform the data independently via scipy/numpy, and with mathematical formulation, however pulling the fourier transform data into a plot straight from the math channel has stumped me.

Thank you for your work with me thus far and thanks for having the manual corrected.

Best and thanks,
"Big" Jim
Posted Wed, 13 Mar 2024 23:15:15 GMT by Teles, Afonso

> how do I get the starting and ending x-values for the fourier transform data?

If you query WFMOutpre? you'll get the y and x scale. You can assume it starts at DC (unless you're using the advanced spectral analysis, in which case you'll have to query it there) and then multiply the scale by 10 to get your total span.

> When I get the waveform data in my python script, only incorrect y values are included. What am I doing wrong to get the wrong y-values from the math channel?

Two things come to mind:

1) The data you're getting is linear data, you need to convert it to dB.

2) Make sure the endianess of your selected encoding and your read function match.

Posted Sat, 16 Mar 2024 00:07:18 GMT by Jim, Big
Hi Afonso,

The big endianness was indeed the problem.

Thanks for helping resolve this.

An issue in changing center/span in the Spectral Mag commands for the math channel:

When I run commands to alter the center/span frequencies (instead of letting them autoset), I get the attached plots. There is a skew to the peak height for the FFT/Spectral Mag that means the peak doesn't match the input frequency, 30MHz in this case.

On the left, you can see the typical peak (unzoomed) for a large span at 30MHz. On the right, I set 1MHz span and 30MHz center frequencies and get a weird skew of the peak frequency.

Any ideas on what I am doing wrong? I'm not sure what I need to alter the incoming y-values by to unskew the data upon changing the center/span freq.

Thanks again for the guidance,
"Big" Jim

You must be signed in to post in this forum.