safety
This commit is contained in:
@@ -5,35 +5,35 @@ import traceback
|
|||||||
from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, IntRange, IDLE, BUSY, WARN, ERROR, Drivable, BoolType, Attached
|
from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, IntRange, IDLE, BUSY, WARN, ERROR, Drivable, BoolType, Attached
|
||||||
|
|
||||||
class TSSOP16_IO(StringIO):
|
class TSSOP16_IO(StringIO):
|
||||||
end_of_line = '\r'
|
end_of_line = '\r\n'
|
||||||
wait_before = 0.0 #3.0
|
wait_before = 3.0
|
||||||
timeout=3.0
|
timeout=1
|
||||||
identification = [ ('*IDN?', r'0x48,ACM1219,.*') ]
|
identification = [ ('*IDN?', r'0x48,ACM1219,.*') ]
|
||||||
|
|
||||||
class TSSOP16(HasIO, Readable):
|
class TSSOP16(HasIO, Readable):
|
||||||
'''only configured for channel 1'''
|
'''only configured for channel 1'''
|
||||||
|
|
||||||
ioClass = TSSOP16_IO
|
ioClass = TSSOP16_IO
|
||||||
value = Parameter('value', FloatRange(unit='pF'), readonly=True)
|
value = Parameter('value', FloatRange(unit='pF'), readonly=True, default=-1)
|
||||||
pollinterval = Parameter(default=0.1)
|
pollinterval = Parameter(default=1)
|
||||||
|
|
||||||
def custom_read_off_cvt(self, recursive_layer=0):
|
def custom_read_off_cvt(self, recursive_layer=0):
|
||||||
try:
|
try:
|
||||||
l = self.communicate('readCVT')
|
l = self.communicate('readCVT')
|
||||||
vals = l.split(',')
|
vals = l.split(',')
|
||||||
vals = [ float(v) for v in vals ]
|
vals = [ float(v) for v in vals ]
|
||||||
#print(vals)
|
print(vals)
|
||||||
return vals[0]
|
return vals[0]
|
||||||
except:
|
except:
|
||||||
return self.read_off_cvt()
|
return self.custom_read_off_cvt(recursive_layer=recursive_layer+1)
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.io.closeConnection()
|
self.io.closeConnection()
|
||||||
self.io.connectStart()
|
self.io.connectStart()
|
||||||
time.sleep(3.0)
|
#time.sleep(3.0)
|
||||||
if(recursive_layer > 10):
|
if(recursive_layer > 2):
|
||||||
return -1
|
return -1
|
||||||
else:
|
else:
|
||||||
return self.read_off_cvt(recursive_layer+1)
|
return self.custom_read_off_cvt(recursive_layer+1)
|
||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
res = self.custom_read_off_cvt()
|
res = self.custom_read_off_cvt()
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import time
|
|||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
class ProgrammedSequence(fc.Readable):
|
class ProgrammedSequence(fc.Drivable): # Drivable only for kill() funcitonality
|
||||||
"""An NMR device being driven by an instance of TNMR. Requires that an instance of TNMR is opened before creation.
|
"""An NMR device being driven by an instance of TNMR. Requires that an instance of TNMR is opened before creation.
|
||||||
|
|
||||||
Use
|
Use
|
||||||
@@ -49,7 +49,7 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
pre_acquisition_time: float (usecs) which describes the length of time to wait after ringdown finishes (1u is okay)
|
pre_acquisition_time: float (usecs) which describes the length of time to wait after ringdown finishes (1u is okay)
|
||||||
post_acquisition_time: float (ms) which describes the length of time to wait after finishing acquisition
|
post_acquisition_time: float (ms) which describes the length of time to wait after finishing acquisition
|
||||||
acq_phase_cycle: str, the phase cycle to run on acquisition (eg., '0 1 1 2', '0 1 2 3', '1 1 2 2 0 0 3 3 1 2 3 4', ...)
|
acq_phase_cycle: str, the phase cycle to run on acquisition (eg., '0 1 1 2', '0 1 2 3', '1 1 2 2 0 0 3 3 1 2 3 4', ...)
|
||||||
num_scans: int (ct), the number of 1D scans to take per sequence
|
num_acqs: int (ct), the number of 1D scans to take per sequence
|
||||||
obs_freq: float (MHz), the NMR frequency
|
obs_freq: float (MHz), the NMR frequency
|
||||||
|
|
||||||
Commands
|
Commands
|
||||||
@@ -72,7 +72,12 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
imags=fc.ArrayOf(fc.FloatRange(), maxlen=4096), # imag values
|
imags=fc.ArrayOf(fc.FloatRange(), maxlen=4096), # imag values
|
||||||
t =fc.ArrayOf(fc.FloatRange(), maxlen=4096)), # times (starting from zero)
|
t =fc.ArrayOf(fc.FloatRange(), maxlen=4096)), # times (starting from zero)
|
||||||
default={ 'reals': [], 'imags': [], 't': [] })
|
default={ 'reals': [], 'imags': [], 't': [] })
|
||||||
status = fc.Parameter(datatype=frappy.datatypes.StatusType(fc.Readable, "DISABLED", 'PREPARED', 'BUSY'), default=('IDLE', 'ok - uncompiled'))
|
target = fc.Parameter('dummy', fc.StructOf(reals=fc.ArrayOf(fc.FloatRange(), maxlen=4096), # real values
|
||||||
|
imags=fc.ArrayOf(fc.FloatRange(), maxlen=4096), # imag values
|
||||||
|
t =fc.ArrayOf(fc.FloatRange(), maxlen=4096)), # times (starting from zero)
|
||||||
|
default={ 'reals': [], 'imags': [], 't': [] }, readonly=True, visibility='w--')
|
||||||
|
|
||||||
|
status = fc.Parameter(datatype=frappy.datatypes.StatusType(fc.Drivable, "DISABLED", 'PREPARED', 'BUSY'), default=('IDLE', 'ok - uncompiled'))
|
||||||
pollinterval = fc.Parameter(default=1)
|
pollinterval = fc.Parameter(default=1)
|
||||||
|
|
||||||
# basic
|
# basic
|
||||||
@@ -81,10 +86,12 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
comments = fc.Parameter('comments', fc.StringType(), default='', readonly=False)
|
comments = fc.Parameter('comments', fc.StringType(), default='', readonly=False)
|
||||||
nucleus = fc.Parameter('nucleus', fc.StringType(), default='', readonly=False)
|
nucleus = fc.Parameter('nucleus', fc.StringType(), default='', readonly=False)
|
||||||
|
|
||||||
|
sequence_length = fc.Parameter('sequence_length', fc.IntRange(), default=0, readonly=True)
|
||||||
sequence_data = fc.Parameter('sequence_config', fc.ArrayOf(fc.StructOf(pulse_width=fc.FloatRange(unit='usecs'),
|
sequence_data = fc.Parameter('sequence_config', fc.ArrayOf(fc.StructOf(pulse_width=fc.FloatRange(unit='usecs'),
|
||||||
pulse_height=fc.FloatRange(unit='%'),
|
pulse_height=fc.FloatRange(unit='%'),
|
||||||
delay_time=fc.FloatRange(unit='usecs'),
|
delay_time=fc.FloatRange(unit='usecs'),
|
||||||
phase_cycle=fc.StringType())), default=[], readonly=False)
|
phase_cycle=fc.StringType()), minlen=0), default=[{'pulse_width':0,'pulse_height':0,'delay_time':0,'phase_cycle':''}]*100, readonly=False)
|
||||||
|
num_acqs_actual = fc.Parameter('num_acqs', fc.IntRange(), readonly=True, default=0)
|
||||||
|
|
||||||
# final details
|
# final details
|
||||||
acquisition_time = fc.Parameter('acquisition_time', fc.FloatRange(unit='usecs'), readonly=False, group='sequence_editor', default=204.8) # this is a limit set by the dwell limit and number of acquisition points
|
acquisition_time = fc.Parameter('acquisition_time', fc.FloatRange(unit='usecs'), readonly=False, group='sequence_editor', default=204.8) # this is a limit set by the dwell limit and number of acquisition points
|
||||||
@@ -92,11 +99,12 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
pre_acquisition_time = fc.Parameter('pre_acquisition_time', fc.FloatRange(unit='usecs'), readonly=False, group='sequence_editor', default=1)
|
pre_acquisition_time = fc.Parameter('pre_acquisition_time', fc.FloatRange(unit='usecs'), readonly=False, group='sequence_editor', default=1)
|
||||||
post_acquisition_time = fc.Parameter('post_acquisition_time', fc.FloatRange(unit='msecs'), readonly=False, group='sequence_editor', default=500)
|
post_acquisition_time = fc.Parameter('post_acquisition_time', fc.FloatRange(unit='msecs'), readonly=False, group='sequence_editor', default=500)
|
||||||
acq_phase_cycle = fc.Parameter('acq_phase_cycle', fc.StringType(), readonly=False, group='sequence_editor', default='')
|
acq_phase_cycle = fc.Parameter('acq_phase_cycle', fc.StringType(), readonly=False, group='sequence_editor', default='')
|
||||||
num_scans = fc.Parameter('num_scans', fc.IntRange(), readonly=False, group='sequence_editor', default=16)
|
num_acqs = fc.Parameter('num_acqs', fc.IntRange(), readonly=False, group='sequence_editor', default=16)
|
||||||
obs_freq = fc.Parameter('obs_freq', fc.FloatRange(unit='MHz'), readonly=False, group='sequence_editor', default=213.16)
|
obs_freq = fc.Parameter('obs_freq', fc.FloatRange(unit='MHz'), readonly=False, group='sequence_editor', default=213.16)
|
||||||
|
|
||||||
compiled_parameters = {} # so that we can store the values of parameters only when compiling, effectively giving us an instance of each parameter loaded into TNMR, as well as "targets" (those above)
|
compiled_parameters = {} # so that we can store the values of parameters only when compiling, effectively giving us an instance of each parameter loaded into TNMR, as well as "targets" (those above)
|
||||||
inited = False
|
inited = False
|
||||||
|
starting = False
|
||||||
approx_sequence_length = 0
|
approx_sequence_length = 0
|
||||||
|
|
||||||
### SETUP
|
### SETUP
|
||||||
@@ -148,6 +156,20 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
|
|
||||||
### READ/WRITE
|
### READ/WRITE
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
if not(self.inited):
|
||||||
|
self.status = ('ERROR', 'TNMR disconnected!')
|
||||||
|
else:
|
||||||
|
if(self.starting):
|
||||||
|
self.status = ('BUSY', 'starting')
|
||||||
|
else:
|
||||||
|
if(self.tnmr().acquisition_running()):
|
||||||
|
self.status = ('BUSY', 'acquiring')
|
||||||
|
elif(self.status[1] == 'acquiring'):
|
||||||
|
# we've just finished acquiring, in frappy's perspective
|
||||||
|
self.status = ('PREPARED', 'compiled')
|
||||||
|
return self.status
|
||||||
|
|
||||||
def write_title(self, t):
|
def write_title(self, t):
|
||||||
self.title = t
|
self.title = t
|
||||||
self.status = ('IDLE', 'ok - uncompiled')
|
self.status = ('IDLE', 'ok - uncompiled')
|
||||||
@@ -193,14 +215,14 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
self.status = ('IDLE', 'ok - uncompiled')
|
self.status = ('IDLE', 'ok - uncompiled')
|
||||||
return self.read_acq_phase_cycle()
|
return self.read_acq_phase_cycle()
|
||||||
|
|
||||||
def read_num_scans(self):
|
def read_num_acqs(self):
|
||||||
return self.tnmr().get_nmrparameter('Scans 1D')
|
return int(self.tnmr().get_nmrparameter('Scans 1D'))
|
||||||
|
|
||||||
def write_num_scans(self, t):
|
def write_num_acqs(self, t):
|
||||||
if(self.status[0] != 'BUSY'):
|
if(self.status[0] != 'BUSY'):
|
||||||
self.tnmr().set_nmrparameter('Scans 1D', t)
|
self.tnmr().set_nmrparameter('Scans 1D', t)
|
||||||
self.status = ('IDLE', 'ok - uncompiled')
|
self.status = ('IDLE', 'ok - uncompiled')
|
||||||
return self.read_num_scans()
|
return self.read_num_acqs()
|
||||||
|
|
||||||
def read_obs_freq(self):
|
def read_obs_freq(self):
|
||||||
return self.tnmr().get_nmrparameter('Observe Freq.')
|
return self.tnmr().get_nmrparameter('Observe Freq.')
|
||||||
@@ -210,6 +232,36 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
self.tnmr().set_nmrparameter('Observe Freq.', t)
|
self.tnmr().set_nmrparameter('Observe Freq.', t)
|
||||||
self.status = ('IDLE', 'ok - uncompiled')
|
self.status = ('IDLE', 'ok - uncompiled')
|
||||||
return self.read_obs_freq()
|
return self.read_obs_freq()
|
||||||
|
|
||||||
|
def write_sequence_data(self, t):
|
||||||
|
self.sequence_length = len(t)
|
||||||
|
seq = []
|
||||||
|
seq += t
|
||||||
|
print(seq)
|
||||||
|
seq += [{'pulse_width':0,'pulse_height':0,'delay_time':0,'phase_cycle':''}] * (100-self.sequence_length) # because nicos will only send the smallest size it has ever sent...
|
||||||
|
self.sequence_data = seq
|
||||||
|
|
||||||
|
return self.read_sequence_data()
|
||||||
|
|
||||||
|
def read_value(self):
|
||||||
|
newvals = {}
|
||||||
|
#try:
|
||||||
|
d = self.tnmr().get_data()
|
||||||
|
newvals['reals'] = d[0]
|
||||||
|
newvals['imags'] = d[1]
|
||||||
|
newvals['t'] = [ self.compiled_parameters['acquisition_time'] * i/len(d[0]) for i in range(0, len(d[0])) ]
|
||||||
|
#except:
|
||||||
|
# newvals['reals'] = []
|
||||||
|
# newvals['imags'] = []
|
||||||
|
# newvals['t'] = []
|
||||||
|
return newvals
|
||||||
|
|
||||||
|
def read_num_acqs_actual(self):
|
||||||
|
try:
|
||||||
|
n = self.tnmr().get_nmrparameter('Actual Scans 1D')
|
||||||
|
return int(n)
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
### PRIVATE (Utility)
|
### PRIVATE (Utility)
|
||||||
def __compile_sequence(self):
|
def __compile_sequence(self):
|
||||||
@@ -229,7 +281,8 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
seq = seq_gen.get_initial_block()
|
seq = seq_gen.get_initial_block()
|
||||||
i = 0
|
i = 0
|
||||||
self.approx_sequence_length = 0
|
self.approx_sequence_length = 0
|
||||||
for s in self.sequence_data:
|
for si in range(self.sequence_length):
|
||||||
|
s = self.sequence_data[si]
|
||||||
seq = seq_gen.combine_blocks(seq, seq_gen.get_single_pulse_block(f'pulse_{i}', str(s['pulse_width']) + 'u',
|
seq = seq_gen.combine_blocks(seq, seq_gen.get_single_pulse_block(f'pulse_{i}', str(s['pulse_width']) + 'u',
|
||||||
str(s['pulse_height']),
|
str(s['pulse_height']),
|
||||||
str(s['delay_time']) + 'u',
|
str(s['delay_time']) + 'u',
|
||||||
@@ -252,10 +305,9 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
filename = filepath + '/sequences/' + filename.replace('.','')
|
filename = filepath + '/sequences/' + filename.replace('.','')
|
||||||
seq_gen.save_sequence(filename, seq)
|
seq_gen.save_sequence(filename, seq)
|
||||||
seq_gen.save_sequence_cfg(filename, seq)
|
seq_gen.save_sequence_cfg(filename, seq)
|
||||||
print(filename)
|
|
||||||
|
|
||||||
dashboard_params = { 'Observe Freq.': self.read_obs_freq(),
|
dashboard_params = { 'Observe Freq.': self.read_obs_freq(),
|
||||||
'Scans 1D': self.read_num_scans(),
|
'Scans 1D': self.read_num_acqs(),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compiled_parameters['ringdown_time'] = self.ringdown_time
|
self.compiled_parameters['ringdown_time'] = self.ringdown_time
|
||||||
@@ -263,7 +315,7 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
self.compiled_parameters['acquisition_time'] = self.acquisition_time
|
self.compiled_parameters['acquisition_time'] = self.acquisition_time
|
||||||
self.compiled_parameters['post_acquisition_time'] = self.post_acquisition_time
|
self.compiled_parameters['post_acquisition_time'] = self.post_acquisition_time
|
||||||
self.compiled_parameters['acq_phase_cycle'] = self.acq_phase_cycle
|
self.compiled_parameters['acq_phase_cycle'] = self.acq_phase_cycle
|
||||||
self.compiled_parameters['num_scans'] = self.read_num_scans()
|
self.compiled_parameters['num_acqs'] = self.read_num_acqs()
|
||||||
self.compiled_parameters['obs_freq'] = self.read_obs_freq()
|
self.compiled_parameters['obs_freq'] = self.read_obs_freq()
|
||||||
self.compiled_parameters['title'] = self.read_title()
|
self.compiled_parameters['title'] = self.read_title()
|
||||||
self.compiled_parameters['comments'] = self.read_comments()
|
self.compiled_parameters['comments'] = self.read_comments()
|
||||||
@@ -290,15 +342,8 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
|
|
||||||
def __zero_go(self):
|
def __zero_go(self):
|
||||||
'''Tells TNMR to acquire data. Only call after __compile_sequence().'''
|
'''Tells TNMR to acquire data. Only call after __compile_sequence().'''
|
||||||
if(self.status[0] != 'BUSY'):
|
if(self.status[0] != 'BUSY' or self.starting):
|
||||||
self.status = ('BUSY', 'acquiring')
|
self.tnmr().ZeroGo(lock=False, check_time=max(int(self.approx_sequence_length*1.5), 5))
|
||||||
self.tnmr().ZeroGo(lock=True, interval=0.5, check_time=max(self.approx_sequence_length*5, 5))
|
|
||||||
newvals = {}
|
|
||||||
newvals['reals'] = self.tnmr().get_data()[0]
|
|
||||||
newvals['imags'] = self.tnmr().get_data()[1]
|
|
||||||
newvals['t'] = [ self.compiled_parameters['acquisition_time'] * i/1024 for i in range(0, 1024) ]
|
|
||||||
self.value = newvals
|
|
||||||
self.status = ('PREPARED', 'compiled')
|
|
||||||
|
|
||||||
def __compile_and_run(self, thread=True):
|
def __compile_and_run(self, thread=True):
|
||||||
'''Compiles and runs the currently-loaded sequence
|
'''Compiles and runs the currently-loaded sequence
|
||||||
@@ -307,9 +352,11 @@ class ProgrammedSequence(fc.Readable):
|
|||||||
----------
|
----------
|
||||||
thread: bool, determines if this should open a child thread and detach the process
|
thread: bool, determines if this should open a child thread and detach the process
|
||||||
'''
|
'''
|
||||||
|
self.starting = True
|
||||||
self.__compile_sequence()
|
self.__compile_sequence()
|
||||||
time.sleep(1.0)
|
time.sleep(1.0)
|
||||||
self.__zero_go()
|
self.__zero_go()
|
||||||
|
self.starting = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ def get_single_pulse_block(name, pulse_width, pulse_height, delay_time, phase_cy
|
|||||||
delay_time = float(delay_time.strip()[:-1]) / 1e6
|
delay_time = float(delay_time.strip()[:-1]) / 1e6
|
||||||
else:
|
else:
|
||||||
delay_time = float(delay_time.strip()) # assume in us
|
delay_time = float(delay_time.strip()) # assume in us
|
||||||
|
|
||||||
|
delay_time_rounded = int(delay_time*10) / 10 # nearest 10ns
|
||||||
|
delay_time = delay_time_rounded
|
||||||
|
|
||||||
ph = name + '_phase'
|
ph = name + '_phase'
|
||||||
rl = name + '_delay'
|
rl = name + '_delay'
|
||||||
|
|||||||
BIN
frappy_psi/tnmr/templates/tmp - Copy.tnt
Normal file
BIN
frappy_psi/tnmr/templates/tmp - Copy.tnt
Normal file
Binary file not shown.
Binary file not shown.
@@ -155,8 +155,8 @@ class TNMR:
|
|||||||
print('Zero-going...')
|
print('Zero-going...')
|
||||||
ntnmr = self.get_instance()
|
ntnmr = self.get_instance()
|
||||||
if not(self.acquisition_running()):
|
if not(self.acquisition_running()):
|
||||||
print('Reset')
|
#print('Reset')
|
||||||
ntnmr.Reset() # to avoid hardware issues? EDIT: Doesn't seem to do much...
|
#ntnmr.Reset() # to avoid hardware issues? EDIT: Doesn't seem to do much...
|
||||||
if(CHECK_MODE == 'data'):
|
if(CHECK_MODE == 'data'):
|
||||||
print('Artificially setting the zeroth point to NULL for error detection.')
|
print('Artificially setting the zeroth point to NULL for error detection.')
|
||||||
ntnmr.SetDataPoint(1, [0,0])
|
ntnmr.SetDataPoint(1, [0,0])
|
||||||
@@ -258,7 +258,7 @@ class TNMR:
|
|||||||
"""
|
"""
|
||||||
print('I: Saving')
|
print('I: Saving')
|
||||||
if filepath == '':
|
if filepath == '':
|
||||||
self.get_instance().Save
|
self.get_instance().Save()
|
||||||
else:
|
else:
|
||||||
self.get_instance().SaveAs(filepath)
|
self.get_instance().SaveAs(filepath)
|
||||||
print(f'I: Saved to file {filepath}')
|
print(f'I: Saved to file {filepath}')
|
||||||
@@ -378,6 +378,11 @@ class TNMR:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
ntnmr = self.get_instance()
|
ntnmr = self.get_instance()
|
||||||
|
|
||||||
|
if (self.acquisition_running()):
|
||||||
|
ntnmr.Abort()
|
||||||
|
print('W: Aborting currently running acquisition!')
|
||||||
|
|
||||||
print(f'Loading sequence at {filename}')
|
print(f'Loading sequence at {filename}')
|
||||||
ntnmr.CloseActiveFile()
|
ntnmr.CloseActiveFile()
|
||||||
success = ntnmr.OpenFile(TEMPLATE_FILE_PATH + 'tmp.tnt')
|
success = ntnmr.OpenFile(TEMPLATE_FILE_PATH + 'tmp.tnt')
|
||||||
@@ -411,6 +416,10 @@ class TNMR:
|
|||||||
else:
|
else:
|
||||||
print('W: Filenames do not match for sequence!')
|
print('W: Filenames do not match for sequence!')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
d = self.get_data()
|
||||||
|
ntnmr.ZeroFill(len(d[0])) # to clear everything out.
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def load_dashboard(self, dashboard_fn):
|
def load_dashboard(self, dashboard_fn):
|
||||||
|
|||||||
Reference in New Issue
Block a user