Compare commits

...

1 Commits

Author SHA1 Message Date
Ultrasound PC
a1fa9f1cbb version as of 2025-01-09 from ultrasound PC 2025-01-09 09:59:33 +01:00
12 changed files with 757 additions and 306 deletions

126
cfg/PEUS.cfg Normal file
View File

@ -0,0 +1,126 @@
[NODE]
id = ultrasound.psi.ch
description = ultrasound settings
[INTERFACE]
uri = tcp://5000
[f]
class = secop_psi.ultrasound.Frequency
description = ultrasound frequency and acquisition loop
uri = serial:///dev/ttyS1
pars = pars
pollinterval = 0.1
# this is the start time:
time = 900
size = 5000
freq = 1.17568e+06
basefreq = 4.14902e+07
control = True
amp = 5.0
nr = 1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #500
sr = 32768 #16384
plot = True
maxstep = 100000
bw = 10E6 #butter worth filter bandwidth
# y scale for plot:
maxy = 0.7
# module to transmit curves:
curves = curves
[curves]
class = secop_psi.ultrasound.Curves
description = t, I, Q and pulse arrays for plot
[roi0]
class = secop_psi.ultrasound.Roi
description = I/Q of region in the control loop.
# this is the center of roi:
time = 2450
size = 300
main = f
[roi1]
class = secop_psi.ultrasound.Roi
description = I/Q of region 1
time = 5950
size = 300
main = f
[roi2]
class = secop_psi.ultrasound.Roi
description = I/Q of region 2
# enable = False
time = 9475
size = 300
main = f
[roi3]
class = secop_psi.ultrasound.Roi
description = I/Q of region 3
#enable = False
time = 12900
size = 300
main = f
[roi4]
class = secop_psi.ultrasound.Roi
description = I/Q of region 4
enable = True
time = 16100
size = 300
main = f
[roi5]
class = secop_psi.ultrasound.Roi
description = I/Q of region 5
enable = False
time = 4000
size = 30
main = f
[roi6]
class = secop_psi.ultrasound.Roi
description = I/Q of region 6
enable = False
time = 4000
size = 200
main = f
[roi7]
class = secop_psi.ultrasound.Roi
description = I/Q of region 7
enable = False
time = 4000
size = 200
main = f
[roi8]
class = secop_psi.ultrasound.Roi
description = I/Q of region 8
enable = False
time = 4000
size = 200
main = f
[roi9]
class = secop_psi.ultrasound.Roi
description = I/Q of region 9
enable = False
time = 4000
size = 200
main = f
[delay]
class = secop_psi.dg645.Delay
description = delay line with 2 channels
#uri = dil4-ts.psi.ch:3008
uri = serial:///dev/ttyS2
on1 = 1e-9
on2 = 1E-9
off1 = 400e-9
off2 = 600e-9
[pars]
class = secop_psi.ultrasound.Pars
description = SEA parameters

63
cfg/RUS.cfg Normal file
View File

@ -0,0 +1,63 @@
[NODE]
id = ultrasound.psi.ch
description = resonant ultra sound setup
[INTERFACE]
uri = tcp://5000
[f]
class = secop_psi.ultrasound.Frequency
description = ultrasound frequency and acquisition loop
uri = serial:///dev/ttyS1
pars = pars
pollinterval = 0.1
# this is the start time:
time = 900
size = 5000
freq = 1.e+03
basefreq = 1.E+3
control = False
rusmode = False
amp = 2.5
nr = 1 #500 #300 #100 #50 #30 #10 #5 #3 #1 #1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #500
sr = 1E8 #16384
plot = True
maxstep = 100000
bw = 10E6 #butter worth filter bandwidth
# y scale for plot:
maxy = 0.7
# module to transmit curves:
curves = curves
[curves]
class = secop_psi.ultrasound.Curves
description = t, I, Q and pulse arrays for plot
[roi0]
class = secop_psi.ultrasound.Roi
description = I/Q of region in the control loop.
# this is the center of roi:
time = 300
size = 5000
main = f
[roi1]
class = secop_psi.ultrasound.Roi
description = I/Q of region 1
time = 100
size = 300
main = f
[delay]
class = secop_psi.dg645.Delay
description = delay line with 2 channels
#uri = dil4-ts.psi.ch:3008
uri = serial:///dev/ttyS2
on1 = 1e-9
on2 = 1E-9
off1 = 400e-9
off2 = 600e-9
[pars]
class = secop_psi.ultrasound.Pars
description = SEA parameters

