Closed zhengliuer closed 1 year ago
Hi Zheng,
You will see that if there is not enough delay set by the programmer, it forces having at least adc_dead_time
amount of delay.
The first check just makes sure that this is not violated by the programmer manually after the ADC creation.
Sorry for the delay. Thanks a lot for the reply.
I'm not sure that I understand why adc.delay should be at least adc_dead_time. What if I just have one block which only has one ADC, like
adc = pp.make_adc(num_samples=1000, delay=0, duration=1e-3)
seq.add_block(adc)
As Maxim said, in pulseq, ADC objects are not allowed to touch the edges of the real time event blocks(according to Siemens scanners). However, if I just add a block which only has one delay object, setting adc.delay as adc.dead_time seems a little weird.
I suppose if we want to make sure that the ADC objects won't touch the edges of the real time event, we need to store the former real-time block's last real-time objects, make sure the time interval is appropriate.
Also, I notice in pulseq, there is a system parameter called rf_ringdown_time, as I asked before here, it should the time interval between ADC and RF? A little confused here.
I am not sure about the exact reason why we need adc_dead_time
, but it is typically set to a very short time, like 10us
(or 1 Gradient Raster Time). If you have a block with only a single ADC and don't want the 10 us shift, you can remove that amount of delay from the previous block as a workaround. You can also set it to 0 and see what happens, I will be curious to learn that.
rf_ringdown_time
specifies the time it takes the RF to settle down. Yes, it also implies ADC should be at least that much further away from the last RF. It also implies a subsequent RF should be at least rf_ringdown_time
apart from the previous RF. But if you look at the code, you will see that unlike the adc_dead_time
, it is not enforced by setting a delay, and it is typically larger than adc_dead_time
. They serve very different purposes.
Edit: For the sake of clarification, in summary, adc_dead_time
has nothing to do with RF. rf_dead_time
dictates that relationship. adc_dead_time
only makes sure the ADC is not touching edges of the event blocks, it does not imply anything about other event blocks.
If I create a sequence like this:
system == pp.Opts(...)
seq = pp.Sequence(system=system)
n_slice = 1
rf_duration = 300e-5
slice_thickness = 3e-3
fa = 30
tr = 100e-3
te = 20e-3
nx = 256
ny = 100
pe_fov = ro_fov = 300e-3
adc = pp.make_adc(num_samples=1000, delay=0, duration=1e-3)
seq.add_block(adc)
ok, error_report = seq.check_timing()
if ok:
print('Timing check passed successfully')
else:
print('Timing check failed. Error listing follows:')
[print(e) for e in error_report]
The report says Event: 0 - adc.delay < system.adc_dead_timeadc: system.adc_dead_time (post-ADC) violation
as expected for the adc.delay is 0.
So in summary, in pulseq,adc_dead_time is used to make sure that the ADC objects won't touch the edge of the following block(including RF event in the same block), not what I thought before: interval between two ADC objects.
Timing check violations does not prohibit .seq creation, so you can go ahead and try it on the scanner. If it fails, it means it is not a Pulseq limitation, but a Siemens limitation.
Thanks a lot!
Hi, I'm now using pypulseq to write some sequences. I had a small problem with adc time checking: https://github.com/imr-framework/pypulseq/blob/355952819df01c5bcbd484b85d1839547d4d08cb/pypulseq/Sequence/sequence.py#L618-L633 For an ADC, check_timing checks
adc.delay + adc.num_samples * adc.dwell + system.adc_dead_time
is bigger than the duration, I'm not sure why we need adc.dead_time here?I would appreciate it if anyone could help with these two questions.