From d55ee42612a7eead1df8682c89c7637c98a0663d Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Mon, 29 Jan 2024 14:14:09 +0100 Subject: [PATCH] remove more coding cookies mainly from frappy_psi Change-Id: I192811459aebe97f3076888cd31a308a51e6aa49 --- frappy/modules.py | 1 - frappy_psi/FG_Lecroy_3000.py | 2 - frappy_psi/SR.py | 2 - frappy_psi/SR830.py | 2 - frappy_psi/SR_7270.py | 2 - frappy_psi/adq_mr.py | 587 ++++++++++++++++----------------- frappy_psi/cryoltd.py | 1 - frappy_psi/cryotel.py | 1 - frappy_psi/dg645.py | 2 - frappy_psi/dilsc.py | 1 - frappy_psi/dpm.py | 1 - frappy_psi/haake.py | 2 - frappy_psi/iqplot.py | 203 ++++++------ frappy_psi/lakeshore.py | 2 - frappy_psi/ls240.py | 2 - frappy_psi/ls340res.py | 2 - frappy_psi/ls370sim.py | 2 - frappy_psi/ls372.py | 2 - frappy_psi/mixins.py | 1 - frappy_psi/parmod.py | 1 - frappy_psi/qnw.py | 2 - frappy_psi/senis.py | 2 - frappy_psi/simdpm.py | 1 - frappy_psi/switching_sensor.py | 2 - frappy_psi/ultrasound.py | 2 - frappy_psi/uniax.py | 1 - frappy_psi/vector.py | 3 +- sync_branches | 2 +- 28 files changed, 396 insertions(+), 438 deletions(-) diff --git a/frappy/modules.py b/frappy/modules.py index 0d835ee..822118d 100644 --- a/frappy/modules.py +++ b/frappy/modules.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/FG_Lecroy_3000.py b/frappy_psi/FG_Lecroy_3000.py index 618fc38..a1bb293 100644 --- a/frappy_psi/FG_Lecroy_3000.py +++ b/frappy_psi/FG_Lecroy_3000.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/SR.py b/frappy_psi/SR.py index 2de98b5..b33ff78 100644 --- a/frappy_psi/SR.py +++ b/frappy_psi/SR.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/SR830.py b/frappy_psi/SR830.py index 06c5862..584e6ab 100644 --- a/frappy_psi/SR830.py +++ b/frappy_psi/SR830.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/SR_7270.py b/frappy_psi/SR_7270.py index 0111e68..0f9ef12 100644 --- a/frappy_psi/SR_7270.py +++ b/frappy_psi/SR_7270.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/adq_mr.py b/frappy_psi/adq_mr.py index d0e9fc1..0786ba4 100644 --- a/frappy_psi/adq_mr.py +++ b/frappy_psi/adq_mr.py @@ -1,294 +1,293 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue Nov 26 15:42:43 2019 - -@author: tartarotti_d-adm -""" - - -import numpy as np -import ctypes as ct -import time -from numpy import sqrt, arctan2, sin, cos - -#from pylab import * - -from scipy import signal - -#ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll") -ADQAPI = ct.cdll.LoadLibrary("libadq.so.0") - -#For different trigger modes -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 -EXT_TRIG_2 = 7 -EXT_TRIG_3 = 8 -LVL_TRIG = 3 -INT_TRIG = 4 -LVL_FALLING = 0 -LVL_RISING = 1 - -#samples_per_record=16384 -ADQ_TRANSFER_MODE_NORMAL = 0x00 -ADQ_CHANNELS_MASK = 0x3 - -#f_LO = 40 - -def butter_lowpass(cutoff, sr, order=5): - nyq = 0.5 * sr - normal_cutoff = cutoff / nyq - b, a = signal.butter(order, normal_cutoff, btype = 'low', analog = False) - return b, a - - -class Adq(object): - max_number_of_channels = 2 - samp_freq = 2 - #ndecimate = 50 # decimation ratio (2GHz / 40 MHz) - ndecimate = 50 - - def __init__(self, number_of_records, samples_per_record, bw_cutoff): - self.number_of_records = number_of_records - self.samples_per_record = samples_per_record - self.bw_cutoff = bw_cutoff - ADQAPI.ADQAPI_GetRevision() - - # Manually set return type from some ADQAPI functions - ADQAPI.CreateADQControlUnit.restype = ct.c_void_p - ADQAPI.ADQ_GetRevision.restype = ct.c_void_p - ADQAPI.ADQ_GetPtrStream.restype = ct.POINTER(ct.c_int16) - ADQAPI.ADQControlUnit_FindDevices.argtypes = [ct.c_void_p] - # Create ADQControlUnit - self.adq_cu = ct.c_void_p(ADQAPI.CreateADQControlUnit()) - ADQAPI.ADQControlUnit_EnableErrorTrace(self.adq_cu, 3, '.') - self.adq_num = 1 - - # Find ADQ devices - ADQAPI.ADQControlUnit_FindDevices(self.adq_cu) - n_of_ADQ = ADQAPI.ADQControlUnit_NofADQ(self.adq_cu) - if n_of_ADQ != 1: - raise ValueError('number of ADQs must be 1, not %d' % n_of_ADQ) - - rev = ADQAPI.ADQ_GetRevision(self.adq_cu, self.adq_num) - revision = ct.cast(rev,ct.POINTER(ct.c_int)) - print('\nConnected to ADQ #1') - # Print revision information - print('FPGA Revision: {}'.format(revision[0])) - if (revision[1]): - print('Local copy') - else : - print('SVN Managed') - if (revision[2]): - print('Mixed Revision') - else : - print('SVN Updated') - print('') - - ADQ_CLOCK_INT_INTREF = 0 #internal clock source - 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) - ########################## - # Sample skip - #ADQAPI.ADQ_SetSampleSkip(self.adq_cu, self.adq_num, 1) - ########################## - - # Set trig mode - self.trigger = EXT_TRIG_1 - #trigger = LVL_TRIG - success = ADQAPI.ADQ_SetTriggerMode(self.adq_cu, self.adq_num, self.trigger) - if (success == 0): - print('ADQ_SetTriggerMode failed.') - if (self.trigger == LVL_TRIG): - success = ADQAPI.ADQ_SetLvlTrigLevel(self.adq_cu, self.adq_num, -100) - if (success == 0): - print('ADQ_SetLvlTrigLevel failed.') - success = ADQAPI.ADQ_SetTrigLevelResetValue(self.adq_cu, self.adq_num, 1000) - if (success == 0): - print('ADQ_SetTrigLevelResetValue failed.') - success = ADQAPI.ADQ_SetLvlTrigChannel(self.adq_cu, self.adq_num, 1) - if (success == 0): - print('ADQ_SetLvlTrigChannel failed.') - success = ADQAPI.ADQ_SetLvlTrigEdge(self.adq_cu, self.adq_num, LVL_RISING) - if (success == 0): - print('ADQ_SetLvlTrigEdge failed.') - elif (self.trigger == EXT_TRIG_1) : - success = ADQAPI.ADQ_SetExternTrigEdge(self.adq_cu, self.adq_num,2) - if (success == 0): - print('ADQ_SetLvlTrigEdge failed.') - # success = ADQAPI.ADQ_SetTriggerThresholdVoltage(self.adq_cu, self.adq_num, trigger, ct.c_double(0.2)) - # if (success == 0): - # print('SetTriggerThresholdVoltage failed.') - print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num)))) - self.setup_target_buffers() - - def setup_target_buffers(self): - # Setup target buffers for data - self.target_buffers=(ct.POINTER(ct.c_int16 * self.samples_per_record * self.number_of_records) - * self.max_number_of_channels)() - for bufp in self.target_buffers: - bufp.contents = (ct.c_int16 * self.samples_per_record * self.number_of_records)() - - def deletecu(self): - # Only disarm trigger after data is collected - ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num) - ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num); - # Delete ADQControlunit - ADQAPI.DeleteADQControlUnit(self.adq_cu) - - def start(self): - """start datat acquisition""" - # samples_per_records = samples_per_record/number_of_records - # Change number of pulses to be acquired acording to how many records are taken - # Start acquisition - ADQAPI.ADQ_MultiRecordSetup(self.adq_cu, self.adq_num, - self.number_of_records, - self.samples_per_record) - - ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num) - ADQAPI.ADQ_ArmTrigger(self.adq_cu, self.adq_num) - - def getdata(self): - """wait for aquisition to be finished and get data""" - #start = time.time() - while(ADQAPI.ADQ_GetAcquiredAll(self.adq_cu,self.adq_num) == 0): - time.sleep(0.001) - #if (self.trigger == SW_TRIG): - # ADQAPI.ADQ_SWTrig(self.adq_cu, self.adq_num) - #mid = time.time() - status = ADQAPI.ADQ_GetData(self.adq_cu, self.adq_num, self.target_buffers, - self.samples_per_record * self.number_of_records, 2, - 0, self.number_of_records, ADQ_CHANNELS_MASK, - 0, self.samples_per_record, ADQ_TRANSFER_MODE_NORMAL); - #print(time.time()-mid,mid-start) - if not status: - raise ValueError('no succesS from ADQ_GetDATA') - # Now this is an array with all records, but the time is artificial - data = [] - for ch in range(2): - onedim = np.frombuffer(self.target_buffers[ch].contents, dtype=np.int16) - data.append(onedim.reshape(self.number_of_records, self.samples_per_record) / float(2**14)) # 14 bits ADC - return data - - def acquire(self): - self.start() - 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): - # sig: signal array - # freq - # ti, tf: initial and end time - si = int(ti * self.samp_freq) - nperiods = freq * (tf - ti) - n = int(round(max(2, int(nperiods)) / nperiods * (tf-ti) * self.samp_freq)) - self.nperiods = n - t = np.arange(si, len(sig)) / self.samp_freq - t = t[:n] - self.pulselen = n / self.samp_freq - sig = sig[si:si+n] - a = 2*np.sum(sig*np.cos(2*np.pi*freq*t))/len(sig) - b = 2*np.sum(sig*np.sin(2*np.pi*freq*t))/len(sig) - return a, b - - def mix(self, sigin, sigout, freq, ti, tf): - # sigin, sigout: signal array, incomping, output - # freq - # ti, tf: initial and end time if sigin - a, b = self.sinW(sigin, freq, ti, tf) - phase = arctan2(a,b) * 180 / np.pi - amp = sqrt(a**2 + b**2) - a, b = a/amp, b/amp - #si = int(ti * self.samp_freq) - t = np.arange(len(sigout)) / self.samp_freq - wave1 = sigout * (a * cos(2*np.pi*freq*t) + b * sin(2*np.pi*freq*t)) - wave2 = sigout * (a * sin(2*np.pi*freq*t) - b * cos(2*np.pi*freq*t)) - return wave1, wave2 - - def averageiq(self, data, freq, ti, tf): - '''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] - +""" +Created on Tue Nov 26 15:42:43 2019 + +@author: tartarotti_d-adm +""" + + +import numpy as np +import ctypes as ct +import time +from numpy import sqrt, arctan2, sin, cos + +#from pylab import * + +from scipy import signal + +#ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll") +ADQAPI = ct.cdll.LoadLibrary("libadq.so.0") + +#For different trigger modes +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 +EXT_TRIG_2 = 7 +EXT_TRIG_3 = 8 +LVL_TRIG = 3 +INT_TRIG = 4 +LVL_FALLING = 0 +LVL_RISING = 1 + +#samples_per_record=16384 +ADQ_TRANSFER_MODE_NORMAL = 0x00 +ADQ_CHANNELS_MASK = 0x3 + +#f_LO = 40 + +def butter_lowpass(cutoff, sr, order=5): + nyq = 0.5 * sr + normal_cutoff = cutoff / nyq + b, a = signal.butter(order, normal_cutoff, btype = 'low', analog = False) + return b, a + + +class Adq(object): + max_number_of_channels = 2 + samp_freq = 2 + #ndecimate = 50 # decimation ratio (2GHz / 40 MHz) + ndecimate = 50 + + def __init__(self, number_of_records, samples_per_record, bw_cutoff): + self.number_of_records = number_of_records + self.samples_per_record = samples_per_record + self.bw_cutoff = bw_cutoff + ADQAPI.ADQAPI_GetRevision() + + # Manually set return type from some ADQAPI functions + ADQAPI.CreateADQControlUnit.restype = ct.c_void_p + ADQAPI.ADQ_GetRevision.restype = ct.c_void_p + ADQAPI.ADQ_GetPtrStream.restype = ct.POINTER(ct.c_int16) + ADQAPI.ADQControlUnit_FindDevices.argtypes = [ct.c_void_p] + # Create ADQControlUnit + self.adq_cu = ct.c_void_p(ADQAPI.CreateADQControlUnit()) + ADQAPI.ADQControlUnit_EnableErrorTrace(self.adq_cu, 3, '.') + self.adq_num = 1 + + # Find ADQ devices + ADQAPI.ADQControlUnit_FindDevices(self.adq_cu) + n_of_ADQ = ADQAPI.ADQControlUnit_NofADQ(self.adq_cu) + if n_of_ADQ != 1: + raise ValueError('number of ADQs must be 1, not %d' % n_of_ADQ) + + rev = ADQAPI.ADQ_GetRevision(self.adq_cu, self.adq_num) + revision = ct.cast(rev,ct.POINTER(ct.c_int)) + print('\nConnected to ADQ #1') + # Print revision information + print('FPGA Revision: {}'.format(revision[0])) + if (revision[1]): + print('Local copy') + else : + print('SVN Managed') + if (revision[2]): + print('Mixed Revision') + else : + print('SVN Updated') + print('') + + ADQ_CLOCK_INT_INTREF = 0 #internal clock source + 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) + ########################## + # Sample skip + #ADQAPI.ADQ_SetSampleSkip(self.adq_cu, self.adq_num, 1) + ########################## + + # Set trig mode + self.trigger = EXT_TRIG_1 + #trigger = LVL_TRIG + success = ADQAPI.ADQ_SetTriggerMode(self.adq_cu, self.adq_num, self.trigger) + if (success == 0): + print('ADQ_SetTriggerMode failed.') + if (self.trigger == LVL_TRIG): + success = ADQAPI.ADQ_SetLvlTrigLevel(self.adq_cu, self.adq_num, -100) + if (success == 0): + print('ADQ_SetLvlTrigLevel failed.') + success = ADQAPI.ADQ_SetTrigLevelResetValue(self.adq_cu, self.adq_num, 1000) + if (success == 0): + print('ADQ_SetTrigLevelResetValue failed.') + success = ADQAPI.ADQ_SetLvlTrigChannel(self.adq_cu, self.adq_num, 1) + if (success == 0): + print('ADQ_SetLvlTrigChannel failed.') + success = ADQAPI.ADQ_SetLvlTrigEdge(self.adq_cu, self.adq_num, LVL_RISING) + if (success == 0): + print('ADQ_SetLvlTrigEdge failed.') + elif (self.trigger == EXT_TRIG_1) : + success = ADQAPI.ADQ_SetExternTrigEdge(self.adq_cu, self.adq_num,2) + if (success == 0): + print('ADQ_SetLvlTrigEdge failed.') + # success = ADQAPI.ADQ_SetTriggerThresholdVoltage(self.adq_cu, self.adq_num, trigger, ct.c_double(0.2)) + # if (success == 0): + # print('SetTriggerThresholdVoltage failed.') + print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num)))) + self.setup_target_buffers() + + def setup_target_buffers(self): + # Setup target buffers for data + self.target_buffers=(ct.POINTER(ct.c_int16 * self.samples_per_record * self.number_of_records) + * self.max_number_of_channels)() + for bufp in self.target_buffers: + bufp.contents = (ct.c_int16 * self.samples_per_record * self.number_of_records)() + + def deletecu(self): + # Only disarm trigger after data is collected + ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num) + ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num); + # Delete ADQControlunit + ADQAPI.DeleteADQControlUnit(self.adq_cu) + + def start(self): + """start datat acquisition""" + # samples_per_records = samples_per_record/number_of_records + # Change number of pulses to be acquired acording to how many records are taken + # Start acquisition + ADQAPI.ADQ_MultiRecordSetup(self.adq_cu, self.adq_num, + self.number_of_records, + self.samples_per_record) + + ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num) + ADQAPI.ADQ_ArmTrigger(self.adq_cu, self.adq_num) + + def getdata(self): + """wait for aquisition to be finished and get data""" + #start = time.time() + while(ADQAPI.ADQ_GetAcquiredAll(self.adq_cu,self.adq_num) == 0): + time.sleep(0.001) + #if (self.trigger == SW_TRIG): + # ADQAPI.ADQ_SWTrig(self.adq_cu, self.adq_num) + #mid = time.time() + status = ADQAPI.ADQ_GetData(self.adq_cu, self.adq_num, self.target_buffers, + self.samples_per_record * self.number_of_records, 2, + 0, self.number_of_records, ADQ_CHANNELS_MASK, + 0, self.samples_per_record, ADQ_TRANSFER_MODE_NORMAL); + #print(time.time()-mid,mid-start) + if not status: + raise ValueError('no succesS from ADQ_GetDATA') + # Now this is an array with all records, but the time is artificial + data = [] + for ch in range(2): + onedim = np.frombuffer(self.target_buffers[ch].contents, dtype=np.int16) + data.append(onedim.reshape(self.number_of_records, self.samples_per_record) / float(2**14)) # 14 bits ADC + return data + + def acquire(self): + self.start() + 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): + # sig: signal array + # freq + # ti, tf: initial and end time + si = int(ti * self.samp_freq) + nperiods = freq * (tf - ti) + n = int(round(max(2, int(nperiods)) / nperiods * (tf-ti) * self.samp_freq)) + self.nperiods = n + t = np.arange(si, len(sig)) / self.samp_freq + t = t[:n] + self.pulselen = n / self.samp_freq + sig = sig[si:si+n] + a = 2*np.sum(sig*np.cos(2*np.pi*freq*t))/len(sig) + b = 2*np.sum(sig*np.sin(2*np.pi*freq*t))/len(sig) + return a, b + + def mix(self, sigin, sigout, freq, ti, tf): + # sigin, sigout: signal array, incomping, output + # freq + # ti, tf: initial and end time if sigin + a, b = self.sinW(sigin, freq, ti, tf) + phase = arctan2(a,b) * 180 / np.pi + amp = sqrt(a**2 + b**2) + a, b = a/amp, b/amp + #si = int(ti * self.samp_freq) + t = np.arange(len(sigout)) / self.samp_freq + wave1 = sigout * (a * cos(2*np.pi*freq*t) + b * sin(2*np.pi*freq*t)) + wave2 = sigout * (a * sin(2*np.pi*freq*t) - b * cos(2*np.pi*freq*t)) + return wave1, wave2 + + def averageiq(self, data, freq, ti, tf): + '''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] + diff --git a/frappy_psi/cryoltd.py b/frappy_psi/cryoltd.py index 135dba5..98bc6f1 100644 --- a/frappy_psi/cryoltd.py +++ b/frappy_psi/cryoltd.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/cryotel.py b/frappy_psi/cryotel.py index c979f41..08f392b 100644 --- a/frappy_psi/cryotel.py +++ b/frappy_psi/cryotel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/dg645.py b/frappy_psi/dg645.py index 4c06a28..624db43 100644 --- a/frappy_psi/dg645.py +++ b/frappy_psi/dg645.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/dilsc.py b/frappy_psi/dilsc.py index 5d49b43..ab572ca 100644 --- a/frappy_psi/dilsc.py +++ b/frappy_psi/dilsc.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/dpm.py b/frappy_psi/dpm.py index 71d07da..bf2dc50 100644 --- a/frappy_psi/dpm.py +++ b/frappy_psi/dpm.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/haake.py b/frappy_psi/haake.py index e00b28c..5369154 100644 --- a/frappy_psi/haake.py +++ b/frappy_psi/haake.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/iqplot.py b/frappy_psi/iqplot.py index 344f062..43a48d3 100644 --- a/frappy_psi/iqplot.py +++ b/frappy_psi/iqplot.py @@ -1,102 +1,101 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue Feb 4 11:07:56 2020 - -@author: tartarotti_d-adm -""" - -import numpy as np -import matplotlib.pyplot as plt - -def rect(x1, x2, y1, y2): - return np.array([[x1,x2,x2,x1,x1],[y1,y1,y2,y2,y1]]) - -NAN = float('nan') - -def rects(intervals, y12): - result = [rect(*intervals[0], *y12)] - for x12 in intervals[1:]: - result.append([[NAN],[NAN]]) - result.append(rect(*x12, *y12)) - return np.concatenate(result, axis=1) - -class Plot: - def __init__(self, maxy): - self.lines = {} - self.yaxis = ((-2 * maxy, maxy), (-maxy, 2 * maxy)) - self.first = True - self.fig = None - - def set_line(self, iax, name, data, fmt, **kwds): - """ - plot or update a line - - when called with self.first = True: plot the line - when called with self.first = False: update the line - - iax: 0: left, 1: right yaxis - name: the name of the line. used also as label for legend, if not starting with underscore - data: data[0] and data[1] are used for x/y data respectively - fmt, other keywords: forwarded to .plot - """ - # ax: 0: left, 1: right - if self.first: - if name.startswith('_'): - label = '_nolegend_' - else: - label = name - self.lines[name], = self.ax[iax].plot(data[0], data[1], fmt, label=label, **kwds) - else: - self.lines[name].set_data(data[0:2]) - - def close(self): - if self.fig: - plt.close(self.fig) - self.fig = None - self.first = True - - def plot(self, curves, rois=None, average=None): - boxes = rects(rois[1:], self.yaxis[0]) - pbox = rect(*rois[0], *self.yaxis[1]) - rbox = rect(*rois[1], *self.yaxis[0]) - - pshift = self.yaxis[0][1] * 0.5 - pulse = curves[3] - pshift - # normalized to 0.8 * pshift: - #pulse = (curves[3] / np.max(curves[3]))* pshift * 0.8 - pshift - - try: - if self.first: - plt.ion() - self.fig, axleft = plt.subplots(figsize=(15,7)) - plt.title("I/Q", fontsize=14) - axleft.set_xlim(0, curves[0][-1]) - self.ax = [axleft, axleft.twinx()] - self.ax[0].axhline(y=0, color='#cccccc') # show x-axis line - self.ax[1].axhline(y=0, color='#cccccc') - self.ax[0].set_ylim(*self.yaxis[0]) - self.ax[1].set_ylim(*self.yaxis[1]) - - self.set_line(0, "I", curves, 'b-') # using curves [0] and [1] - self.set_line(0, "_Iaverage", average, 'b.') - - self.set_line(0, "Ampl", (curves[0],np.sqrt(curves[1]**2+curves[2]**2)), '#808080') - - self.set_line(1, "Q", (curves[0], curves[2]), 'g-') - self.set_line(1, "_Qaverage", (average[0], average[2]), 'g.') - - self.set_line(0, "pulse", (curves[0], pulse), 'c-') - - self.set_line(0, "roi's", boxes, 'm-') - self.set_line(1, "pulse reg", pbox, 'k-') - self.set_line(0, "ctrl reg", rbox, 'r-') - - if self.first: - self.fig.legend(fontsize=12) - plt.tight_layout() - finally: - self.first = False - - plt.draw() - self.fig.canvas.draw() - self.fig.canvas.flush_events() +""" +Created on Tue Feb 4 11:07:56 2020 + +@author: tartarotti_d-adm +""" + +import numpy as np +import matplotlib.pyplot as plt + +def rect(x1, x2, y1, y2): + return np.array([[x1,x2,x2,x1,x1],[y1,y1,y2,y2,y1]]) + +NAN = float('nan') + +def rects(intervals, y12): + result = [rect(*intervals[0], *y12)] + for x12 in intervals[1:]: + result.append([[NAN],[NAN]]) + result.append(rect(*x12, *y12)) + return np.concatenate(result, axis=1) + +class Plot: + def __init__(self, maxy): + self.lines = {} + self.yaxis = ((-2 * maxy, maxy), (-maxy, 2 * maxy)) + self.first = True + self.fig = None + + def set_line(self, iax, name, data, fmt, **kwds): + """ + plot or update a line + + when called with self.first = True: plot the line + when called with self.first = False: update the line + + iax: 0: left, 1: right yaxis + name: the name of the line. used also as label for legend, if not starting with underscore + data: data[0] and data[1] are used for x/y data respectively + fmt, other keywords: forwarded to .plot + """ + # ax: 0: left, 1: right + if self.first: + if name.startswith('_'): + label = '_nolegend_' + else: + label = name + self.lines[name], = self.ax[iax].plot(data[0], data[1], fmt, label=label, **kwds) + else: + self.lines[name].set_data(data[0:2]) + + def close(self): + if self.fig: + plt.close(self.fig) + self.fig = None + self.first = True + + def plot(self, curves, rois=None, average=None): + boxes = rects(rois[1:], self.yaxis[0]) + pbox = rect(*rois[0], *self.yaxis[1]) + rbox = rect(*rois[1], *self.yaxis[0]) + + pshift = self.yaxis[0][1] * 0.5 + pulse = curves[3] - pshift + # normalized to 0.8 * pshift: + #pulse = (curves[3] / np.max(curves[3]))* pshift * 0.8 - pshift + + try: + if self.first: + plt.ion() + self.fig, axleft = plt.subplots(figsize=(15,7)) + plt.title("I/Q", fontsize=14) + axleft.set_xlim(0, curves[0][-1]) + self.ax = [axleft, axleft.twinx()] + self.ax[0].axhline(y=0, color='#cccccc') # show x-axis line + self.ax[1].axhline(y=0, color='#cccccc') + self.ax[0].set_ylim(*self.yaxis[0]) + self.ax[1].set_ylim(*self.yaxis[1]) + + self.set_line(0, "I", curves, 'b-') # using curves [0] and [1] + self.set_line(0, "_Iaverage", average, 'b.') + + self.set_line(0, "Ampl", (curves[0],np.sqrt(curves[1]**2+curves[2]**2)), '#808080') + + self.set_line(1, "Q", (curves[0], curves[2]), 'g-') + self.set_line(1, "_Qaverage", (average[0], average[2]), 'g.') + + self.set_line(0, "pulse", (curves[0], pulse), 'c-') + + self.set_line(0, "roi's", boxes, 'm-') + self.set_line(1, "pulse reg", pbox, 'k-') + self.set_line(0, "ctrl reg", rbox, 'r-') + + if self.first: + self.fig.legend(fontsize=12) + plt.tight_layout() + finally: + self.first = False + + plt.draw() + self.fig.canvas.draw() + self.fig.canvas.flush_events() diff --git a/frappy_psi/lakeshore.py b/frappy_psi/lakeshore.py index 3a017b4..105322b 100644 --- a/frappy_psi/lakeshore.py +++ b/frappy_psi/lakeshore.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/ls240.py b/frappy_psi/ls240.py index 417acfb..818d91d 100644 --- a/frappy_psi/ls240.py +++ b/frappy_psi/ls240.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/ls340res.py b/frappy_psi/ls340res.py index a9f9c7d..1207fa2 100644 --- a/frappy_psi/ls340res.py +++ b/frappy_psi/ls340res.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/ls370sim.py b/frappy_psi/ls370sim.py index b934685..1791290 100644 --- a/frappy_psi/ls370sim.py +++ b/frappy_psi/ls370sim.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/ls372.py b/frappy_psi/ls372.py index 4899b2d..a18ab1d 100644 --- a/frappy_psi/ls372.py +++ b/frappy_psi/ls372.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/mixins.py b/frappy_psi/mixins.py index b44df3e..ab7daed 100644 --- a/frappy_psi/mixins.py +++ b/frappy_psi/mixins.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/parmod.py b/frappy_psi/parmod.py index ca84503..9c35a68 100644 --- a/frappy_psi/parmod.py +++ b/frappy_psi/parmod.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/qnw.py b/frappy_psi/qnw.py index d7c2d81..f699352 100644 --- a/frappy_psi/qnw.py +++ b/frappy_psi/qnw.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/senis.py b/frappy_psi/senis.py index f129a04..0ab3b67 100644 --- a/frappy_psi/senis.py +++ b/frappy_psi/senis.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/simdpm.py b/frappy_psi/simdpm.py index 97e9fa9..82feb81 100644 --- a/frappy_psi/simdpm.py +++ b/frappy_psi/simdpm.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/switching_sensor.py b/frappy_psi/switching_sensor.py index 08976dc..a61f697 100644 --- a/frappy_psi/switching_sensor.py +++ b/frappy_psi/switching_sensor.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/ultrasound.py b/frappy_psi/ultrasound.py index e4c9fe8..b2e0cdf 100644 --- a/frappy_psi/ultrasound.py +++ b/frappy_psi/ultrasound.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software diff --git a/frappy_psi/uniax.py b/frappy_psi/uniax.py index 7c66298..067b058 100644 --- a/frappy_psi/uniax.py +++ b/frappy_psi/uniax.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under diff --git a/frappy_psi/vector.py b/frappy_psi/vector.py index 9e28386..4a9816d 100644 --- a/frappy_psi/vector.py +++ b/frappy_psi/vector.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # ***************************************************************************** # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software @@ -86,4 +85,4 @@ class Vector(Drivable, VectorRd): self.parameters['target'].datatype = TupleOf(*members) def write_target(self, value): - return tuple((c.write_target(v) for v, c in zip(value, self.components))) \ No newline at end of file + return tuple((c.write_target(v) for v, c in zip(value, self.components))) diff --git a/sync_branches b/sync_branches index 2c4cdf5..df249d9 100644 --- a/sync_branches +++ b/sync_branches @@ -1,2 +1,2 @@ 2024-01-29 wip develop - +2023-10-01 wip mlz # test wise