17
cfg/dg.cfg Normal file
View File

@ -0,0 +1,17 @@
[node ultrasound.psi.ch]
description = ultrasound settings
[interface tcp]
type = tcp
bindto = 0.0.0.0
bindport = 5000
[module delay]
class = secop_psi.dg645.Delay
description = delay line with 2 channels
#uri = dil4-ts.psi.ch:3008
uri = serial:///dev/ttyS2
on1 = 10e-9
on2 = 1E-9
off1 = 250e-9
off2 = 550e-9

126
cfg/ultrasound.cfg Normal file
View File

@ -0,0 +1,126 @@
[NODE]
id = ultrasound.psi.ch
description = ultrasound settings
[INTERFACE]
uri = tcp://5000
[f]
class = secop_psi.ultrasound.Frequency
description = ultrasound frequency and acquisition loop
uri = serial:///dev/ttyS1
pars = pars
pollinterval = 0.1
# this is the start time:
time = 900
size = 5000
freq = 1.17568e+06
basefreq = 4.14902e+07
control = True
amp = 5.0
nr = 1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #500
sr = 32768 #16384
plot = True
maxstep = 100000
bw = 10E6 #butter worth filter bandwidth
# y scale for plot:
maxy = 0.7
# module to transmit curves:
curves = curves
[curves]
class = secop_psi.ultrasound.Curves
description = t, I, Q and pulse arrays for plot
[roi0]
class = secop_psi.ultrasound.Roi
description = I/Q of region in the control loop.
# this is the center of roi:
time = 2450
size = 300
main = f
[roi1]
class = secop_psi.ultrasound.Roi
description = I/Q of region 1
time = 5950
size = 300
main = f
[roi2]
class = secop_psi.ultrasound.Roi
description = I/Q of region 2
# enable = False
time = 9475
size = 300
main = f
[roi3]
class = secop_psi.ultrasound.Roi
description = I/Q of region 3
#enable = False
time = 12900
size = 300
main = f
[roi4]
class = secop_psi.ultrasound.Roi
description = I/Q of region 4
enable = True
time = 16100
size = 300
main = f
[roi5]
class = secop_psi.ultrasound.Roi
description = I/Q of region 5
enable = False
time = 4000
size = 30
main = f
[roi6]
class = secop_psi.ultrasound.Roi
description = I/Q of region 6
enable = False
time = 4000
size = 200
main = f
[roi7]
class = secop_psi.ultrasound.Roi
description = I/Q of region 7
enable = False
time = 4000
size = 200
main = f
[roi8]
class = secop_psi.ultrasound.Roi
description = I/Q of region 8
enable = False
time = 4000
size = 200
main = f
[roi9]
class = secop_psi.ultrasound.Roi
description = I/Q of region 9
enable = False
time = 4000
size = 200
main = f
[delay]
class = secop_psi.dg645.Delay
description = delay line with 2 channels
#uri = dil4-ts.psi.ch:3008
uri = serial:///dev/ttyS2
on1 = 1e-9
on2 = 1E-9
off1 = 400e-9
off2 = 600e-9
[pars]
class = secop_psi.ultrasound.Pars
description = SEA parameters

127
ftune.py Normal file
View File

