*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
Commit 8b525b19 authored by Leolab Cavity CAD PC's avatar Leolab Cavity CAD PC
Browse files

Fastcomtec: New device code to let MCS8A run for long time and save trigger...

Fastcomtec: New device code to let MCS8A run for long time and save trigger signals instead of starting and stopping for each shot.
parent d73ccdae
No related branches found
No related tags found
1 merge request!5Added Fastcomtec MCS8A timetagger for measurements with SPCM
[MCS8A A] 208 FW 3.104 SV 1.243
range=256
range=44736
periods=2
sweepmode=22fd2088
sweepmode=22fc2088
fstchan=0
holdafter=0
streamstatus=0
......@@ -37,8 +37,8 @@ wndheight=286
sysdef=0
showstarts=0
[CHN1]
range=256
active=0
range=44736
active=1
bitshift=18
cftfak=2580100
evpreset=10
......@@ -51,7 +51,7 @@ calfact3=0
calunit=nsec
caluse=1
[CHN2]
range=256
range=44736
active=1
bitshift=18
cftfak=2580100
......
......@@ -9,83 +9,73 @@
from . import fastcomtec_api
from blacs.tab_base_classes import Worker
from labscript import config
from labscript_utils.labconfig import LabConfig
import os
import labscript_utils.h5_lock
import h5py
import numpy as np
import time
from datetime import datetime
class MCS8AWorker(Worker):
def init(self):
self.start = time.perf_counter()
self.base_dir = "C:/mcs8x64/"
self.data_mame_tmp = "CHN2_tmp"
# ONLY FOR MPA AND AUTOSAVE
self.data_path_tmp = self.base_dir + self.data_mame_tmp + ".mpa"
# ONLY FOR DAT WITHOUT AUTOSAVE
# self.data_path_tmp = self.base_dir + self.data_mame_tmp
self.base_dir = LabConfig().get("DEFAULT","experiment_shot_storage") + "\\MCS8A"
os.makedirs(self.base_dir, exist_ok=True) # create MCS8A folder if it doesn't exist yet
self.device = fastcomtec_api.FastComTec()
print("Connected...")
# print("Status: ", self.device.get_acq_status())
self.device.halt_measurement()
# load (default) config
if not os.path.realpath(self.config_path) == self.config_path.replace("/","\\"):
self.config_path = os.path.dirname(os.path.realpath(__file__)) + "\\" + self.config_path
self.config_path = self.config_path.replace("\\", "/")
print("Load config...", self.config_path)
self.device.load_config(self.config_path)
# print(f"Data file path: {self.data_path_tmp}")
# ONLY FOR MPA AND AUTOSAVE
# self.device._send_dll_command(f"mpaname={self.data_path_tmp}") # mpa might be slow
# Save data only in list file and in binary format
self.device._send_dll_command("mpafmt=dat")
self.device._send_dll_command("savedata=2")
# ONLY FOR DAT WITHOUT AUTOSAVE
# self.device._send_dll_command(f"datname={self.data_mame_tmp}")
# self.device._send_dll_command("fmt=dat")
self.smart_cache = {}
print('init completed')
# Set how long each measurement lasts, i.e. how ofen a new file is started.
# We don't want it too long, because then the single files get huge, but we also don't
# want it too often, because each stopping and starting takes some time.
self.maxduration = 300 # seconds
self.device._send_dll_command("bitshift=18") # 400ps * 2^0x18 = 0.0067 s
range_int = np.ceil(self.maxduration / (400e-12 * 2**0x18) / 64) * 64
self.device._send_dll_command(f"range={int(range_int)}")
def get_new_mpapath(self):
mpaname = self.device_name + "_" + datetime.now().strftime("%Y-%d-%m_%H-%M-%S") + ".mpa"
return self.base_dir + "\\" + mpaname
def transition_to_buffered(self, device_name, h5_file, initial_values, fresh):
print(f"Cycle time: {time.perf_counter()-self.start:.1f} s")
self.start = time.perf_counter()
self.h5file = h5_file # save for 'transition_to_manual'
self.mpaname = h5_file.replace("\\","/").replace(".h5",".mpa")
self.device._send_dll_command(f"mpaname={self.mpaname}")
while True:
status = self.device.get_acq_status()
status = getattr(status,"started")
if status!=1:
break
print("Waiting for device to stop running (from previous shot)...", end="\r")
time.sleep(0.1)
self.device.halt_measurement()
with h5py.File(h5_file,'r') as f:
command_group = f[f"devices/{self.device_name}/commands"]
for command in command_group.attrs:
if (command in self.smart_cache and command_group.attrs[command]==self.smart_cache[command]) and not fresh:
continue
self.smart_cache[command] = command_group.attrs[command]
if command_group.attrs[command] is not None:
command = f"{command}={command_group.attrs[command]}"
self.device._send_dll_command(command)
print(f"Programmed command '{command}'")
# self.device.erase_measruement() # Don't erase because this takes super long for some reason
self.device.start_measurement()
# If device is already started, we leave it running and just save the datapath and index in the h5file.
# If the device is not running, or already longer than the defined duration, send the stop command, set new datafile and start new measurement.
# TODO: How to handle parameters (start new measurment when they changed, or treat parameters statically)
if getattr(self.device.get_acq_status(),"started") != 1 or time.perf_counter()-getattr(self,"start_time",-self.maxduration)>self.maxduration:
time.sleep(1) # TODO: Do we need this wait? What's the minumum?
self.device.halt_measurement()
mpapath = self.get_new_mpapath()
self.device._send_dll_command(f"mpaname={mpapath}")
self.datapath = mpapath.replace(".mpa",".lst")
self.dataindex = 0
print("Set filename...", self.datapath.split("\\")[-1])
# self.device.erase_measruement() # Don't erase because this takes super long for some reason
self.device.start_measurement()
self.start_time = time.perf_counter()
time.sleep(0.2) # some buffer time to make sure the measurement already started for sure
# TODO: What's the minimum time to wait here?
# Save where to find the measurement data (which file and within file)
with h5py.File(h5_file,'r+') as f:
group = f[f"devices/{self.device_name}"]
group.attrs["datapath"] = self.datapath
group.attrs["dataindex"] = self.dataindex
self.dataindex += group.attrs["n_trigger"]
return {}
......@@ -104,5 +94,5 @@ class MCS8AWorker(Worker):
def abort_transition_to_buffered(self):
return True
# def shutdown(self):
# self.device._send_dll_command("exit")
\ No newline at end of file
def shutdown(self):
self.device._send_dll_command("exit")
\ No newline at end of file
......@@ -2,11 +2,11 @@
# #
# /user_devices/FastComtecMCS8A/labscript_devices.py #
# #
# Jan 2023, Stephan Roschinski #
# Feb. 2024, Leonard Group #
# #
# #
#####################################################################
from labscript import TriggerableDevice, LabscriptError, set_passed_properties
from labscript import TriggerableDevice, LabscriptError, set_passed_properties, config
import numpy as np
class MCS8A(TriggerableDevice):
......@@ -19,34 +19,23 @@ class MCS8A(TriggerableDevice):
super().__init__(name, parent_device, connection, **kwargs)
self.BLACS_connection = "SPCM MCS8A"
self.config_path = config_path
self.commands = {}
self.labels = {}
def do_checks(self):
if len(self.trigger_device.triggerings) > 1:
raise NotImplementedError("Only 1 acquistuin allowed, working on code!")
def set_dll_command(self, command, value = None):
if command in self.commands:
raise LabscriptError("Do not set the same config command twice!")
self.commands[command] = value
def set_binwidth_and_duration(self, binwidth, duration):
"""
Parameters:
"""
bitshift = round(np.log2(binwidth/400e-12))
self.set_dll_command(f"bitshift", hex(bitshift)[2:])
range_dec = duration/binwidth//64 * 64
self.set_dll_command("range", str(int(range_dec)))
def acquire(self, t, duration, trigger_duration=None, label=""):
if trigger_duration is None:
trigger_duration = duration
self.labels[t] = label
self.trigger(t,trigger_duration)
def generate_code(self, hdf5_file):
group = hdf5_file.create_group(f"devices/{self.name}")
commands_group = group.create_group("commands")
for command,value in self.commands.items():
commands_group.attrs[command] = value
labels_group = group.create_group("labels")
for t,label in self.labels.items():
labels_group.attrs[str(t)] = label
self.do_checks()
group.attrs["n_trigger"] = len(self.trigger_device.triggerings)
durations = [triggering[1] for triggering in self.trigger_device.triggerings]
group.create_dataset("durations", compression = config.compression, data = durations)
super().generate_code(hdf5_file)
......
[MCS8A A] 208 FW 3.104 SV 1.243
range=29824
periods=2
sweepmode=22fd2088
fstchan=0
holdafter=0
streamstatus=3
calreg0=0
calreg1=0
calreg2=0
calreg3=0
swpreset=1
prena=6
syncout=0
cycles=2
sequences=1
tagbits=16
vdac0=1079c
vdac1=479c
vdac2=43b4
vdac3=3b4
vdac4=3b4
vdac5=3b4
vdac6=3b4
vdac7=3b4
timepreset=0.000
digio=0
digval=0
autoinc=0
savedata=1
mpafmt=asc
sephead=1
fmt=asc
smoothpts=5
wndwidth=163
wndheight=286
sysdef=0
showstarts=0
[CHN1]
range=29824
active=0
bitshift=11
cftfak=2580100
evpreset=10
roimin=0
roimax=29824
caloff=0.000000
calfact=52428.800000
calfact2=0
calfact3=0
calunit=nsec
caluse=1
[CHN2]
range=29824
active=1
bitshift=11
cftfak=2580100
evpreset=10
roimin=0
roimax=64
caloff=0.000000
calfact=52428.800000
calfact2=0
calfact3=0
calunit=nsec
caluse=1
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment