Compare commits
1 Commits
wip
...
ultrasound
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a1fa9f1cbb |
126
cfg/PEUS.cfg
Normal file
126
cfg/PEUS.cfg
Normal 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
63
cfg/RUS.cfg
Normal 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
17
cfg/dg.cfg
Normal 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
126
cfg/ultrasound.cfg
Normal 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
127
ftune.py
Normal 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()
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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='')
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -1,294 +1,257 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Created on Tue Nov 26 15:42:43 2019
|
Created on Tue Nov 26 15:42:43 2019
|
||||||
|
|
||||||
@author: tartarotti_d-adm
|
@author: tartarotti_d-adm
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import numpy as np
|
import sys
|
||||||
import ctypes as ct
|
import atexit
|
||||||
import time
|
import signal
|
||||||
from numpy import sqrt, arctan2, sin, cos
|
import time
|
||||||
|
import numpy as np
|
||||||
#from pylab import *
|
import ctypes as ct
|
||||||
|
from numpy import sqrt, arctan2, sin, cos
|
||||||
from scipy import signal
|
import scipy.signal
|
||||||
|
|
||||||
#ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll")
|
#from pylab import *
|
||||||
ADQAPI = ct.cdll.LoadLibrary("libadq.so.0")
|
|
||||||
|
#ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll")
|
||||||
#For different trigger modes
|
ADQAPI = ct.cdll.LoadLibrary("libadq.so.0")
|
||||||
SW_TRIG = 1
|
|
||||||
EXT_TRIG_1 = 2 #This external trigger does not work if the level of the trigger is very close to 0.5V. Now we have it close to 3V, and it works
|
#For different trigger modes
|
||||||
EXT_TRIG_2 = 7
|
SW_TRIG = 1
|
||||||
EXT_TRIG_3 = 8
|
EXT_TRIG_1 = 2 #This external trigger does not work if the level of the trigger is very close to 0.5V. Now we have it close to 3V, and it works
|
||||||
LVL_TRIG = 3
|
EXT_TRIG_2 = 7
|
||||||
INT_TRIG = 4
|
EXT_TRIG_3 = 8
|
||||||
LVL_FALLING = 0
|
LVL_TRIG = 3
|
||||||
LVL_RISING = 1
|
INT_TRIG = 4
|
||||||
|
LVL_FALLING = 0
|
||||||
#samples_per_record=16384
|
LVL_RISING = 1
|
||||||
ADQ_TRANSFER_MODE_NORMAL = 0x00
|
|
||||||
ADQ_CHANNELS_MASK = 0x3
|
#samples_per_record=16384
|
||||||
|
ADQ_TRANSFER_MODE_NORMAL = 0x00
|
||||||
#f_LO = 40
|
ADQ_CHANNELS_MASK = 0x3
|
||||||
|
|
||||||
def butter_lowpass(cutoff, sr, order=5):
|
#f_LO = 40
|
||||||
nyq = 0.5 * sr
|
|
||||||
normal_cutoff = cutoff / nyq
|
def butter_lowpass(cutoff, sr, order=5):
|
||||||
b, a = signal.butter(order, normal_cutoff, btype = 'low', analog = False)
|
nyq = 0.5 * sr
|
||||||
return b, a
|
normal_cutoff = cutoff / nyq
|
||||||
|
b, a = scipy.signal.butter(order, normal_cutoff, btype = 'low', analog = False)
|
||||||
|
return b, a
|
||||||
class Adq(object):
|
|
||||||
max_number_of_channels = 2
|
|
||||||
samp_freq = 2
|
class Adq(object):
|
||||||
#ndecimate = 50 # decimation ratio (2GHz / 40 MHz)
|
max_number_of_channels = 2
|
||||||
ndecimate = 50
|
samp_freq = 2
|
||||||
|
#ndecimate = 50 # decimation ratio (2GHz / 40 MHz)
|
||||||
def __init__(self, number_of_records, samples_per_record, bw_cutoff):
|
ndecimate = 50
|
||||||
self.number_of_records = number_of_records
|
|
||||||
self.samples_per_record = samples_per_record
|
def __init__(self, number_of_records, samples_per_record, bw_cutoff):
|
||||||
self.bw_cutoff = bw_cutoff
|
self.number_of_records = number_of_records
|
||||||
ADQAPI.ADQAPI_GetRevision()
|
self.samples_per_record = samples_per_record
|
||||||
|
self.bw_cutoff = bw_cutoff
|
||||||
# Manually set return type from some ADQAPI functions
|
ADQAPI.ADQAPI_GetRevision()
|
||||||
ADQAPI.CreateADQControlUnit.restype = ct.c_void_p
|
|
||||||
ADQAPI.ADQ_GetRevision.restype = ct.c_void_p
|
# Manually set return type from some ADQAPI functions
|
||||||
ADQAPI.ADQ_GetPtrStream.restype = ct.POINTER(ct.c_int16)
|
ADQAPI.CreateADQControlUnit.restype = ct.c_void_p
|
||||||
ADQAPI.ADQControlUnit_FindDevices.argtypes = [ct.c_void_p]
|
ADQAPI.ADQ_GetRevision.restype = ct.c_void_p
|
||||||
# Create ADQControlUnit
|
ADQAPI.ADQ_GetPtrStream.restype = ct.POINTER(ct.c_int16)
|
||||||
self.adq_cu = ct.c_void_p(ADQAPI.CreateADQControlUnit())
|
ADQAPI.ADQControlUnit_FindDevices.argtypes = [ct.c_void_p]
|
||||||
ADQAPI.ADQControlUnit_EnableErrorTrace(self.adq_cu, 3, '.')
|
# Create ADQControlUnit
|
||||||
self.adq_num = 1
|
self.adq_cu = ct.c_void_p(ADQAPI.CreateADQControlUnit())
|
||||||
|
ADQAPI.ADQControlUnit_EnableErrorTrace(self.adq_cu, 3, '.')
|
||||||
# Find ADQ devices
|
self.adq_num = 1
|
||||||
ADQAPI.ADQControlUnit_FindDevices(self.adq_cu)
|
|
||||||
n_of_ADQ = ADQAPI.ADQControlUnit_NofADQ(self.adq_cu)
|
# Find ADQ devices
|
||||||
if n_of_ADQ != 1:
|
ADQAPI.ADQControlUnit_FindDevices(self.adq_cu)
|
||||||
raise ValueError('number of ADQs must be 1, not %d' % n_of_ADQ)
|
n_of_ADQ = ADQAPI.ADQControlUnit_NofADQ(self.adq_cu)
|
||||||
|
if n_of_ADQ != 1:
|
||||||
rev = ADQAPI.ADQ_GetRevision(self.adq_cu, self.adq_num)
|
raise ValueError('number of ADQs must be 1, not %d' % n_of_ADQ)
|
||||||
revision = ct.cast(rev,ct.POINTER(ct.c_int))
|
|
||||||
print('\nConnected to ADQ #1')
|
rev = ADQAPI.ADQ_GetRevision(self.adq_cu, self.adq_num)
|
||||||
# Print revision information
|
revision = ct.cast(rev,ct.POINTER(ct.c_int))
|
||||||
print('FPGA Revision: {}'.format(revision[0]))
|
print('\nConnected to ADQ #1')
|
||||||
if (revision[1]):
|
# Print revision information
|
||||||
print('Local copy')
|
print('FPGA Revision: {}'.format(revision[0]))
|
||||||
else :
|
if (revision[1]):
|
||||||
print('SVN Managed')
|
print('Local copy')
|
||||||
if (revision[2]):
|
else :
|
||||||
print('Mixed Revision')
|
print('SVN Managed')
|
||||||
else :
|
if (revision[2]):
|
||||||
print('SVN Updated')
|
print('Mixed Revision')
|
||||||
print('')
|
else :
|
||||||
|
print('SVN Updated')
|
||||||
ADQ_CLOCK_INT_INTREF = 0 #internal clock source
|
print('')
|
||||||
ADQ_CLOCK_EXT_REF = 1 #internal clock source, external reference
|
|
||||||
ADQ_CLOCK_EXT_CLOCK = 2 #External clock source
|
ADQ_CLOCK_INT_INTREF = 0 #internal clock source
|
||||||
ADQAPI.ADQ_SetClockSource(self.adq_cu, self.adq_num, ADQ_CLOCK_EXT_REF);
|
ADQ_CLOCK_EXT_REF = 1 #internal clock source, external reference
|
||||||
|
ADQ_CLOCK_EXT_CLOCK = 2 #External clock source
|
||||||
##########################
|
ADQAPI.ADQ_SetClockSource(self.adq_cu, self.adq_num, ADQ_CLOCK_EXT_REF);
|
||||||
# Test pattern
|
|
||||||
#ADQAPI.ADQ_SetTestPatternMode(self.adq_cu, self.adq_num, 4)
|
##########################
|
||||||
##########################
|
# Test pattern
|
||||||
# Sample skip
|
#ADQAPI.ADQ_SetTestPatternMode(self.adq_cu, self.adq_num, 4)
|
||||||
#ADQAPI.ADQ_SetSampleSkip(self.adq_cu, self.adq_num, 1)
|
##########################
|
||||||
##########################
|
# Sample skip
|
||||||
|
#ADQAPI.ADQ_SetSampleSkip(self.adq_cu, self.adq_num, 1)
|
||||||
# Set trig mode
|
##########################
|
||||||
self.trigger = EXT_TRIG_1
|
|
||||||
#trigger = LVL_TRIG
|
# Set trig mode
|
||||||
success = ADQAPI.ADQ_SetTriggerMode(self.adq_cu, self.adq_num, self.trigger)
|
self.trigger = EXT_TRIG_1
|
||||||
if (success == 0):
|
#trigger = LVL_TRIG
|
||||||
print('ADQ_SetTriggerMode failed.')
|
success = ADQAPI.ADQ_SetTriggerMode(self.adq_cu, self.adq_num, self.trigger)
|
||||||
if (self.trigger == LVL_TRIG):
|
if (success == 0):
|
||||||
success = ADQAPI.ADQ_SetLvlTrigLevel(self.adq_cu, self.adq_num, -100)
|
print('ADQ_SetTriggerMode failed.')
|
||||||
if (success == 0):
|
if (self.trigger == LVL_TRIG):
|
||||||
print('ADQ_SetLvlTrigLevel failed.')
|
success = ADQAPI.ADQ_SetLvlTrigLevel(self.adq_cu, self.adq_num, -100)
|
||||||
success = ADQAPI.ADQ_SetTrigLevelResetValue(self.adq_cu, self.adq_num, 1000)
|
if (success == 0):
|
||||||
if (success == 0):
|
print('ADQ_SetLvlTrigLevel failed.')
|
||||||
print('ADQ_SetTrigLevelResetValue failed.')
|
success = ADQAPI.ADQ_SetTrigLevelResetValue(self.adq_cu, self.adq_num, 1000)
|
||||||
success = ADQAPI.ADQ_SetLvlTrigChannel(self.adq_cu, self.adq_num, 1)
|
if (success == 0):
|
||||||
if (success == 0):
|
print('ADQ_SetTrigLevelResetValue failed.')
|
||||||
print('ADQ_SetLvlTrigChannel failed.')
|
success = ADQAPI.ADQ_SetLvlTrigChannel(self.adq_cu, self.adq_num, 1)
|
||||||
success = ADQAPI.ADQ_SetLvlTrigEdge(self.adq_cu, self.adq_num, LVL_RISING)
|
if (success == 0):
|
||||||
if (success == 0):
|
print('ADQ_SetLvlTrigChannel failed.')
|
||||||
print('ADQ_SetLvlTrigEdge failed.')
|
success = ADQAPI.ADQ_SetLvlTrigEdge(self.adq_cu, self.adq_num, LVL_RISING)
|
||||||
elif (self.trigger == EXT_TRIG_1) :
|
if (success == 0):
|
||||||
success = ADQAPI.ADQ_SetExternTrigEdge(self.adq_cu, self.adq_num,2)
|
print('ADQ_SetLvlTrigEdge failed.')
|
||||||
if (success == 0):
|
elif (self.trigger == EXT_TRIG_1) :
|
||||||
print('ADQ_SetLvlTrigEdge failed.')
|
success = ADQAPI.ADQ_SetExternTrigEdge(self.adq_cu, self.adq_num,2)
|
||||||
# success = ADQAPI.ADQ_SetTriggerThresholdVoltage(self.adq_cu, self.adq_num, trigger, ct.c_double(0.2))
|
if (success == 0):
|
||||||
# if (success == 0):
|
print('ADQ_SetLvlTrigEdge failed.')
|
||||||
# print('SetTriggerThresholdVoltage failed.')
|
# success = ADQAPI.ADQ_SetTriggerThresholdVoltage(self.adq_cu, self.adq_num, trigger, ct.c_double(0.2))
|
||||||
print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num))))
|
# if (success == 0):
|
||||||
self.setup_target_buffers()
|
# print('SetTriggerThresholdVoltage failed.')
|
||||||
|
print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num))))
|
||||||
def setup_target_buffers(self):
|
self.setup_target_buffers()
|
||||||
# Setup target buffers for data
|
atexit.register(self.deletecu)
|
||||||
self.target_buffers=(ct.POINTER(ct.c_int16 * self.samples_per_record * self.number_of_records)
|
signal.signal(signal.SIGTERM, lambda *_: sys.exit(0))
|
||||||
* self.max_number_of_channels)()
|
|
||||||
for bufp in self.target_buffers:
|
def setup_target_buffers(self):
|
||||||
bufp.contents = (ct.c_int16 * self.samples_per_record * self.number_of_records)()
|
# Setup target buffers for data
|
||||||
|
self.target_buffers=(ct.POINTER(ct.c_int16 * self.samples_per_record * self.number_of_records)
|
||||||
def deletecu(self):
|
* self.max_number_of_channels)()
|
||||||
# Only disarm trigger after data is collected
|
for bufp in self.target_buffers:
|
||||||
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
bufp.contents = (ct.c_int16 * self.samples_per_record * self.number_of_records)()
|
||||||
ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num);
|
|
||||||
# Delete ADQControlunit
|
def deletecu(self):
|
||||||
ADQAPI.DeleteADQControlUnit(self.adq_cu)
|
# Only disarm trigger after data is collected
|
||||||
|
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
||||||
def start(self):
|
ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num);
|
||||||
"""start datat acquisition"""
|
# Delete ADQControlunit
|
||||||
# samples_per_records = samples_per_record/number_of_records
|
ADQAPI.DeleteADQControlUnit(self.adq_cu)
|
||||||
# Change number of pulses to be acquired acording to how many records are taken
|
print('ADQ closed')
|
||||||
# Start acquisition
|
|
||||||
ADQAPI.ADQ_MultiRecordSetup(self.adq_cu, self.adq_num,
|
def start(self):
|
||||||
self.number_of_records,
|
"""start data acquisition"""
|
||||||
self.samples_per_record)
|
# samples_per_records = samples_per_record/number_of_records
|
||||||
|
# Change number of pulses to be acquired acording to how many records are taken
|
||||||
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
# Start acquisition
|
||||||
ADQAPI.ADQ_ArmTrigger(self.adq_cu, self.adq_num)
|
ADQAPI.ADQ_MultiRecordSetup(self.adq_cu, self.adq_num,
|
||||||
|
self.number_of_records,
|
||||||
def getdata(self):
|
self.samples_per_record)
|
||||||
"""wait for aquisition to be finished and get data"""
|
|
||||||
#start = time.time()
|
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
||||||
while(ADQAPI.ADQ_GetAcquiredAll(self.adq_cu,self.adq_num) == 0):
|
ADQAPI.ADQ_ArmTrigger(self.adq_cu, self.adq_num)
|
||||||
time.sleep(0.001)
|
|
||||||
#if (self.trigger == SW_TRIG):
|
def getdata(self):
|
||||||
# ADQAPI.ADQ_SWTrig(self.adq_cu, self.adq_num)
|
"""wait for aquisition to be finished and get data"""
|
||||||
#mid = time.time()
|
#start = time.time()
|
||||||
status = ADQAPI.ADQ_GetData(self.adq_cu, self.adq_num, self.target_buffers,
|
while(ADQAPI.ADQ_GetAcquiredAll(self.adq_cu,self.adq_num) == 0):
|
||||||
self.samples_per_record * self.number_of_records, 2,
|
time.sleep(0.001)
|
||||||
0, self.number_of_records, ADQ_CHANNELS_MASK,
|
#if (self.trigger == SW_TRIG):
|
||||||
0, self.samples_per_record, ADQ_TRANSFER_MODE_NORMAL);
|
# ADQAPI.ADQ_SWTrig(self.adq_cu, self.adq_num)
|
||||||
#print(time.time()-mid,mid-start)
|
#mid = time.time()
|
||||||
if not status:
|
status = ADQAPI.ADQ_GetData(self.adq_cu, self.adq_num, self.target_buffers,
|
||||||
raise ValueError('no succesS from ADQ_GetDATA')
|
self.samples_per_record * self.number_of_records, 2,
|
||||||
# Now this is an array with all records, but the time is artificial
|
0, self.number_of_records, ADQ_CHANNELS_MASK,
|
||||||
data = []
|
0, self.samples_per_record, ADQ_TRANSFER_MODE_NORMAL);
|
||||||
for ch in range(2):
|
#print(time.time()-mid,mid-start)
|
||||||
onedim = np.frombuffer(self.target_buffers[ch].contents, dtype=np.int16)
|
if not status:
|
||||||
data.append(onedim.reshape(self.number_of_records, self.samples_per_record) / float(2**14)) # 14 bits ADC
|
raise ValueError('no succesS from ADQ_GetDATA')
|
||||||
return data
|
# Now this is an array with all records, but the time is artificial
|
||||||
|
data = []
|
||||||
def acquire(self):
|
for ch in range(2):
|
||||||
self.start()
|
onedim = np.frombuffer(self.target_buffers[ch].contents, dtype=np.int16)
|
||||||
return self.getdata()
|
data.append(onedim.reshape(self.number_of_records, self.samples_per_record) / float(2**14)) # 14 bits ADC
|
||||||
'''
|
return data
|
||||||
def average(self, data):
|
|
||||||
#Average over records
|
def acquire(self):
|
||||||
return [data[ch].sum(axis=0) / self.number_of_records for ch in range(2)]
|
self.start()
|
||||||
|
return self.getdata()
|
||||||
def iq(self, channel, f_LO):
|
|
||||||
newx = np.linspace(0, self.samples_per_record /2, self.samples_per_record)
|
def sinW(self,sig,freq,ti,tf):
|
||||||
s0 = channel /((2**16)/2)*0.5*np.exp(1j*2*np.pi*f_LO/(1e3)*newx)
|
# sig: signal array
|
||||||
I0 = s0.real
|
# freq
|
||||||
Q0 = s0.imag
|
# ti, tf: initial and end time
|
||||||
return I0, Q0
|
si = int(ti * self.samp_freq)
|
||||||
|
nperiods = freq * (tf - ti)
|
||||||
|
n = int(round(max(2, int(nperiods)) / nperiods * (tf-ti) * self.samp_freq))
|
||||||
def fitting(self, data, f_LO, ti, tf):
|
self.nperiods = n
|
||||||
# As long as data[0] is the pulse
|
t = np.arange(si, len(sig)) / self.samp_freq
|
||||||
si = 2*ti #Those are for fitting the pulse
|
t = t[:n]
|
||||||
sf = 2*tf
|
self.pulselen = n / self.samp_freq
|
||||||
phase = np.zeros(self.number_of_records)
|
sig = sig[si:si+n]
|
||||||
amplitude = np.zeros(self.number_of_records)
|
a = 2*np.sum(sig*np.cos(2*np.pi*freq*t))/len(sig)
|
||||||
offset = np.zeros(self.number_of_records)
|
b = 2*np.sum(sig*np.sin(2*np.pi*freq*t))/len(sig)
|
||||||
|
return a, b
|
||||||
for i in range(self.number_of_records):
|
|
||||||
phase[i], amplitude[i] = sineW(data[0][i][si:sf],f_LO*1e-9,ti,tf)
|
def mix(self, sigin, sigout, freq, ti, tf):
|
||||||
offset[i] = np.average(data[0][i][si:sf])
|
# sigin, sigout: signal array, incomping, output
|
||||||
return phase, amplitude, offset
|
# freq
|
||||||
|
# ti, tf: initial and end time if sigin
|
||||||
|
a, b = self.sinW(sigin, freq, ti, tf)
|
||||||
def waveIQ(self, channel,ti,f_LO):
|
phase = arctan2(a,b) * 180 / np.pi
|
||||||
#channel is not the sample data
|
amp = sqrt(a**2 + b**2)
|
||||||
t = np.linspace(0, self.samples_per_record /2, self.samples_per_record + 1)[:-1]
|
a, b = a/amp, b/amp
|
||||||
si = 2*ti # Again that is where the wave pulse starts
|
#si = int(ti * self.samp_freq)
|
||||||
cwi = np.zeros((self.number_of_records,self.samples_per_record))
|
t = np.arange(len(sigout)) / self.samp_freq
|
||||||
cwq = np.zeros((self.number_of_records,self.samples_per_record))
|
wave1 = sigout * (a * cos(2*np.pi*freq*t) + b * sin(2*np.pi*freq*t))
|
||||||
iq = np.zeros((self.number_of_records,self.samples_per_record))
|
wave2 = sigout * (a * sin(2*np.pi*freq*t) - b * cos(2*np.pi*freq*t))
|
||||||
q = np.zeros((self.number_of_records,self.samples_per_record))
|
return wave1, wave2
|
||||||
for i in range(self.number_of_records):
|
|
||||||
cwi[i] = np.zeros(self.samples_per_record)
|
def averageiq(self, data, freq, ti, tf):
|
||||||
cwq[i] = np.zeros(self.samples_per_record)
|
'''Average over records'''
|
||||||
cwi[i] = amplitude[i]*sin(t[si:]*f_LO*1e-9*2*np.pi+phase[i]*np.pi/180)+bias[i]
|
iorq = np.array([self.mix(data[0][i], data[1][i], freq, ti, tf) for i in range(self.number_of_records)])
|
||||||
cwq[i] = amplitude[i]*sin(t[si:]*f_LO*1e-9*(2*np.pi+(phase[i]+90)*np.pi/180))+bias[i]
|
# iorq = np.array([self.mix(data[0][:], data[1][:], freq, ti, tf)])
|
||||||
|
return iorq.sum(axis=0) / self.number_of_records
|
||||||
iq[i] = channel[i]*cwi[i]
|
|
||||||
q[i] = channel[i]*cwq[i]
|
def filtro(self, iorq, cutoff):
|
||||||
|
b, a = butter_lowpass(cutoff, self.samp_freq*1e9)
|
||||||
return iq,q
|
|
||||||
'''
|
#ifi = np.array(scipy.signal.filtfilt(b,a,iorq[0]))
|
||||||
def sinW(self,sig,freq,ti,tf):
|
#qf = np.array(scipy.signal.filtfilt(b,a,iorq[1]))
|
||||||
# sig: signal array
|
iqf = [scipy.signal.filtfilt(b,a,iorq[i]) for i in np.arange(len(iorq))]
|
||||||
# freq
|
|
||||||
# ti, tf: initial and end time
|
return iqf
|
||||||
si = int(ti * self.samp_freq)
|
|
||||||
nperiods = freq * (tf - ti)
|
def box(self, iorq, ti, tf):
|
||||||
n = int(round(max(2, int(nperiods)) / nperiods * (tf-ti) * self.samp_freq))
|
si = int(self.samp_freq * ti)
|
||||||
self.nperiods = n
|
sf = int(self.samp_freq * tf)
|
||||||
t = np.arange(si, len(sig)) / self.samp_freq
|
bxa = [sum(iorq[i][si:sf])/(sf-si) for i in np.arange(len(iorq))]
|
||||||
t = t[:n]
|
return bxa
|
||||||
self.pulselen = n / self.samp_freq
|
|
||||||
sig = sig[si:si+n]
|
def gates_and_curves(self, data, freq, pulse, roi):
|
||||||
a = 2*np.sum(sig*np.cos(2*np.pi*freq*t))/len(sig)
|
"""return iq values of rois and prepare plottable curves for iq"""
|
||||||
b = 2*np.sum(sig*np.sin(2*np.pi*freq*t))/len(sig)
|
self.ndecimate = int(round(2E9/freq))
|
||||||
return a, b
|
times = []
|
||||||
|
times.append(('aviq', time.time()))
|
||||||
def mix(self, sigin, sigout, freq, ti, tf):
|
iq = self.averageiq(data,freq*1e-9,*pulse)
|
||||||
# sigin, sigout: signal array, incomping, output
|
times.append(('filtro', time.time()))
|
||||||
# freq
|
iqf = self.filtro(iq,self.bw_cutoff)
|
||||||
# ti, tf: initial and end time if sigin
|
m = len(iqf[0]) // self.ndecimate
|
||||||
a, b = self.sinW(sigin, freq, ti, tf)
|
ll = m * self.ndecimate
|
||||||
phase = arctan2(a,b) * 180 / np.pi
|
iqf = [iqfx[0:ll] for iqfx in iqf]
|
||||||
amp = sqrt(a**2 + b**2)
|
times.append(('iqdec', time.time()))
|
||||||
a, b = a/amp, b/amp
|
iqd = np.average(np.resize(iqf, (2, m, self.ndecimate)), axis=2)
|
||||||
#si = int(ti * self.samp_freq)
|
t_axis = np.arange(m) * self.ndecimate / self.samp_freq
|
||||||
t = np.arange(len(sigout)) / self.samp_freq
|
pulsig = np.abs(data[0][0])
|
||||||
wave1 = sigout * (a * cos(2*np.pi*freq*t) + b * sin(2*np.pi*freq*t))
|
times.append(('pulsig', time.time()))
|
||||||
wave2 = sigout * (a * sin(2*np.pi*freq*t) - b * cos(2*np.pi*freq*t))
|
pulsig = np.average(np.resize(pulsig, (m, self.ndecimate)), axis=1)
|
||||||
return wave1, wave2
|
self.curves = (t_axis, iqd[0], iqd[1], pulsig)
|
||||||
|
#print(times)
|
||||||
def averageiq(self, data, freq, ti, tf):
|
return [self.box(iqf,*r) for r in roi]
|
||||||
'''Average over records'''
|
|
||||||
iorq = np.array([self.mix(data[0][i], data[1][i], freq, ti, tf) for i in range(self.number_of_records)])
|
|
||||||
# iorq = np.array([self.mix(data[0][:], data[1][:], freq, ti, tf)])
|
|
||||||
return iorq.sum(axis=0) / self.number_of_records
|
|
||||||
|
|
||||||
def filtro(self, iorq, cutoff):
|
|
||||||
b, a = butter_lowpass(cutoff, self.samp_freq*1e9)
|
|
||||||
|
|
||||||
#ifi = np.array(signal.filtfilt(b,a,iorq[0]))
|
|
||||||
#qf = np.array(signal.filtfilt(b,a,iorq[1]))
|
|
||||||
iqf = [signal.filtfilt(b,a,iorq[i]) for i in np.arange(len(iorq))]
|
|
||||||
|
|
||||||
return iqf
|
|
||||||
|
|
||||||
def box(self, iorq, ti, tf):
|
|
||||||
si = int(self.samp_freq * ti)
|
|
||||||
sf = int(self.samp_freq * tf)
|
|
||||||
bxa = [sum(iorq[i][si:sf])/(sf-si) for i in np.arange(len(iorq))]
|
|
||||||
return bxa
|
|
||||||
|
|
||||||
def gates_and_curves(self, data, freq, pulse, roi):
|
|
||||||
"""return iq values of rois and prepare plottable curves for iq"""
|
|
||||||
times = []
|
|
||||||
times.append(('aviq', time.time()))
|
|
||||||
iq = self.averageiq(data,freq*1e-9,*pulse)
|
|
||||||
times.append(('filtro', time.time()))
|
|
||||||
iqf = self.filtro(iq,self.bw_cutoff)
|
|
||||||
m = len(iqf[0]) // self.ndecimate
|
|
||||||
times.append(('iqdec', time.time()))
|
|
||||||
iqd = np.average(np.resize(iqf, (2, m, self.ndecimate)), axis=2)
|
|
||||||
t_axis = np.arange(m) * self.ndecimate / self.samp_freq
|
|
||||||
pulsig = np.abs(data[0][0])
|
|
||||||
times.append(('pulsig', time.time()))
|
|
||||||
pulsig = np.average(np.resize(pulsig, (m, self.ndecimate)), axis=1)
|
|
||||||
self.curves = (t_axis, iqd[0], iqd[1], pulsig)
|
|
||||||
#print(times)
|
|
||||||
return [self.box(iqf,*r) for r in roi]
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user