@ -0,0 +1,127 @@
import PySimpleGUI as sg
import time
import sys
sys.path.append(r'/Users/bartkowiak/Programs/frappy/frappy')
from secop.client import SecopClient
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
from numpy.random import rand
import numpy as np
def draw_figure(canvas, figure):
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw()
figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
return figure_canvas_agg
def upd_flim(inp):
return int(inp)
def connection_handler(sec,status,IP,port, cstate):
if cstate == -1 and status == False:
try :
cstate = 1
#sock.connect((IP,int(port)))
sec = SecopClient(IP+':'+port)
sec.connect()
sec.setParameter('f','control',False)
status = False
except :
cstate = -1
status = True
elif status == True and cstate == 1 :
status = False
sec.disconnect()
#sock.close()
cstate = -1
return cstate, status,sec
def new_xy(sec, cstate):
xn = 0
yn = 0
if cstate == 1:
try:
xn = sec.getParameter('roi0','i')[0]
yn = sec.getParameter('roi0','q')[0]
except:
pass
return xn, yn
def send_new_f(sec, cstate, freq):
if cstate == 1:
freq = sec.setParameter('f','basefreq',freq)
return freq
# THIS IS THE MAIN LOOP
def main(): # define the main loop
freq = '10000000'
f_start = 39000000
f_end = 42000000
new_f = f_start
down = True
down2 = True
cstate = -1
tstart = time.time()
x = np.array([])
y = np.array([])
IP = 'pc13252'
port = '5000'
sec = SecopClient(IP+':'+port)
layout = [ [sg.Text('Frequency Tuner)')],
[sg.Text('IP\t\t:',font= ("Helvetica",22)),sg.InputText(key='_IP_',default_text=IP,font= ("Helvetica",22),size=(15,1))],
[sg.Text('PORT\t\t:',font= ("Helvetica",22)),sg.InputText(key='_PORT_',default_text=port,font= ("Helvetica",22),size=(15,1)),sg.T(' ' * 41), sg.Button('connect',key='connect',font= ("Helvetica",22))],
[sg.Text('Start Frequency\t:',font= ("Helvetica",22)),sg.InputText(key='_f_start_', default_text='39000000',font= ("Helvetica",22),size=(15,1))],
[sg.Text('Stop Frequency\t:',font= ("Helvetica",22)),sg.InputText(key='_f_end_',default_text='45000000',font= ("Helvetica",22),size=(15,1))],
[sg.Slider(range=(f_start, f_end),key='_SLtune_', orientation='h',font= ("Helvetica",22), size=(35, 20), default_value=f_start),sg.T(' ' * 2),sg.Button('sweep',key='sweep',font= ("Helvetica",22))],
[sg.Canvas(size=(640, 480), key='-CANVAS-')],
[sg.Button('Exit',font= ("Helvetica",22)),sg.T(' ' * 150),sg.Button('Clear Plot',key='clp',font= ("Helvetica",22))] ] # a couple of buttons
window = sg.Window('Frequency tuner', layout, finalize=True)
canvas_elem = window['-CANVAS-']
canvas = canvas_elem.TKCanvas
# draw the intitial scatter plot
fig, ax = plt.subplots()
ax.grid(True)
fig_agg = draw_figure(canvas, fig)
while True:
# Event Loop
event, values = window.Read(timeout=0.5)
if event in (None, 'Exit'): # checks if user wants to exit
if cstate == 1:
connection_handler(sec,True,values['_IP_'],values['_PORT_'],cstate)
break
if event == 'connect':
down = not down
window['connect'].Update(('disconnect','connect')[down])
cstate, down, sec = connection_handler(sec,down,values['_IP_'],values['_PORT_'],cstate)
if event == 'sweep':
down2 = not down2
window['sweep'].Update(('sweeping','sweep')[down2])
#if event in ('_SL8_','_SL6_','_SL4_','_SL2_'): # the two lines of code needed to get button and run command
#freq = update_freq(inp=[values['_SL8_'],values['_SL6_'],values['_SL4_'],values['_SL2_']])
if down2 == False:
if time.time() - tstart > 1.:
tstart = time.time()
new_f = int(int(values['_SLtune_']) + (int(values['_f_end_'])-int(values['_f_start_']))/200)
send_new_f(sec,cstate,new_f)
window['_SLtune_'].Update(value=new_f)
if event == 'clp':
x = np.array([])
y = np.array([])
window['_SLtune_'].Update(range=(int(values['_f_start_']),int(values['_f_end_'])))
xn,yn = new_xy(sec,cstate)
ax.cla()
ax.grid(True)
x = np.append(x,xn)
y = np.append(y,yn)
ax.plot(x, y)
fig_agg.draw()
window.Close()
if __name__ == '__main__':
main()

View File

@ -44,3 +44,4 @@ ERROR = Drivable.Status.ERROR
WARN = Drivable.Status.WARN WARN = Drivable.Status.WARN
BUSY = Drivable.Status.BUSY BUSY = Drivable.Status.BUSY
IDLE = Drivable.Status.IDLE IDLE = Drivable.Status.IDLE
DISABLED = Drivable.Status.DISABLED

View File

