morgan-at-keysight / pyarbtools

Create waveforms and control Keysight signal generators in Python with PyArbTools.
Other
52 stars 14 forks source link

awg_pulse_sequence.py feature multiply CW #30

Closed KfirCohen-PyLab closed 3 years ago

KfirCohen-PyLab commented 3 years ago

Hello Morgan, how are you doing? First of all thank you very much for your help with the controlling AWG m8190a python scripts, it's really helped me with my work and I wanted to know if there is an option to add multiply CW pulses in my sequence builder, I thought on two options:

  1. Add 2 different waveform in one segment and add an idle segment after the first segment and run them as a sequence together.(I know a sequence cannot start with an idle waveform but it can end with one right?)

  2. Make 3 segments that in the first segment we have X waveform, The second segment will be an idle, The third segment will have Y waveform and running all three of the segments as a sequence.

Moreover I've been studying your code more deeply and I wanted to clarifying some things to know if I am understanding it correctly...

Here some lines from your main function that are importent for me to know:

# User-defined sample rate, carrier freq, pulse width, and pri.       _**#Here you are defining your CW emitter.**_
############################################################################
fs = 10e9           _**#sample rate of the clock.**_
cf = 100e6         _**#Carrier frequency of the emitter.**_
width = 10e-6   _**#Emitter pulse width.**_
pri = 20e-6        _**#Emitter pulse repetition interval between every pulse.**_
############################################################################

# Create building blocks for cw pulse sequence.
pulseOn, endWfm, idleSamples = cw_pulse_sequence(fs, cf, width, pri, res)  _**#Creating the cw pulse sequence.**_

# Define required waveforms and send data to AWG.
awg.write(f'trace:def 1, {len(pulseOn)}')     _**#Sending to the instrument the first data segment , seg ID 1 and his length.**_
awg.write_binary_values('trace:data 1, 0, ', pulseOn, datatype='h')
awg.write(f'trace:def 2, {len(endWfm)}')  _**#Sending to the instrument the first idle segment , seg ID 2 and his length.**_
awg.write_binary_values('trace:data 2, 0, ', endWfm, datatype='h')

"""
Command Documentation

Load sequence index with **wfm** segment
stable:data <seq_table_index>, <control_entry>, <seq_loop_cnt>, <seg_loop_cnt>, <seg_id>, <seg_start>, <seg_end>

Load sequence index with **idle** waveform
stable:data <seq_table_index>, <control_entry>, <seq_loop_cnt>, <command_code>, <idle_sample>, <idle_delay>, 0

Descriptions of the command arguments (<control_entry>, <seq_loop_cnt>, etc.) can be found
on pages 262-265 in Keysight M8190A User's Guide (Edition 13.0, October 2017).
"""

# Build sequence.
awg.write('seq:delete:all') _**#Cleaning the seq table before writing**_
awg.query('seq:def:new? 3')

awg.write(f'stable1:data 0, {1 << 28} _**#28 bit init marker seq **_    , 1, 1, 1, 0, #hffffffff')  _**#Make the first Data segment**_ 
awg.write(f'stable1:data 1, {1 << 31} _**#31 bit data/command**_   , 0, 0, 0, {idleSamples}, 0')  _**#Make the idle waveform**_
awg.write(f'stable1:data 2, {1 << 30} _**#30 bit end marker seq**_  , 0, 1, 2, 0, #hffffffff') _**#Make the second Data segment**_

# Configure AWG to output a sequence and begin playback.

awg.write('source:func1:mode stsequence')  _**#Defining the play mode to sequence mode**_

Now for my questions:

Thank you in advance.

morgan-at-keysight commented 3 years ago

Thanks for the question. Even though it's not directly related to PyArbTools, I'll answer it here.

Can I add building blocks with different data waveform to create different segments or different waveforms in one segment?

Absolutely, this is an arbitrary waveform generator after all.

How do you approach cyclicity problems if you encountered one in your tests with AWG m8190a? (my main problem I keep on solving.)

Can you elaborate on what you mean by "cyclicity problems"?

If I'm interpreting this correctly, I think it's an issue with either waveform granularity or idle segment granularity. Due to hardware architecture of the DACs we use, all waveforms loaded into them must have a length that is an integer multiple of a certain number of samples. We call this the waveform granularity. There is a similar but less stringent granularity requirement for the idle segment length in the M8190A.

In PyArbTools, I have a helper function for each signal generator class in instruments.py called check_wfm(), which ensures the waveform you're downloading meets the granularity (and minimum length) requirements for the generator you're using. I have not implemented this helper function for the idle segment in the M8190A sequencer because I haven't implemented that functionality yet.

KfirCohen-PyLab commented 3 years ago

