Markus Rosenstihl
7da97a4f26
A parameter option "suppress_ringing" has been added to the Saturation Recovery script. This option modifies phase lists and allows the application of a phase cycle that compensates for ringing but reduces signal-to-noise ratio by half. This gives users the option to prioritize either reduced ringing or higher SNR as per their requirements.
177 lines
6.9 KiB
Python
177 lines
6.9 KiB
Python
# -*- coding: iso-8859-1 -*-
|
|
|
|
TXEnableDelay = 2e-6
|
|
TXEnableValue = 0b0001 # TTL line blanking RF amplifier (bit 0)
|
|
TXPulseValue = 0b0010 # TTL line triggering RF pulses (bit 1)
|
|
ADCSensitivity = 2 # voltage span for ADC
|
|
|
|
def experiment(): # saturation-recovery with soild-echo detection
|
|
|
|
# set up acquisition parameters:
|
|
pars = {}
|
|
pars['P90'] = 2.3e-6 # 90-degree pulse length (s)
|
|
pars['SF'] = 46.7e6 # spectrometer frequency (Hz)
|
|
pars['SW'] = 10e6 # spectral window (Hz)
|
|
pars['SI'] = 1*1024 # number of acquisition points
|
|
pars['NS'] = 16 # number of scans
|
|
pars['DS'] = 0 # number of dummy scans
|
|
pars['TAU'] = 1 # delay for recovery (s)
|
|
pars['D3'] = 20e-6 # echo delay (s)
|
|
pars['D4'] = 0 # pre-aquisition delay (s), use negative values
|
|
pars['PHA'] = -30 # receiver phase (degree)
|
|
# -*- these ain't variable: -*-
|
|
pars['NECH'] = 7 # number of saturation pulses
|
|
pars['D1'] = 100e-3 # starting interval in saturation sequence (s)
|
|
pars['D2'] = 1e-4 # end interval in saturation sequence (s)
|
|
pars['DATADIR'] = '/home/fprak/Students/' # data directory
|
|
pars['OUTFILE'] = None # output file name
|
|
pars["suppress_ringing"] = False # 16 Phase cycle, reduces ringing but halves SNR
|
|
|
|
# specify a variable parameter (optional):
|
|
pars['VAR_PAR'] = 'TAU' # variable parameter name (a string)
|
|
start = 1e-4 # starting value
|
|
stop = 1e-0 # end value
|
|
steps = 10 # number of values
|
|
log_scale = True # log scale flag
|
|
stag_range = True # staggered range flag
|
|
|
|
# check parameters for safety:
|
|
if pars['PHA'] < 0:
|
|
pars['PHA'] = 360 + pars['PHA']
|
|
|
|
if pars['P90'] > 20e-6:
|
|
raise Exception("pulse too long!!!")
|
|
|
|
# check whether a variable parameter is named:
|
|
var_key = pars.get('VAR_PAR')
|
|
if var_key == 'P90' and (start > 20e-6 or stop > 20e-6):
|
|
raise Exception("Pulse too long!!!")
|
|
|
|
if pars['NS']%8 != 0:
|
|
print 'Number of scans should be ',pars['NS'],' due to phase cycling'
|
|
|
|
if pars['D1'] < pars['D2']:
|
|
raise Exception("D1 must be greater than D2!")
|
|
|
|
sat_length = sum(log_range(pars['D1'],pars['D2'],pars['NECH']))
|
|
if sat_length > 1.:
|
|
raise Exception("saturation sequence too long!!!")
|
|
|
|
# start the experiment:
|
|
if var_key:
|
|
# this is an arrayed experiment:
|
|
if log_scale:
|
|
array = log_range(start, stop, steps)
|
|
else:
|
|
array = lin_range(start, stop, steps)
|
|
|
|
if stag_range:
|
|
array = staggered_range(array, size = 2)
|
|
|
|
# estimate the experiment time:
|
|
if var_key == 'TAU':
|
|
seconds = ((sat_length + pars['D3']*2) * steps + sum(array)) * (pars['NS'] + pars['DS'])
|
|
elif var_key == 'D3':
|
|
seconds = ((sat_length + pars['TAU']) * steps + sum(array)*2) * (pars['NS'] + pars['DS'])
|
|
else:
|
|
seconds = (sat_length + pars['TAU'] + pars['D3']*2) * steps * (pars['NS']+ pars['DS'])
|
|
m, s = divmod(seconds, 60)
|
|
h, m = divmod(m, 60)
|
|
print '%s%02d:%02d:%02d' % ('Experiment time estimated: ', h, m, s)
|
|
|
|
# loop for a variable parameter:
|
|
for index, pars[var_key] in enumerate(array):
|
|
print 'Arrayed experiment for '+var_key+': run = '+str(index+1)+\
|
|
' out of '+str(array.size)+': value = '+str(pars[var_key])
|
|
# loop for accumulation:
|
|
for run in xrange(pars['NS']+pars['DS']):
|
|
yield satrec2_experiment(pars, run)
|
|
synchronize()
|
|
else:
|
|
# estimate the experiment time:
|
|
seconds = (sat_length + pars['TAU'] + pars['D3']*2) * (pars['NS']+ pars['DS'])
|
|
m, s = divmod(seconds, 60)
|
|
h, m = divmod(m, 60)
|
|
print '%s%02d:%02d:%02d' % ('Experiment time estimated: ', h, m, s)
|
|
|
|
# loop for accumulation:
|
|
for run in xrange(pars['NS']+pars['DS']):
|
|
yield satrec2_experiment(pars, run)
|
|
|
|
|
|
# the pulse program:
|
|
|
|
def satrec2_experiment(pars, run):
|
|
e=Experiment()
|
|
|
|
dummy_scans = pars.get('DS')
|
|
if dummy_scans:
|
|
run -= dummy_scans
|
|
|
|
pars['PROG'] = 'satrec2_experiment'
|
|
|
|
if pars["suppress_ringing"]:
|
|
# phase cycle to compensate ringing (loss of half the signal!)
|
|
pars['PH3'] = [ 0, 0, 0, 0, 90, 90, 90, 90, 180, 180, 180, 180, 270, 270, 270, 270] # 1st 90-degree pulse
|
|
pars['PH4'] = [ 0, 90, 180, 270, 90, 180, 270, 0, 180, 270, 0, 90, 270, 0, 90, 180] # 2nd 90-degree pulse
|
|
pars['PH2'] = [ 180, 0, 180, 0, 270, 90, 270, 90, 0, 180, 0, 180, 90, 270, 90, 270] # receiver
|
|
else:
|
|
# simple phase cycle:
|
|
pars['PH1'] = [0] # saturation pulses
|
|
pars['PH3'] = [0, 180, 0, 180, 90, 270, 90, 270] # 1st 90-degree pulse
|
|
pars['PH4'] = [90, 90, 270, 270, 0, 0, 180, 180] # 2nd 90-degree pulse
|
|
pars['PH2'] = [0, 180, 0, 180, 90, 270, 90, 270] # receiver
|
|
|
|
# read in variables:
|
|
P90 = pars['P90']
|
|
SF = pars['SF']
|
|
NECH = pars['NECH']
|
|
D1 = pars['D1']
|
|
D2 = pars['D2']
|
|
D3 = pars['D3']
|
|
D4 = pars['D4']
|
|
TAU = pars['TAU']
|
|
PH1 = pars['PH1'][run%len(pars['PH1'])]
|
|
PH3 = pars['PH3'][run%len(pars['PH3'])]
|
|
PH4 = pars['PH4'][run%len(pars['PH4'])]
|
|
PH2 = pars['PH2'][run%len(pars['PH2'])]
|
|
PHA = pars['PHA']
|
|
SI = pars['SI']
|
|
SW = pars['SW']
|
|
|
|
# set variable delay list for saturation pulses:
|
|
vdlist = log_range(D2, D1, NECH-1)
|
|
|
|
# the pulse sequence:
|
|
|
|
# saturation:
|
|
e.set_frequency(SF, phase=PH1) # set frequency and phase for saturation pulses
|
|
e.ttl_pulse(TXEnableDelay, value=TXEnableValue) # enable RF amplifier
|
|
e.ttl_pulse(P90, value=TXEnableValue|TXPulseValue) # apply 90-degree pulse
|
|
for delay in vdlist[::-1]:
|
|
e.wait(delay-P90-TXEnableDelay) # wait for next saturation pulse
|
|
e.ttl_pulse(TXEnableDelay, value=TXEnableValue) # enable RF amplifier
|
|
e.ttl_pulse(P90, value=TXEnableValue|TXPulseValue) # apply 90-degree pulse
|
|
|
|
e.set_phase(PH3) # set phase for next pulse
|
|
# recovery:
|
|
e.wait(TAU-5e-7) # wait for tau
|
|
|
|
# echo detection:
|
|
e.ttl_pulse(TXEnableDelay, value=TXEnableValue) # enable RF amplifier
|
|
e.ttl_pulse(P90, value=TXEnableValue|TXPulseValue) # apply 90-degree pulse
|
|
e.set_phase(PH4) # set phase for next pulse
|
|
e.wait(D3-P90-TXEnableDelay-5e-7) # echo delay
|
|
e.ttl_pulse(TXEnableDelay, value=TXEnableValue) # enable RF amplifier
|
|
e.ttl_pulse(P90, value=TXEnableValue|TXPulseValue) # apply 90-degree pulse
|
|
e.set_phase(PHA) # set phase for receiver
|
|
e.wait(D3-P90/2+D4-5e-7) # echo delay
|
|
e.record(SI, SW, sensitivity=ADCSensitivity) # acquisition
|
|
|
|
# write experiment attributes:
|
|
for key in pars.keys():
|
|
e.set_description(key, pars[key]) # pulse sequence parameters
|
|
e.set_description('run', run) # current scan
|
|
e.set_description('rec_phase', -PH2) # current receiver phase
|
|
|
|
return e |