@ -760,7 +760,7 @@ class ArrayOf(DataType):
def __call__(self, value): def __call__(self, value):
"""validate an external representation to an internal one""" """validate an external representation to an internal one"""
if isinstance(value, (tuple, list)): try:
# check number of elements # check number of elements
if self.minlen is not None and len(value) < self.minlen: if self.minlen is not None and len(value) < self.minlen:
raise BadValueError( raise BadValueError(
@ -768,11 +768,12 @@ class ArrayOf(DataType):
self.minlen) self.minlen)
if self.maxlen is not None and len(value) > self.maxlen: if self.maxlen is not None and len(value) > self.maxlen:
raise BadValueError( raise BadValueError(
'Array too big, holds at most %d elements!' % self.minlen) 'Array too big, holds at most %d elements!' % self.maxlen)
# apply subtype valiation to all elements and return as list # apply subtype valdiation to all elements and return as list
return tuple(self.members(elem) for elem in value) return tuple(self.members(elem) for elem in value)
raise BadValueError( except TypeError:
'Can not convert %s to ArrayOf DataType!' % repr(value)) raise BadValueError('%s can not be converted to ArrayOf DataType!'
% type(value).__name__) from None
def export_value(self, value): def export_value(self, value):
"""returns a python object fit for serialisation""" """returns a python object fit for serialisation"""
@ -842,6 +843,7 @@ class TupleOf(DataType):
return tuple(sub(elem) return tuple(sub(elem)
for sub, elem in zip(self.members, value)) for sub, elem in zip(self.members, value))
except Exception as exc: except Exception as exc:
print(value)
raise BadValueError('Can not validate:', str(exc)) from None raise BadValueError('Can not validate:', str(exc)) from None
def export_value(self, value): def export_value(self, value):

View File

@ -47,7 +47,7 @@ class SilentError(CommunicationFailedError):
class HasIO(Module): class HasIO(Module):
"""Mixin for modules using a communicator""" """Mixin for modules using a communicator"""
io = Attached() io = Attached(mandatory=False)
uri = Property('uri for automatic creation of the attached communication module', uri = Property('uri for automatic creation of the attached communication module',
StringType(), default='') StringType(), default='')

View File

@ -500,10 +500,11 @@ class Module(HasAccessibles):
# TODO: remove readerror 'property' and replace value with exception # TODO: remove readerror 'property' and replace value with exception
pobj = self.parameters[pname] pobj = self.parameters[pname]
timestamp = timestamp or time.time() timestamp = timestamp or time.time()
changed = pobj.value != value
try: try:
value = pobj.datatype(value)
changed = pobj.value != value
# store the value even in case of error # store the value even in case of error
pobj.value = pobj.datatype(value) pobj.value = value
except Exception as e: except Exception as e:
if isinstance(e, DiscouragedConversion): if isinstance(e, DiscouragedConversion):
if DiscouragedConversion.log_message: if DiscouragedConversion.log_message:

View File

@ -149,6 +149,9 @@ class Parameter(Accessible):
default None: write if given in config''', NoneOr(BoolType()), default None: write if given in config''', NoneOr(BoolType()),
export=False, default=None, settable=False) export=False, default=None, settable=False)
# used in NICOS only ...
nicos_category = Property(
'''NICOS parameter category''', StringType(), export=True, default='')
# used on the instance copy only # used on the instance copy only
value = None value = None

View File

