From 91488183381b32bb62a18a933c7f6db45941028e Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Wed, 5 Nov 2025 12:45:04 -0800 Subject: [PATCH 01/13] Remove references to epics --- sodetlib/__init__.py | 1 - sodetlib/det_config.py | 11 +++-------- sodetlib/util.py | 17 ++++++++--------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/sodetlib/__init__.py b/sodetlib/__init__.py index 359f45cb..931b5a50 100644 --- a/sodetlib/__init__.py +++ b/sodetlib/__init__.py @@ -1,7 +1,6 @@ import os from functools import wraps try: - import epics from pysmurf.client.util.pub import set_action except Exception as e: # Just return base function regularly if can't import set_action diff --git a/sodetlib/det_config.py b/sodetlib/det_config.py index 58c22170..5c8ac527 100644 --- a/sodetlib/det_config.py +++ b/sodetlib/det_config.py @@ -640,22 +640,19 @@ def dump_configs(self, output_dir=None, clobber=False, dump_rogue_tree=False): return outfiles - def get_smurf_control(self, offline=False, epics_root=None, + def get_smurf_control(self, offline=False, smurfpub_id=None, make_logfile=False, setup=False, dump_configs=None, config_dir=None, apply_dev_configs=False, load_device_tune=True, **pysmurf_kwargs): """ Creates pysmurf instance based off of configuration parameters. - If not specified as keyword arguments ``epics_root`` and ``smurf_pub`` + If not specified as keyword arguments ``smurf_pub`` will be created based on the slot and crate id's. Args: offline (bool): Whether to start pysmurf in offline mode. Defaults to False - epics_root (str, optional): - Pysmurf epics root. If none, it will be set to - ``smurf_server_s``. smurfpub_id (str, optional): Pysmurf publisher ID. If None, will default to crate_slot. @@ -674,8 +671,6 @@ def get_smurf_control(self, offline=False, epics_root=None, import pysmurf.client slot_cfg = self.sys['slots'][f'SLOT[{self.slot}]'] - if epics_root is None: - epics_root = f'smurf_server_s{self.slot}' if smurfpub_id is None: smurfpub_id = self.stream_id if dump_configs is None: @@ -688,7 +683,7 @@ def get_smurf_control(self, offline=False, epics_root=None, S = pysmurf.client.SmurfControl(offline=True) else: S = pysmurf.client.SmurfControl( - epics_root=epics_root, cfg_file=self.pysmurf_file, setup=setup, + cfg_file=self.pysmurf_file, setup=setup, make_logfile=make_logfile, data_path_id=smurfpub_id, **pysmurf_kwargs) self.S = S diff --git a/sodetlib/util.py b/sodetlib/util.py index f960f7c9..45ef6adf 100644 --- a/sodetlib/util.py +++ b/sodetlib/util.py @@ -15,7 +15,6 @@ if not os.environ.get('NO_PYSMURF', False): try: - import epics import pysmurf from pysmurf.client.command.cryo_card import cmd_make except Exception: @@ -208,8 +207,8 @@ def get_metadata(S, cfg): 'iv_file': cfg.dev.exp.get('iv_file'), 'v_bias': S.get_tes_bias_bipolar_array(), 'pysmurf_client_version': pysmurf.__version__, - 'rogue_version': S._caget(f'{S.epics_root}:AMCc:RogueVersion'), - 'smurf_core_version': S._caget(f'{S.epics_root}:AMCc:SmurfApplication:SmurfVersion'), + 'rogue_version': S._caget('AMCc.RogueVersion'), + 'smurf_core_version': S._caget('AMCc.SmurfApplication.SmurfVersion'), 'sodetlib_version': sodetlib.__version__, 'fpga_git_hash': S.get_fpga_git_hash_short(), 'cryocard_fw_version': S.C.get_fw_version(), @@ -541,7 +540,7 @@ def get_r2(sig, sig_hat): class _Register: def __init__(self, S, addr): self.S = S - self.addr = S.epics_root + ":" + addr + self.addr = addr def get(self, **kw): return self.S._caget(self.addr, **kw) @@ -555,11 +554,11 @@ class Registers: they are not in the standard rogue tree, or settable by existing pysmurf get/set functions """ - _root = 'AMCc:' - _processor = _root + "SmurfProcessor:" - _sostream = _processor + "SOStream:" - _sofilewriter = _sostream + 'SOFileWriter:' - _source_root = _root + 'StreamDataSource:' + _root = 'AMCc.' + _processor = _root + "SmurfProcessor." + _sostream = _processor + "SOStream." + _sofilewriter = _sostream + 'SOFileWriter.' + _source_root = _root + 'StreamDataSource.' _registers = { 'pysmurf_action': _sostream + 'pysmurf_action', From c0464e9659c44bbc79ff0f54506eb933c920e624 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Wed, 5 Nov 2025 12:46:49 -0800 Subject: [PATCH 02/13] fix(util.set_current_mode): Fix up cryo card access bypassing pysmurf. --- sodetlib/util.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sodetlib/util.py b/sodetlib/util.py index 45ef6adf..c797e7e0 100644 --- a/sodetlib/util.py +++ b/sodetlib/util.py @@ -672,25 +672,19 @@ def set_current_mode(S, bgs, mode, const_current=True): nbits = S._rtm_slow_dac_nbits dac_data = np.clip(dac_data, -2**(nbits-1), 2**(nbits-1)-1) - dac_data_reg = S.rtm_spi_max_root + S._rtm_slow_dac_data_array_reg - - - if isinstance(S.C.writepv, str): - cryocard_writepv = S.C.writepv - else: - cryocard_writepv = S.C.writepv.pvname + dac_data_reg = S.rtm_spi_max_root + S._rtm_slow_dac_data_reg # It takes longer for DC voltages to settle than it does to toggle the # high-current relay, so we can set them at the same time when switchign # to hcm, but when switching to lcm we need a sleep statement to prevent # dets from latching. if mode: - epics.caput_many([cryocard_writepv, dac_data_reg], [relay_data, dac_data], - wait=True) + S._caput(dac_data_reg, dac_data, wait_done=False) + S.C.do_write(S.C.relay_address, new_relay) else: S._caput(dac_data_reg, dac_data) time.sleep(0.04) - S._caput(cryocard_writepv, relay_data) + S.C.do_write(S.C.relay_address, new_relay) time.sleep(0.1) # Just to be safe From 41c72cfb6088b8a7c16b5342ad857b249a8e0b25 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Wed, 5 Nov 2025 16:24:57 -0800 Subject: [PATCH 03/13] fix(get_smurf_control): Added server_port argument. --- sodetlib/det_config.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sodetlib/det_config.py b/sodetlib/det_config.py index 5c8ac527..fb37e85d 100644 --- a/sodetlib/det_config.py +++ b/sodetlib/det_config.py @@ -640,7 +640,7 @@ def dump_configs(self, output_dir=None, clobber=False, dump_rogue_tree=False): return outfiles - def get_smurf_control(self, offline=False, + def get_smurf_control(self, offline=False, server_port=None, smurfpub_id=None, make_logfile=False, setup=False, dump_configs=None, config_dir=None, apply_dev_configs=False, load_device_tune=True, @@ -653,6 +653,9 @@ def get_smurf_control(self, offline=False, Args: offline (bool): Whether to start pysmurf in offline mode. Defaults to False + server_port (int, optional): + The port for the SMuRF server to connect to. Will infer from + slot number if not provided. smurfpub_id (str, optional): Pysmurf publisher ID. If None, will default to crate_slot. @@ -675,6 +678,8 @@ def get_smurf_control(self, offline=False, smurfpub_id = self.stream_id if dump_configs is None: dump_configs = self.dump + if server_port is None: + server_port = 9000 + 2 * self.slot # Pysmurf publisher will check this to determine publisher id. os.environ['SMURFPUB_ID'] = smurfpub_id @@ -685,7 +690,8 @@ def get_smurf_control(self, offline=False, S = pysmurf.client.SmurfControl( cfg_file=self.pysmurf_file, setup=setup, make_logfile=make_logfile, data_path_id=smurfpub_id, - **pysmurf_kwargs) + server_port=server_port, **pysmurf_kwargs + ) self.S = S # Lets just stash this in pysmurf... S._sodetlib_cfg = self From 81f5d75f67e5301487896f74d58b62df725dbf71 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Wed, 5 Nov 2025 17:49:57 -0800 Subject: [PATCH 04/13] fix(jackhammer): Update wait for epics server. --- requirements.txt | 1 + sodetlib/hammers/jackhammer.py | 49 +++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/requirements.txt b/requirements.txt index 61bbe80b..b05b4788 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ scipy matplotlib lmfit pandas +zmq # Can install sotodlib from PyPI once Python version in pysmurf-controller is >=3.10 # i.e. when [1] is merged and propagated to [2]. # [1] - https://github.com/simonsobs/smurf_dockers/pull/6 diff --git a/sodetlib/hammers/jackhammer.py b/sodetlib/hammers/jackhammer.py index e36a74da..5f47d6e6 100644 --- a/sodetlib/hammers/jackhammer.py +++ b/sodetlib/hammers/jackhammer.py @@ -7,6 +7,7 @@ import os import threading from typing import List, Literal +import zmq class TermColors: @@ -108,36 +109,47 @@ def util_run(cmd, args=[], name=None, rm=True, **run_kwargs): return subprocess.run(shlex.split(cmd), cwd=cwd, **run_kwargs) -def check_epics_connection(epics_server, retry=False): +def check_server_connection(server_port, retry=False, timeout=1): """ - Checks if we can connect to a specific epics server. + Checks if we can connect to a specific server. Args: - epics_server (string): - epics server to connect to + server_port (int): + ZMQ server to connect to retry (bool): If true, will continuously check until a connection has been established. """ + # setup connection + c = zmq.Context() + + # message to check if server is ready + msg = {'path': 'AMCc.Ready', 'attr': 'get', 'args': [], 'kwargs': {}} + def do_ping(): + s = c.socket(zmq.REQ) + s.setsockopt(zmq.RCVTIMEO, timeout * 1000) + s.setsockopt(zmq.LINGER, 0) # discard undelivered messages + s.connect(f"tcp://localhost:{server_port + 1}") + try: + s.send_pyobj(msg) + resp = s.recv_pyobj() + return bool(resp) + except zmq.error.Again: + return False + finally: + s.close() + if retry: - print(f"Waiting for epics connection to {epics_server}", end='', flush=True) + print(f"Waiting for connection to server on port {server_port}", end='', flush=True) while True: - x = util_run( - 'caget', args=[f'{epics_server}:AMCc:enable'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT - ) - if "True" in x.stdout.decode(): + if do_ping(): break print('.', end='', flush=True) print("\nConnected!") return True else: - x = util_run( - 'caget', args=[f'{epics_server}:AMCc:enable'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT - ) - return "True" in x.stdout.decode() + return do_ping() def get_running_dockers(get_all=True): @@ -243,13 +255,13 @@ def dump_docker_logs(slots, dump_rogue_tree=False): if dump_rogue_tree: dump_script = '/sodetlib/scripts/dump_rogue_state.py' for slot in slots: - if check_epics_connection(f'smurf_server_s{slot}', retry=False): + if check_server_connection(9000 + 2 * slot, retry=False): out_file = os.path.join(dump_dir, f'rogue_state_s{slot}.yml') cprint(f"Dumping s{slot} state to {out_file}", style=TermColors.HEADER) util_run('python3', args=[dump_script, str(slot), out_file], name=f'rogue_dump_s{slot}') else: - print(f"Could not connect to epics for slot {slot}") + print(f"Could not connect to server for slot {slot}") def run_on_shelf_manager(cmd_str): """ Runs a command on the shelf manager. Takes in the command as a string""" @@ -474,8 +486,7 @@ def hammer_func(args): # Waits for streamer-dockers to start print("Waiting for server dockers to connect. This might take a few minutes...") for slot in slots: - epics_server = f'smurf_server_s{slot}' - check_epics_connection(epics_server, retry=True) + check_server_connection(9000 + 2 * slot, retry=True) if reboot and not args.skip_setup: cprint("Configuring pysmurf", style=TermColors.HEADER) From dd0ef3b3a68e08d4667bbe6cfc172a7a393daf40 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Thu, 20 Nov 2025 15:58:22 -0800 Subject: [PATCH 05/13] fix: Remove references to deprecated GradientDescent parameters. --- sodetlib/det_config.py | 3 --- sodetlib/operations/uxm_relock.py | 7 +------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/sodetlib/det_config.py b/sodetlib/det_config.py index fb37e85d..23d30c0b 100644 --- a/sodetlib/det_config.py +++ b/sodetlib/det_config.py @@ -117,11 +117,8 @@ def odict_rep(dumper, data): # Gradient Descent Parameters "gradientDescentMaxIters": 100, "gradientDescentAverages": 2, - "gradientDescentGain": 0.001, "gradientDescentConvergeHz": 500, "gradientDescentStepHz": 5000, - "gradientDescentMomentum": 1, - "gradientDescentBeta": 0.1, # Fixed tones "fixed_tones": {"enabled": False, "freq_offsets": [], "channels": [], "tone_power": 0}, diff --git a/sodetlib/operations/uxm_relock.py b/sodetlib/operations/uxm_relock.py index 5d13161f..e3f3036f 100644 --- a/sodetlib/operations/uxm_relock.py +++ b/sodetlib/operations/uxm_relock.py @@ -65,8 +65,7 @@ def reload_tune(S, cfg, bands, setup_notches=False, @sdl.set_action() def run_grad_descent_and_eta_scan( - S, cfg, bands=None, update_tune=False, force_run=False, max_iters=None, - gain=None): + S, cfg, bands=None, update_tune=False, force_run=False, max_iters=None): """ This function runs serial gradient and eta scan for each band. Critically, it pulls in gradient descent tune parameters from the device @@ -108,14 +107,10 @@ def run_grad_descent_and_eta_scan( if max_iters is None: max_iters = bcfg['gradientDescentMaxIters'] - if gain is None: - gain = bcfg['gradientDescentGain'] S.set_gradient_descent_step_hz(b, bcfg['gradientDescentStepHz']) S.set_gradient_descent_max_iters(b, max_iters) - S.set_gradient_descent_gain(b, gain) S.set_gradient_descent_converge_hz(b, bcfg['gradientDescentConvergeHz']) - S.set_gradient_descent_beta(b, bcfg['gradientDescentBeta']) S.log(f"Running grad descent and eta scan on band {b}") From 72cc717d85d530e1f271e3fc4188372261229030 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Mon, 15 Dec 2025 11:10:52 -0800 Subject: [PATCH 06/13] fix: Update server port convention to use factor of 3 --- sodetlib/det_config.py | 2 +- sodetlib/hammers/jackhammer.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sodetlib/det_config.py b/sodetlib/det_config.py index 23d30c0b..a3c5753d 100644 --- a/sodetlib/det_config.py +++ b/sodetlib/det_config.py @@ -676,7 +676,7 @@ def get_smurf_control(self, offline=False, server_port=None, if dump_configs is None: dump_configs = self.dump if server_port is None: - server_port = 9000 + 2 * self.slot + server_port = 9000 + 3 * self.slot # Pysmurf publisher will check this to determine publisher id. os.environ['SMURFPUB_ID'] = smurfpub_id diff --git a/sodetlib/hammers/jackhammer.py b/sodetlib/hammers/jackhammer.py index 5f47d6e6..f0bdeb60 100644 --- a/sodetlib/hammers/jackhammer.py +++ b/sodetlib/hammers/jackhammer.py @@ -255,7 +255,7 @@ def dump_docker_logs(slots, dump_rogue_tree=False): if dump_rogue_tree: dump_script = '/sodetlib/scripts/dump_rogue_state.py' for slot in slots: - if check_server_connection(9000 + 2 * slot, retry=False): + if check_server_connection(9000 + 3 * slot, retry=False): out_file = os.path.join(dump_dir, f'rogue_state_s{slot}.yml') cprint(f"Dumping s{slot} state to {out_file}", style=TermColors.HEADER) util_run('python3', args=[dump_script, str(slot), out_file], @@ -486,7 +486,7 @@ def hammer_func(args): # Waits for streamer-dockers to start print("Waiting for server dockers to connect. This might take a few minutes...") for slot in slots: - check_server_connection(9000 + 2 * slot, retry=True) + check_server_connection(9000 + 3 * slot, retry=True) if reboot and not args.skip_setup: cprint("Configuring pysmurf", style=TermColors.HEADER) @@ -575,7 +575,7 @@ def gui_func(args): slot = args.slot else: slot = available_slots[0] - server_port = 9000 + 2*slot + server_port = 9000 + 3*slot sodetlib_root = os.environ.get('SODETLIB_ROOT', '/home/cryo/sodetlib') script_path = os.path.join(sodetlib_root, 'hammers', 'run_gui.sh') From 4549ee918f036b45dc659242ff723a5448e09849 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Tue, 6 Jan 2026 11:55:00 -0800 Subject: [PATCH 07/13] feat(setup_amps): Add argument to pass on to optimisation function --- sodetlib/operations/uxm_setup.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sodetlib/operations/uxm_setup.py b/sodetlib/operations/uxm_setup.py index 9f0530ab..2db11968 100644 --- a/sodetlib/operations/uxm_setup.py +++ b/sodetlib/operations/uxm_setup.py @@ -145,7 +145,7 @@ def find_drain_voltage(S, target_Id, amp_name, vd_min=0.1, vd_max=0.95, @sdl.set_action() -def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True): +def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args={}): """ Initial setup for 50k and hemt amplifiers. For C04/C05 cryocards, will first check if the drain voltages are set. Then checks if drain @@ -175,6 +175,8 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True): If true, will update the device cfg and save the file. enable_300K_LNA: If true, will turn on the 300K LNAs. + opt_args : dict (optional) + Extra kwargs to pass to the `find_gate_voltage` calls. """ sdl.pub_ocs_log(S, "Starting setup_amps") @@ -223,6 +225,9 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True): if Vd != exp[f"amp_{amp}_drain_volt"]: S.set_amp_drain_voltage(amp, exp[f"amp_{amp}_drain_volt"]) + # extra args for optimisation + if "wait_time" not in opt_args: + opt_args["wait_time"] = exp['amp_step_wait_time'] # Check drain currents / scan bias voltages for amp in amp_list: delta_Id = np.abs(amp_biases[f"{amp}_drain_current"] - exp[f"amp_{amp}_drain_current"]) @@ -235,20 +240,23 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True): ): S.log(f"{amp} current not within tolerance, scanning for correct drain voltage") success = find_drain_voltage( - S, exp[f"amp_{amp}_drain_current"], amp, wait_time=exp['amp_step_wait_time'], - id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], + S, exp[f"amp_{amp}_drain_current"], amp, + id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], **opt_args ) else: S.log(f"{amp} current not within tolerance, scanning for correct gate voltage") + if "vg_min" not in opt_args: + opt_args["vg_min"] = exp[f'amp_{amp}_gate_volt_min'] + if "vg_max" not in opt_args: + opt_args["vg_max"] = exp[f'amp_{amp}_gate_volt_max'], # If optimal value was found previously, use it first. init_gate_volt = exp[f'amp_{amp}_gate_volt'] if init_gate_volt is None: init_gate_volt = exp[f'amp_{amp}_init_gate_volt'] S.set_amp_gate_voltage(amp, init_gate_volt,override=True) success = find_gate_voltage( - S, exp[f"amp_{amp}_drain_current"], amp, wait_time=exp['amp_step_wait_time'], - id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], - vg_min=exp[f'amp_{amp}_gate_volt_min'], vg_max=exp[f'amp_{amp}_gate_volt_max'], + S, exp[f"amp_{amp}_drain_current"], amp, + id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], **opt_args ) if not success: sdl.pub_ocs_log(S, f"Failed determining {amp} bias voltage") From 69f45b572439c31d727a63c3b737e7727e12e0b9 Mon Sep 17 00:00:00 2001 From: simonscryo Date: Mon, 23 Feb 2026 23:02:07 +0000 Subject: [PATCH 08/13] fix(det_config): str/int typo --- sodetlib/det_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sodetlib/det_config.py b/sodetlib/det_config.py index a3c5753d..907ddcba 100644 --- a/sodetlib/det_config.py +++ b/sodetlib/det_config.py @@ -676,7 +676,7 @@ def get_smurf_control(self, offline=False, server_port=None, if dump_configs is None: dump_configs = self.dump if server_port is None: - server_port = 9000 + 3 * self.slot + server_port = 9000 + 3 * int(self.slot) # Pysmurf publisher will check this to determine publisher id. os.environ['SMURFPUB_ID'] = smurfpub_id From a73237fa66e49387f3ce89da50bd5af46d22d0a9 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Tue, 14 Apr 2026 17:12:07 -0700 Subject: [PATCH 09/13] fix(stream_g3_on): Increase max wait time for session ID. --- sodetlib/stream.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sodetlib/stream.py b/sodetlib/stream.py index a2d04123..30f4e6b6 100644 --- a/sodetlib/stream.py +++ b/sodetlib/stream.py @@ -231,8 +231,8 @@ def stream_g3_on(S, make_freq_mask=False, emulator=False, tag=None, reg.open_g3stream.set(1) # Sometimes it takes a bit for data to propogate through to the - # streamer - for _ in range(10): + # streamer. Wait up to 30s + for _ in range(60): sess_id = reg.g3_session_id.get() if sess_id != 0: break From d40f0f78d69ebc74e6f8e89d8bc033cfbeb3c835 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Thu, 16 Apr 2026 12:33:54 -0700 Subject: [PATCH 10/13] fix(requirements): Get sotodlib from pip --- requirements.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index b05b4788..83698a25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,11 +6,7 @@ matplotlib lmfit pandas zmq -# Can install sotodlib from PyPI once Python version in pysmurf-controller is >=3.10 -# i.e. when [1] is merged and propagated to [2]. -# [1] - https://github.com/simonsobs/smurf_dockers/pull/6 -# [2] - https://github.com/simonsobs/socs/blob/main/docker/pysmurf_controller/Dockerfile -sotodlib @ git+https://github.com/simonsobs/sotodlib.git@5d613d5915b1716c401abecb5446088bce5fc1a4 +sotodlib pysmurf-slac # scripts From 73a993d369ab917ee10a4d95ecef83cd6d1913c7 Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Fri, 17 Apr 2026 11:43:39 -0700 Subject: [PATCH 11/13] fix(uxm_setup.setup_amps): opt_args defaults to None. For a reason I don't understand, setting a default of opt_args={} was being ignored and populated with parameter values. --- sodetlib/operations/uxm_setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sodetlib/operations/uxm_setup.py b/sodetlib/operations/uxm_setup.py index 2db11968..c6cdc3d7 100644 --- a/sodetlib/operations/uxm_setup.py +++ b/sodetlib/operations/uxm_setup.py @@ -145,7 +145,7 @@ def find_drain_voltage(S, target_Id, amp_name, vd_min=0.1, vd_max=0.95, @sdl.set_action() -def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args={}): +def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args=None): """ Initial setup for 50k and hemt amplifiers. For C04/C05 cryocards, will first check if the drain voltages are set. Then checks if drain @@ -182,6 +182,9 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args={}): exp = cfg.dev.exp + if opt_args is None: + opt_args = {} + # Determine cryocard rev major, minor, patch = S.C.get_fw_version() if major == 4: From 833492cff978b328700891d2dec9857c0efd674a Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Mon, 20 Apr 2026 11:09:29 -0700 Subject: [PATCH 12/13] fix(uxm_setup.setup_amps): Update opt args for each amp --- sodetlib/operations/uxm_setup.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sodetlib/operations/uxm_setup.py b/sodetlib/operations/uxm_setup.py index c6cdc3d7..2b60e841 100644 --- a/sodetlib/operations/uxm_setup.py +++ b/sodetlib/operations/uxm_setup.py @@ -233,6 +233,8 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args=None): opt_args["wait_time"] = exp['amp_step_wait_time'] # Check drain currents / scan bias voltages for amp in amp_list: + # arguments to pass to optimization function + amp_opts = opt_args.copy() delta_Id = np.abs(amp_biases[f"{amp}_drain_current"] - exp[f"amp_{amp}_drain_current"]) if delta_Id > exp[f'amp_{amp}_drain_current_tolerance']: # Only scan Vd if connected to an ASU hemt @@ -244,14 +246,14 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args=None): S.log(f"{amp} current not within tolerance, scanning for correct drain voltage") success = find_drain_voltage( S, exp[f"amp_{amp}_drain_current"], amp, - id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], **opt_args + id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], **amp_opts ) else: S.log(f"{amp} current not within tolerance, scanning for correct gate voltage") - if "vg_min" not in opt_args: - opt_args["vg_min"] = exp[f'amp_{amp}_gate_volt_min'] + if "vg_min" not in amp_opts: + amp_opts["vg_min"] = exp[f'amp_{amp}_gate_volt_min'] if "vg_max" not in opt_args: - opt_args["vg_max"] = exp[f'amp_{amp}_gate_volt_max'], + amp_opts["vg_max"] = exp[f'amp_{amp}_gate_volt_max'], # If optimal value was found previously, use it first. init_gate_volt = exp[f'amp_{amp}_gate_volt'] if init_gate_volt is None: @@ -259,7 +261,7 @@ def setup_amps(S, cfg, update_cfg=True, enable_300K_LNA=True, opt_args=None): S.set_amp_gate_voltage(amp, init_gate_volt,override=True) success = find_gate_voltage( S, exp[f"amp_{amp}_drain_current"], amp, - id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], **opt_args + id_tolerance=exp[f'amp_{amp}_drain_current_tolerance'], **amp_opts ) if not success: sdl.pub_ocs_log(S, f"Failed determining {amp} bias voltage") From b24c50d75d144aaf010f0c4455db61f63b32a44f Mon Sep 17 00:00:00 2001 From: Tristan Pinsonneault-Marotte Date: Tue, 12 May 2026 16:58:58 -0700 Subject: [PATCH 13/13] fix(stream): Use startG3Stream to ensure status frame fully populated --- sodetlib/stream.py | 4 +++- sodetlib/util.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sodetlib/stream.py b/sodetlib/stream.py index 30f4e6b6..d92e6796 100644 --- a/sodetlib/stream.py +++ b/sodetlib/stream.py @@ -228,7 +228,9 @@ def stream_g3_on(S, make_freq_mask=False, emulator=False, tag=None, reg.source_enable.set(1) S.set_stream_enable(1) - reg.open_g3stream.set(1) + # trigger the g3 streamer to start a new session + # wrapper ensure status frame is properly formed + reg.start_g3stream.set(1) # Sometimes it takes a bit for data to propogate through to the # streamer. Wait up to 30s diff --git a/sodetlib/util.py b/sodetlib/util.py index c797e7e0..c185f54e 100644 --- a/sodetlib/util.py +++ b/sodetlib/util.py @@ -565,6 +565,7 @@ class Registers: 'pysmurf_action_timestamp': _sostream + "pysmurf_action_timestamp", 'stream_tag': _sostream + "stream_tag", 'open_g3stream': _sostream + "open_g3stream", + 'start_g3stream': _sostream + "startG3Stream", 'g3_session_id': _sofilewriter + "session_id", 'g3_filepath': _sofilewriter + "filepath", 'debug_data': _sostream + "DebugData",