Hi morgan, Thanks for the response.

Can you elaborate on what you mean by "cyclicity problems"?

Of course, I am trying to create a pulse wave (like a synthesizer creates), using a sequence of CW signal segment (pulseOn) an idle segment in the length of the PRI and an "end-cap" segment endWfm.

But everytime I run this sequence I see on my spectrum analyzer (on zero span mode) that the signal is drifting in time... instead of being stable. I strongly agree with you that the problem is caused by the granularity that is taken in the process of the fucntion check_wfm() in awg_pulse_sequence.py.

I am working with fs = 12G/Hz ,resolution 'wsp' with granularity of 64 and minimum samples of 320, in my tries of tests I've managed to find a relation between the size of PRI I decided and the idle segment length, When I reduce the MinLen and the granularity it seems to be almost stable there is still a very minor drift (in the size of nano sec units) , I almost got the point when it works perfectly but I still have a few basic things that are missing me, from your answer I resume that the functions in PyArbTools can be useful here and maybe it can be integrate in the awg_pulse_sequence.py or reversed.

I will try using the PyArbTools to create my pulse wave, If I come up with a solution I will write you as soon as I can.

Thank a lot for your help, and good luck!

KfirCohen-PyLab commented 3 years ago

Hi Morgan, How are you doing? Did you understand what I meant in my question? I Look forward to hearing from you. @morgan-at-keysight

morgan-at-keysight commented 3 years ago

Can you share screenshots of the drift you're seeing? Exactly how much are the pulses drifting? Are they drifting the same amount with each new acquisition?

KfirCohen-PyLab commented 3 years ago

I did kind of a tracking table on my tests, Each test I changed only the PRI and measuerd the samples that shifts and their time:

Pw[usec] , Pri[usec] , sampels shift , time shift [usec] 1 100 12 1 1 1000 132 11 1 10000 1284 107 1 100000 12840 1070

awg.write(f'stable1:data 0, {1 << 28}, 1, 1, 2, 0, #hffffffff') awg.write(f'stable1:data 1, {1 << 31} , 0, 0, 0, {idleSamples - minLen - 13}, 0') awg.write(f'stable1:data 2, {1 << 30} ,0, 1, 1, 0, #hffffffff')

morgan-at-keysight commented 3 years ago

Did you change the PRI by adjusting the waveform length or by changing the idle delay?

If you changed the waveform length, you'll be limited by the granularity of the waveform. This means that the resolution you have for adjusting the PRI is sampleGranularity / sampleRate, which would be 64 / 12e9 = 5.3333 ns. If your desired change in PRI is not divisible by that number, you'll get some unexpected results. You can still do it this way, but you may have to adjust your sample rate to get the resolution you need.

A better way would be to change the idle delay since it has a granularity of one DAC output sample, giving you much finer resolution.

KfirCohen-PyLab commented 3 years ago

Yes I changed the idle waveform length as you can see in my previous replay I wrote this: "{idleSamples - minLen - 13}" in the length of the idle segment, IdleSamples minus the minLen which is 320 samples, minus 13 samples (samples shift) which have given me a very minor drift in the pulse around 5.3333 ns. In the spectrom analayzer the pulses looked almost steady but from a closer look in zoom in the pulse drifted very slowly....

morgan-at-keysight commented 3 years ago

Sorry, I missed that in the formatting of the code in that message. I was playing with the sequencer feature today and didn't see any drift on my end when using the idle segment as the off time of a pulse train. I have written a simple sequencer API for the M8190A in PyArbTools and will be uploading the new code later today. You might take a look at it when it goes live.

KfirCohen-PyLab commented 3 years ago

I saw what you wrote in Pyarbtools last update, I still see a little drift in the size of about 0.5 usec which is small but still effective drift on my work...

Plus I tried to add pulse width option to the example and succeded to make a fulled controlled sequence with pw and pri i've choose to create, Theres a chance you can add this option to the code too?

morgan-at-keysight commented 3 years ago

Please send a series of screenshots that clearly show the drift you are seeing with measurements (the easiest way is to use markers, just make sure they show the change.drift in PRI or pulse width).

The example I posted with that update uses a sine waveform with an idle segment to create a pulse to show how the idle segment feature operates. If I was doing a "real" pulsed signal, I would use the wfmBuilder.cw_pulse_generator() method, which does have arguments to set pulse width and pri in the waveform itself.

As of March 4, 2021, cw_pulse_generator() is located on line 382 of wfmBuilder.py.

morgan-at-keysight commented 3 years ago

@KfirCohen-PyLab what is the status of this issue? Have you measured the drift you were experiencing or found another workaround?

morgan-at-keysight commented 3 years ago

Closing due to inactivity.