@ -6,15 +6,17 @@ Created on Tue Nov 26 15:42:43 2019
""" """
import sys
import atexit
import signal
import time
import numpy as np import numpy as np
import ctypes as ct import ctypes as ct
import time
from numpy import sqrt, arctan2, sin, cos from numpy import sqrt, arctan2, sin, cos
import scipy.signal
#from pylab import * #from pylab import *
from scipy import signal
#ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll") #ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll")
ADQAPI = ct.cdll.LoadLibrary("libadq.so.0") ADQAPI = ct.cdll.LoadLibrary("libadq.so.0")
@ -37,7 +39,7 @@ ADQ_CHANNELS_MASK = 0x3
def butter_lowpass(cutoff, sr, order=5): def butter_lowpass(cutoff, sr, order=5):
nyq = 0.5 * sr nyq = 0.5 * sr
normal_cutoff = cutoff / nyq normal_cutoff = cutoff / nyq
b, a = signal.butter(order, normal_cutoff, btype = 'low', analog = False) b, a = scipy.signal.butter(order, normal_cutoff, btype = 'low', analog = False)
return b, a return b, a
@ -125,6 +127,8 @@ class Adq(object):
# print('SetTriggerThresholdVoltage failed.') # print('SetTriggerThresholdVoltage failed.')
print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num)))) print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num))))
self.setup_target_buffers() self.setup_target_buffers()
atexit.register(self.deletecu)
signal.signal(signal.SIGTERM, lambda *_: sys.exit(0))
def setup_target_buffers(self): def setup_target_buffers(self):
# Setup target buffers for data # Setup target buffers for data
@ -139,9 +143,10 @@ class Adq(object):
ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num); ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num);
# Delete ADQControlunit # Delete ADQControlunit
ADQAPI.DeleteADQControlUnit(self.adq_cu) ADQAPI.DeleteADQControlUnit(self.adq_cu)
print('ADQ closed')
def start(self): def start(self):
"""start datat acquisition""" """start data acquisition"""
# samples_per_records = samples_per_record/number_of_records # samples_per_records = samples_per_record/number_of_records
# Change number of pulses to be acquired acording to how many records are taken # Change number of pulses to be acquired acording to how many records are taken
# Start acquisition # Start acquisition
@ -177,52 +182,7 @@ class Adq(object):
def acquire(self): def acquire(self):
self.start() self.start()
return self.getdata() return self.getdata()
'''
def average(self, data):
#Average over records
return [data[ch].sum(axis=0) / self.number_of_records for ch in range(2)]
def iq(self, channel, f_LO):
newx = np.linspace(0, self.samples_per_record /2, self.samples_per_record)
s0 = channel /((2**16)/2)*0.5*np.exp(1j*2*np.pi*f_LO/(1e3)*newx)
I0 = s0.real
Q0 = s0.imag
return I0, Q0
def fitting(self, data, f_LO, ti, tf):
# As long as data[0] is the pulse
si = 2*ti #Those are for fitting the pulse
sf = 2*tf
phase = np.zeros(self.number_of_records)
amplitude = np.zeros(self.number_of_records)
offset = np.zeros(self.number_of_records)
for i in range(self.number_of_records):
phase[i], amplitude[i] = sineW(data[0][i][si:sf],f_LO*1e-9,ti,tf)
offset[i] = np.average(data[0][i][si:sf])
return phase, amplitude, offset
def waveIQ(self, channel,ti,f_LO):
#channel is not the sample data
t = np.linspace(0, self.samples_per_record /2, self.samples_per_record + 1)[:-1]
si = 2*ti # Again that is where the wave pulse starts
cwi = np.zeros((self.number_of_records,self.samples_per_record))
cwq = np.zeros((self.number_of_records,self.samples_per_record))
iq = np.zeros((self.number_of_records,self.samples_per_record))
q = np.zeros((self.number_of_records,self.samples_per_record))
for i in range(self.number_of_records):
cwi[i] = np.zeros(self.samples_per_record)
cwq[i] = np.zeros(self.samples_per_record)
cwi[i] = amplitude[i]*sin(t[si:]*f_LO*1e-9*2*np.pi+phase[i]*np.pi/180)+bias[i]
cwq[i] = amplitude[i]*sin(t[si:]*f_LO*1e-9*(2*np.pi+(phase[i]+90)*np.pi/180))+bias[i]
iq[i] = channel[i]*cwi[i]
q[i] = channel[i]*cwq[i]
return iq,q
'''
def sinW(self,sig,freq,ti,tf): def sinW(self,sig,freq,ti,tf):
# sig: signal array # sig: signal array
# freq # freq
@ -262,9 +222,9 @@ class Adq(object):
def filtro(self, iorq, cutoff): def filtro(self, iorq, cutoff):
b, a = butter_lowpass(cutoff, self.samp_freq*1e9) b, a = butter_lowpass(cutoff, self.samp_freq*1e9)
#ifi = np.array(signal.filtfilt(b,a,iorq[0])) #ifi = np.array(scipy.signal.filtfilt(b,a,iorq[0]))
#qf = np.array(signal.filtfilt(b,a,iorq[1])) #qf = np.array(scipy.signal.filtfilt(b,a,iorq[1]))
iqf = [signal.filtfilt(b,a,iorq[i]) for i in np.arange(len(iorq))] iqf = [scipy.signal.filtfilt(b,a,iorq[i]) for i in np.arange(len(iorq))]
return iqf return iqf
@ -276,12 +236,15 @@ class Adq(object):
def gates_and_curves(self, data, freq, pulse, roi): def gates_and_curves(self, data, freq, pulse, roi):
"""return iq values of rois and prepare plottable curves for iq""" """return iq values of rois and prepare plottable curves for iq"""
self.ndecimate = int(round(2E9/freq))
times = [] times = []
times.append(('aviq', time.time())) times.append(('aviq', time.time()))
iq = self.averageiq(data,freq*1e-9,*pulse) iq = self.averageiq(data,freq*1e-9,*pulse)
times.append(('filtro', time.time())) times.append(('filtro', time.time()))
iqf = self.filtro(iq,self.bw_cutoff) iqf = self.filtro(iq,self.bw_cutoff)
m = len(iqf[0]) // self.ndecimate m = len(iqf[0]) // self.ndecimate
ll = m * self.ndecimate
iqf = [iqfx[0:ll] for iqfx in iqf]
times.append(('iqdec', time.time())) times.append(('iqdec', time.time()))
iqd = np.average(np.resize(iqf, (2, m, self.ndecimate)), axis=2) iqd = np.average(np.resize(iqf, (2, m, self.ndecimate)), axis=2)
t_axis = np.arange(m) * self.ndecimate / self.samp_freq t_axis = np.arange(m) * self.ndecimate / self.samp_freq

