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

@ -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]

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)