Added functionality for the TNMR module to write partial scans - useful for long experiments with many acquisitions, which might need to be terminated early. Also good for impatient people. Added functionality to the ZVL Network Analyser module to allow for use of inbuilt data correction (calibration).
This commit is contained in:
@@ -30,32 +30,50 @@ class ZVLNetAnalyzer():
|
||||
self.base_data = np.array([])
|
||||
self.base_data = self.get_data()[1]
|
||||
|
||||
self.min_freq = 0
|
||||
self.max_freq = 0
|
||||
|
||||
def reset(self):
|
||||
#self.instrument.write('*RST')
|
||||
#self.instrument.write('SYST:PRES') # reloads current setup.
|
||||
self.instrument.write('*CLS')
|
||||
self.instrument.write('*RST')
|
||||
self.instrument.write('INST:NSEL 2')
|
||||
self.instrument.write('DISPlay:WINDow1:STATe ON')
|
||||
self.instrument.write(":CALC:PAR:MEAS 'Trc1', 'S11'")
|
||||
self.instrument.write('CALC:FORM MLOG')
|
||||
self.instrument.write('INIT:CONT OFF')
|
||||
self.instrument.write("SYST:USER:DISP:TITL 'Frappy connection'")
|
||||
#self.instrument.write('INIT:SCOP OFF')
|
||||
#self.instrument.write('DISPlay:WINDow2:STATe ON')
|
||||
self.instrument.write('*ESE')
|
||||
|
||||
self.min_freq, self.max_freq = self.get_freq_range() # default is largest.
|
||||
|
||||
def load_calibration(self, f):
|
||||
self.instrument.write(f":MMEMORY:STORE:CORR 1, 'OSM1 {f}'") # put calibration in pool
|
||||
self.instrument.write(f":MMEMORY:LOAD:CORR 1, 'OSM1 {f}'") # load from pool
|
||||
def reload_calibration(self):
|
||||
self.reset()
|
||||
#self.instrument.write("DISP:MENU:KEY:SEL 'Correction Off'")
|
||||
#self.instrument.write("DISP:MENU:KEY:EXEC 'Correction Off'")
|
||||
self.instrument.write("DISP:MENU:KEY:EXEC 'Recall Last Cal Set'")
|
||||
time.sleep(1)
|
||||
self.min_freq, self.max_freq = self.get_freq_range() # default is largest.
|
||||
|
||||
def get_freq_range(self):
|
||||
start = float(self.instrument.ask('SENS1:FREQ:STAR?'))
|
||||
stop = float(self.instrument.ask('SENS1:FREQ:STOP?'))
|
||||
|
||||
return start, stop
|
||||
|
||||
def set_freq_range(self, start, stop):
|
||||
'''In Hz'''
|
||||
self.instrument.write(f'SENS1:FREQ:STAR {start}')
|
||||
self.instrument.write(f'SENS1:FREQ:STOP {stop}')
|
||||
if(start >= self.min_freq) and (stop <= self.max_freq):
|
||||
|
||||
self.instrument.write(f'SENS1:FREQ:STAR {start}')
|
||||
self.instrument.write(f'SENS1:FREQ:STOP {stop}')
|
||||
self.start_freq = start
|
||||
self.stop_freq = stop
|
||||
|
||||
def set_freq_span(self, center, span):
|
||||
'''In Hz'''
|
||||
self.instrument.write(f'SENS1:FREQ:CENT {center}')
|
||||
self.instrument.write(f'SENS1:FREQ:SPAN {span}')
|
||||
start = center - span/2
|
||||
stop = center + span/2
|
||||
|
||||
self.set_freq_range(start, stop)
|
||||
|
||||
def set_averaging_passes(self,avgs):
|
||||
'''
|
||||
@@ -101,6 +119,7 @@ class ZVLNetAnalyzer():
|
||||
assert(averaging_passes<=999)
|
||||
assert(units in ['dB', 'unitless'])
|
||||
|
||||
self.instrument.write('INIT:CONT OFF')
|
||||
self.instrument.write(f'SWE:POIN {N}')
|
||||
self.instrument.write(f'SWE:COUN {averaging_passes}')
|
||||
|
||||
|
||||
50
frappy_psi/network_analysers/ZVL/test.py
Normal file
50
frappy_psi/network_analysers/ZVL/test.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from ZVLDriver import *
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
# example code. profiles the per-point delay for reading data and
|
||||
ip = '129.129.156.201'
|
||||
ip = '169.254.83.53'
|
||||
import matplotlib.pyplot as plt
|
||||
print('start')
|
||||
z = ZVLNetAnalyzer()
|
||||
z.reset()
|
||||
|
||||
|
||||
#mm, mmi, fr, frq = z.find_peak(50_000_000, 350_000_000, 20_000_000)
|
||||
#plt.plot(frq, fr)
|
||||
#plt.axvline(frq[mmi])
|
||||
#plt.axhline(mm)
|
||||
#plt.show()
|
||||
|
||||
#z.reset()
|
||||
##z.set_freq_range(1_000_000, 2_000_000.5)
|
||||
##z.set_freq_span(1_000_000, 10_000)
|
||||
z.set_freq_range(25_750_000, 75_250_000)
|
||||
plt.scatter(*(z.get_data()))
|
||||
|
||||
z.reload_calibration()
|
||||
#z.set_freq_span(220_000_000, 50_000_000)
|
||||
plt.scatter(*(z.get_data()))
|
||||
plt.show()
|
||||
|
||||
#Ns = np.linspace(3, 1000, 100).astype(int)
|
||||
#ts = []
|
||||
#for N in Ns:
|
||||
# st = time.time()
|
||||
# freqs, data = z.get_data(N)
|
||||
# et = time.time()
|
||||
# dt = (et-st)
|
||||
# print(f'got data, {dt/N} ({dt})')
|
||||
# ts += [dt]
|
||||
#
|
||||
#plt.scatter(Ns, ts)
|
||||
#plt.show()
|
||||
#plt.scatter(Ns, np.array(ts)/np.array(Ns))
|
||||
#plt.show()
|
||||
|
||||
#input()
|
||||
#plt.plot(*z.get_data(averaging_passes=1), alpha=0.3)
|
||||
#plt.plot(*z.get_data(averaging_passes=64), alpha=0.3)
|
||||
#plt.show()
|
||||
|
||||
input()
|
||||
@@ -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)
|
||||
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', ...)
|
||||
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
|
||||
|
||||
Commands
|
||||
@@ -86,6 +86,7 @@ class ProgrammedSequence(fc.Readable):
|
||||
pulse_height=fc.FloatRange(unit='%'),
|
||||
delay_time=fc.FloatRange(unit='usecs'),
|
||||
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
|
||||
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
|
||||
@@ -93,7 +94,7 @@ class ProgrammedSequence(fc.Readable):
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
@@ -194,14 +195,14 @@ class ProgrammedSequence(fc.Readable):
|
||||
self.status = ('IDLE', 'ok - uncompiled')
|
||||
return self.read_acq_phase_cycle()
|
||||
|
||||
def read_num_scans(self):
|
||||
def read_num_acqs(self):
|
||||
return self.tnmr().get_nmrparameter('Scans 1D')
|
||||
|
||||
def write_num_scans(self, t):
|
||||
def write_num_acqs(self, t):
|
||||
if(self.status[0] != 'BUSY'):
|
||||
self.tnmr().set_nmrparameter('Scans 1D', t)
|
||||
self.status = ('IDLE', 'ok - uncompiled')
|
||||
return self.read_num_scans()
|
||||
return self.read_num_acqs()
|
||||
|
||||
def read_obs_freq(self):
|
||||
return self.tnmr().get_nmrparameter('Observe Freq.')
|
||||
@@ -221,6 +222,34 @@ class ProgrammedSequence(fc.Readable):
|
||||
self.sequence_data = seq
|
||||
|
||||
return self.read_sequence_data()
|
||||
|
||||
def read_status(self):
|
||||
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 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 n
|
||||
except:
|
||||
return 0
|
||||
|
||||
### PRIVATE (Utility)
|
||||
def __compile_sequence(self):
|
||||
@@ -266,7 +295,7 @@ class ProgrammedSequence(fc.Readable):
|
||||
seq_gen.save_sequence_cfg(filename, seq)
|
||||
|
||||
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
|
||||
@@ -274,7 +303,7 @@ class ProgrammedSequence(fc.Readable):
|
||||
self.compiled_parameters['acquisition_time'] = self.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['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['title'] = self.read_title()
|
||||
self.compiled_parameters['comments'] = self.read_comments()
|
||||
@@ -303,13 +332,7 @@ class ProgrammedSequence(fc.Readable):
|
||||
'''Tells TNMR to acquire data. Only call after __compile_sequence().'''
|
||||
if(self.status[0] != 'BUSY'):
|
||||
self.status = ('BUSY', 'acquiring')
|
||||
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')
|
||||
self.tnmr().ZeroGo(lock=False, check_time=max(self.approx_sequence_length*5, 5))
|
||||
|
||||
def __compile_and_run(self, thread=True):
|
||||
'''Compiles and runs the currently-loaded sequence
|
||||
|
||||
@@ -411,6 +411,10 @@ class TNMR:
|
||||
else:
|
||||
print('W: Filenames do not match for sequence!')
|
||||
return False
|
||||
|
||||
d = self.get_data()
|
||||
ntnmr.ZeroFill(len(d[0])) # to clear everything out.
|
||||
|
||||
return True
|
||||
|
||||
def load_dashboard(self, dashboard_fn):
|
||||
|
||||
Reference in New Issue
Block a user