View File

@ -30,7 +30,8 @@ import numpy as np
import secop_psi.iqplot as iqplot import secop_psi.iqplot as iqplot
from secop_psi.adq_mr import Adq from secop_psi.adq_mr import Adq
from secop.core import Attached, BoolType, Done, FloatRange, HasIO, \ from secop.core import Attached, BoolType, Done, FloatRange, HasIO, \
IntRange, Module, Parameter, Readable, StringIO, StringType IntRange, Module, Parameter, Readable, StringIO, StringType, \
IDLE, DISABLED, TupleOf, ArrayOf
from secop.properties import Property from secop.properties import Property
@ -54,7 +55,6 @@ class Roi(Readable):
time = Parameter('start time', FloatRange(unit='nsec'), readonly=False) time = Parameter('start time', FloatRange(unit='nsec'), readonly=False)
size = Parameter('interval (symmetric around time)', FloatRange(unit='nsec'), readonly=False) size = Parameter('interval (symmetric around time)', FloatRange(unit='nsec'), readonly=False)
enable = Parameter('calculate this roi', BoolType(), readonly=False, default=True) enable = Parameter('calculate this roi', BoolType(), readonly=False, default=True)
#status = Parameter(export=False)
pollinterval = Parameter(export=False) pollinterval = Parameter(export=False)
interval = (0,0) interval = (0,0)
@ -67,6 +67,9 @@ class Roi(Readable):
def calc_interval(self): def calc_interval(self):
self.interval = (self.time - 0.5 * self.size, self.time + 0.5 * self.size) self.interval = (self.time - 0.5 * self.size, self.time + 0.5 * self.size)
def read_status(self):
return (IDLE, '') if self.enable else (DISABLED, 'disabled')
def write_time(self, value): def write_time(self, value):
self.time = value self.time = value
self.calc_interval() self.calc_interval()
@ -84,7 +87,7 @@ class Pars(Module):
timestamp = Parameter('unix timestamp', StringType(), default='0', readonly=False) timestamp = Parameter('unix timestamp', StringType(), default='0', readonly=False)
temperature = Parameter('T', FloatRange(unit='K'), default=0, readonly=False) temperature = Parameter('T', FloatRange(unit='K'), default=0, readonly=False)
mf = Parameter('field', FloatRange(unit='T'), default=0, readonly=False) mf = Parameter('field', FloatRange(unit='T'), default=0, readonly=False)
sr = Parameter('rotaion angle', FloatRange(unit='deg'), default=0, readonly=False) sr = Parameter('rotation angle', FloatRange(unit='deg'), default=0, readonly=False)
class FreqStringIO(StringIO): class FreqStringIO(StringIO):
@ -93,16 +96,19 @@ class FreqStringIO(StringIO):
class Frequency(HasIO, Readable): class Frequency(HasIO, Readable):
pars = Attached() pars = Attached()
sr = Property('samples per record', datatype=IntRange(), default=16384) curves = Attached(mandatory=False)
# sr = Property('samples per record', datatype=IntRange(), default=16384)
maxy = Property('plot y scale', datatype=FloatRange(), default=0.5) maxy = Property('plot y scale', datatype=FloatRange(), default=0.5)
value = Parameter('frequency@I,q', datatype=FloatRange(unit='Hz'), default=0) value = Parameter('frequency@I,q', datatype=FloatRange(unit='Hz'), default=0)
basefreq = Parameter('base frequency', FloatRange(unit='Hz'), readonly=False) basefreq = Parameter('base frequency', FloatRange(unit='Hz'), readonly=False)
nr = Parameter('number of records', datatype=IntRange(1,10000), default=500) nr = Parameter('number of records', datatype=IntRange(1,10000), default=500)
sr = Parameter('samples per record', datatype=IntRange(1,1E9), default=16384)
freq = Parameter('target frequency', FloatRange(unit='Hz'), readonly=False) freq = Parameter('target frequency', FloatRange(unit='Hz'), readonly=False)
bw = Parameter('bandwidth lowpassfilter', datatype=FloatRange(unit='Hz'),default=10E6) bw = Parameter('bandwidth lowpassfilter', datatype=FloatRange(unit='Hz'),default=10E6)
amp = Parameter('amplitude', FloatRange(unit='dBm'), readonly=False) amp = Parameter('amplitude', FloatRange(unit='dBm'), readonly=False)
control = Parameter('control loop on?', BoolType(), readonly=False, default=True) control = Parameter('control loop on?', BoolType(), readonly=False, default=True)
rusmode = Parameter('RUS mode on?', BoolType(), readonly=False, default=False)
time = Parameter('pulse start time', FloatRange(unit='nsec'), time = Parameter('pulse start time', FloatRange(unit='nsec'),
readonly=False) readonly=False)
size = Parameter('pulse length (starting from time)', FloatRange(unit='nsec'), size = Parameter('pulse length (starting from time)', FloatRange(unit='nsec'),
@ -130,6 +136,7 @@ class Frequency(HasIO, Readable):
self.adq = Adq(self.nr, self.sr, self.bw) self.adq = Adq(self.nr, self.sr, self.bw)
self.roilist = [] self.roilist = []
self.write_nr(self.nr) self.write_nr(self.nr)
self.write_sr(self.sr)
self.skipctrl = 0 self.skipctrl = 0
self.plotter = iqplot.Plot(self.maxy) self.plotter = iqplot.Plot(self.maxy)
self.calc_interval() self.calc_interval()
@ -151,6 +158,9 @@ class Frequency(HasIO, Readable):
# self.pollinterval = value * 0.0001 # self.pollinterval = value * 0.0001
return value return value
def write_sr(self, value):
return value
def register_roi(self, roi): def register_roi(self, roi):
self.roilist.append(roi) self.roilist.append(roi)
@ -176,7 +186,11 @@ class Frequency(HasIO, Readable):
"""main poll loop body""" """main poll loop body"""
if self.lastfreq is None: if self.lastfreq is None:
self.lastfreq = self.set_freq() self.lastfreq = self.set_freq()
if self.rusmode:
self.sr = int(12e9/self.lastfreq) #picking up 12 period at the ith frequency in the time scale
# self.adq.samples_per_record = self.sr
self.adq.start() self.adq.start()
if self.starttime is None: if self.starttime is None:
self.starttime = time.time() self.starttime = time.time()
times = [] times = []
@ -200,6 +214,8 @@ class Frequency(HasIO, Readable):
gates = self.adq.gates_and_curves(data, freq, self.interval, gates = self.adq.gates_and_curves(data, freq, self.interval,
[r.interval for r in roilist]) [r.interval for r in roilist])
if self.curves: # if attached Curves module is defined, update it
self.curves.value = self.adq.curves
if self.save: if self.save:
times.append(('save',time.time())) times.append(('save',time.time()))
tdata, idata, qdata, pdata = self.adq.curves tdata, idata, qdata, pdata = self.adq.curves
@ -259,3 +275,9 @@ class Frequency(HasIO, Readable):
self.freq = sorted((self.freq - self.maxstep, newfreq, self.freq + self.maxstep))[1] self.freq = sorted((self.freq - self.maxstep, newfreq, self.freq + self.maxstep))[1]
#print(times) #print(times)
return Done return Done
class Curves(Readable):
value = Parameter("t, i, q, pulse curves",
TupleOf(*[ArrayOf(FloatRange(), 0, 16283) for _ in range(4)]), default=[[]] * 4)