From 21e29710fec44016e4dd2b1b442d70219ddc05f7 Mon Sep 17 00:00:00 2001 From: Jesalina Date: Wed, 13 May 2026 18:07:16 -0400 Subject: [PATCH 1/2] new feature: IV sweep jupyter notebook and edit GUI to update immediately --- Measurements/DCIV/IV_sweep_GUI.py | 109 ++++++- Measurements/DCIV/IV_sweep_testing.ipynb | 352 +++++++++++++++++++++++ 2 files changed, 451 insertions(+), 10 deletions(-) create mode 100644 Measurements/DCIV/IV_sweep_testing.ipynb diff --git a/Measurements/DCIV/IV_sweep_GUI.py b/Measurements/DCIV/IV_sweep_GUI.py index 2e3bf55..69b4f4b 100644 --- a/Measurements/DCIV/IV_sweep_GUI.py +++ b/Measurements/DCIV/IV_sweep_GUI.py @@ -4,12 +4,55 @@ import tkinter as tk from tkinter import ttk import numpy as np +import threading +import time +import pandas as pd from piec.drivers.sourcemeter.keithley2400 import Keithley2400 from piec.drivers.sourcemeter.virtual_keithley2400 import VirtualKeithley2400 from piec.measurement.iv_sweep import IVSweep -from piec.analysis.utilities import standard_csv_to_metadata_and_data from piec.measurement.gui_utils import MeasurementApp + +class _LiveIVSweep(IVSweep): + """IVSweep subclass that tracks data live for GUI updates. + + Uses underscore-prefixed attributes so _update_metadata() ignores them. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._live_voltages = [] + self._live_currents = [] + + def sweep(self): + voltages = np.linspace(self.v_start, self.v_stop, self.num_steps) + measured_voltages = [] + measured_currents = [] + self._live_voltages = [] + self._live_currents = [] + + print(f"Starting IV sweep: {self.v_start}V to {self.v_stop}V in {self.num_steps} steps...") + self.sourcemeter.output(on=True) + + for i, v in enumerate(voltages): + self.sourcemeter.set_source_voltage(v) + time.sleep(self.dwell_time) + measured_v = self.sourcemeter.get_voltage() + measured_i = self.sourcemeter.get_current() + measured_voltages.append(measured_v) + measured_currents.append(measured_i) + self._live_voltages.append(measured_v) + self._live_currents.append(measured_i) + + if (i + 1) % max(1, self.num_steps // 10) == 0: + print(f" Step {i + 1}/{self.num_steps}: V={measured_v:.4f} V, I={measured_i:.6e} A") + + self.data = pd.DataFrame({ + "voltage (V)": measured_voltages, + "current (A)": measured_currents, + }) + print("Sweep complete.") + DEFAULTS = { "sm_address": "VIRTUAL", "save_dir": r"your\default\save\directory", @@ -28,6 +71,9 @@ def __init__(self, root): print("Welcome to the IV Sweep GUI!") print("Ctrl+Enter: Run Measurement") + self.measurement_thread = None + self.is_measuring = False + visa_resources = self.get_visa_resources() # Static Inputs (Save Dir is at row 0 in base) @@ -109,6 +155,10 @@ def refresh_instruments(self): self.sm_address_entry.set("VIRTUAL") def run_measurement(self): + if self.is_measuring: + print("Measurement already in progress...") + return + print("Running IV Sweep measurement...") sm_address = self.sm_address_entry.get() @@ -134,7 +184,7 @@ def run_measurement(self): else: sourcemeter = Keithley2400(sm_address) - self.experiment = IVSweep( + self.experiment = _LiveIVSweep( sourcemeter=sourcemeter, v_start=v_start, v_stop=v_stop, @@ -144,18 +194,57 @@ def run_measurement(self): sense_mode=sense_mode, save_dir=save_dir, ) - self.experiment.run_experiment() + + self.is_measuring = True + self.run_button.config(state='disabled') + + self.measurement_thread = threading.Thread( + target=self.experiment.run_experiment, + daemon=True, + ) + self.measurement_thread.start() + self.update_plot_loop() + + def update_plot_loop(self): + if not self.is_measuring: + return + self.plot_data() + if self.measurement_thread and self.measurement_thread.is_alive(): + self.root.after(500, self.update_plot_loop) + else: + self.is_measuring = False + self.run_button.config(state='normal') + print("Measurement complete.") + self.plot_data() + def plot_data(self, event=None): - self.ax.clear() - metadata, data = standard_csv_to_metadata_and_data(self.experiment.filename) - x_data = data[self.x_axis.get()] - y_data = data[self.y_axis.get()] + if not hasattr(self, 'experiment'): + return - self.ax.plot(x_data, y_data, marker=".", color="k", label=f"{self.y_axis.get()} vs {self.x_axis.get()}") - self.ax.set_xlabel(self.x_axis.get()) - self.ax.set_ylabel(self.y_axis.get()) + live_v = self.experiment._live_voltages + live_i = self.experiment._live_currents + + if not live_v: + return + + live_data = { + "voltage (V)": live_v, + "current (A)": live_i, + } + + x_col = self.x_axis.get() + y_col = self.y_axis.get() + + if x_col not in live_data or y_col not in live_data: + return + + self.ax.clear() + self.ax.plot(live_data[x_col], live_data[y_col], marker=".", color="k", + label=f"{y_col} vs {x_col}") + self.ax.set_xlabel(x_col) + self.ax.set_ylabel(y_col) self.canvas.draw() diff --git a/Measurements/DCIV/IV_sweep_testing.ipynb b/Measurements/DCIV/IV_sweep_testing.ipynb new file mode 100644 index 0000000..16f81a6 --- /dev/null +++ b/Measurements/DCIV/IV_sweep_testing.ipynb @@ -0,0 +1,352 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cell-0", + "metadata": {}, + "source": [ + "# Caretta Lab IV Sweep Testing Notebook" + ] + }, + { + "cell_type": "markdown", + "id": "cell-1", + "metadata": {}, + "source": [ + "This python notebook provides an interactive interface with the IV sweep measurement functionality available in the open source Python Integrated Experiment Control (piec) package. The IV sweep uses a sourcemeter to step voltage from a start to stop value, measuring current at each step to characterize the current-voltage relationship of a device. Code documentation and setup details can be found at https://piec.readthedocs.io." + ] + }, + { + "cell_type": "markdown", + "id": "cell-2", + "metadata": {}, + "source": [ + "*COPY THIS NOTEBOOK AND RUN IN A LOCAL DIRECTORY TO PREVENT IT FROM BEING OVERWRITTEN BY GITHUB*" + ] + }, + { + "cell_type": "markdown", + "id": "cell-3", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "cell-4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Warning: if using digilent please check the readme file and install the required dependencies (UL) or try running pip install mcculw\n" + ] + } + ], + "source": [ + "from piec.drivers.sourcemeter.virtual_keithley2400 import VirtualKeithley2400\n", + "from piec.measurement.iv_sweep import IVSweep\n", + "from piec.analysis.utilities import standard_csv_to_metadata_and_data\n", + "from piec.drivers.utilities import PiecManager\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import numpy as np\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cell-5", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\Jesalina Phan\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-packages\\pyvisa_py\\tcpip.py:122: UserWarning: TCPIP::hislip resource discovery requires the zeroconf package to be installed... try 'pip install zeroconf'\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "text/plain": [ + "()" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pm = PiecManager()\n", + "pm.list_resources()" + ] + }, + { + "cell_type": "markdown", + "id": "cell-6", + "metadata": {}, + "source": [ + "### Instrument Setup" + ] + }, + { + "cell_type": "markdown", + "id": "cell-7", + "metadata": {}, + "source": [ + "The IV sweep requires one instrument:\n", + "- **Sourcemeter** (sourcemeter): Sources voltage and measures current simultaneously. Typically a Keithley 2400.\n", + "\n", + "In piec, each instrument is represented by a class object. Initialize it with the appropriate VISA address. Use `'VIRTUAL'` to run in simulation mode without real hardware." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cell-8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sourcemeter: Virtual Keithley 2400\n" + ] + } + ], + "source": [ + "sourcemeter = VirtualKeithley2400() # Sourcemeter: 'GPIB0::24::INSTR' for real, VirtualKeithley2400() for simulation\n", + "\n", + "print('Sourcemeter: ', sourcemeter.idn())" + ] + }, + { + "cell_type": "markdown", + "id": "cell-9", + "metadata": {}, + "source": [ + "### IV Sweep Measurement" + ] + }, + { + "cell_type": "markdown", + "id": "cell-10", + "metadata": {}, + "source": [ + "The IV sweep steps voltage linearly from `v_start` to `v_stop` in `num_steps` steps. At each step, the sourcemeter waits `dwell_time` seconds then records the measured voltage and current. The result is an I-V curve characterizing the device under test.\n", + "\n", + "Key parameters:\n", + "- **v_start**: Starting voltage in Volts.\n", + "- **v_stop**: Ending voltage in Volts.\n", + "- **num_steps**: Number of voltage steps in the sweep.\n", + "- **current_compliance**: Maximum allowed current in Amps — protects the device from overcurrent.\n", + "- **dwell_time**: Time to wait at each voltage step before measuring (seconds).\n", + "- **sense_mode**: `'2W'` for 2-wire (remote sense off) or `'4W'` for 4-wire (Kelvin) sensing." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "cell-11", + "metadata": {}, + "outputs": [], + "source": [ + "### VARIABLE DEFINITIONS ###\n", + "\n", + "path = r\"scratch\" # path to save data, make sure directory exists and you have permissions\n", + "\n", + "v_start = 0.0 # starting voltage (V)\n", + "v_stop = 1.0 # ending voltage (V)\n", + "num_steps = 50 # number of voltage steps\n", + "current_compliance = 0.1 # current compliance limit (A)\n", + "dwell_time = 0.1 # wait time at each step before measuring (s)\n", + "sense_mode = '2W' # sensing mode: '2W' or '4W'" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "cell-12", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running IV sweep experiment...\n", + "Sourcemeter configured.\n", + "Starting IV sweep: 0.0V to 1.0V in 50 steps...\n", + " Step 5/50: V=0.0816 V, I=0.000000e+00 A\n", + " Step 10/50: V=0.1837 V, I=0.000000e+00 A\n", + " Step 15/50: V=0.2857 V, I=0.000000e+00 A\n", + " Step 20/50: V=0.3878 V, I=0.000000e+00 A\n", + " Step 25/50: V=0.4898 V, I=0.000000e+00 A\n", + " Step 30/50: V=0.5918 V, I=0.000000e+00 A\n", + " Step 35/50: V=0.6939 V, I=0.000000e+00 A\n", + " Step 40/50: V=0.7959 V, I=0.000000e+00 A\n", + " Step 45/50: V=0.8980 V, I=0.000000e+00 A\n", + " Step 50/50: V=1.0000 V, I=0.000000e+00 A\n", + "Sweep complete.\n", + "Output off.\n", + "IV sweep data saved to scratch\\0_iv_sweep_0p0V_to_1p0V.csv\n", + "Experiment complete.\n" + ] + } + ], + "source": [ + "### RUN ###\n", + "\n", + "experiment = IVSweep(\n", + " sourcemeter=sourcemeter,\n", + " v_start=v_start,\n", + " v_stop=v_stop,\n", + " num_steps=num_steps,\n", + " current_compliance=current_compliance,\n", + " dwell_time=dwell_time,\n", + " sense_mode=sense_mode,\n", + " save_dir=path,\n", + ")\n", + "\n", + "# Run the experiment — this will configure the sourcemeter,\n", + "# step through voltages capturing data, save results, and return.\n", + "experiment.run_experiment()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cell-13", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
voltage (V)current (A)
00.0000000.0
10.0204080.0
20.0408160.0
30.0612240.0
40.0816330.0
\n", + "
" + ], + "text/plain": [ + " voltage (V) current (A)\n", + "0 0.000000 0.0\n", + "1 0.020408 0.0\n", + "2 0.040816 0.0\n", + "3 0.061224 0.0\n", + "4 0.081633 0.0" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Retrieve the captured data for further analysis\n", + "iv_metadata, iv_df = standard_csv_to_metadata_and_data(experiment.filename)\n", + "iv_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cell-14", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Pn36OnglAABQc1SrYPHAAw/EBRdcEIMGDYqJEyfGrrvuGj179oxZs2aVWn7s2LHRu3fv6NOnT0yaNCmOPvrobJk8eXK2/ZtvvsmOc9lll2VfH3rooZg6dWoceeSR6/iVAQBA9VanUCgUoppILRR77rln3Hrrrdnj5cuXR5s2beK8886Lfv36rVL+hBNOiK+//joee+yx4nV77bVXdOrUKe64445Sn2P8+PHRpUuX+Oijj2KrrbZao3rNnz8/mjZtGvPmzYsmTZr8z68PAACqkvJc51abFovFixfHhAkTokePHsXr6tatmz0eN25cqfuk9SuWT1ILx+rKJ+lNq1OnTjRr1my1ZRYtWpS9ySsuAABQm1WbYDF79uxYtmxZtGjRosT69HjGjBml7pPWl6f8woULszEXqftUWYns6quvzpJb0ZJaTQAAoDarNsGioqWB3Mcff3yknmG33357mWX79++ftWwULdOmTVtn9QQAgKqoflQTm266adSrVy9mzpxZYn163LJly1L3SevXpHxRqEjjKkaPHv2d/ccaNWqULQAAQDVrsWjYsGHsscce8fTTTxevS4O30+Nu3bqVuk9av2L55MknnyxRvihUvPPOO/HUU09F8+bNK/BVAABAzVRtWiySNNXsqaeeGp07d85mbho8eHA269Ppp5+ebU/3oGjdunU2BiL55S9/Gfvvv3/ccMMNcdhhh8WwYcPi5ZdfjjvvvLM4VBx33HHZVLNp5qg0hqNo/MUmm2yShRkAAKCGBYs0feznn38eAwcOzAJAmjZ21KhRxQO0P/7442ymqCLdu3eP+++/Py699NK45JJLYvvtt4+HH344dt5552z7p59+Go8++mj2fTrWisaMGRMHHHDAOn19AABQXVWr+1hUVe5jAQBATVQj72MBAABUXYIFAACQm2ABAADkJlgAAAC5CRYAAEBuggUAAJCbYAEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAACQm2ABAADkJlgAAAC5CRYAAEBuggUAAJCbYAEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAACQm2ABAADkJlgAAAC5CRYAAEBuggUAAJBb/fIUnjt3bowYMSKeffbZ+Oijj+Kbb76JzTbbLHbbbbfo2bNndO/ePX+NAACAmtliMX369DjjjDNiiy22iKuuuiq+/fbb6NSpUxx88MGx5ZZbxpgxY+L73/9+dOjQIR544IGKrzUAAFD9WixSi8Spp54aEyZMyMJDaVLYePjhh2Pw4MExbdq0uOiii9Z2XQEAgCqqTqFQKHxXoS+++CKaN2++xgctb/nqbv78+dG0adOYN29eNGnSpLKrAwAA6/w6d426Qq1JSFi+fHk89thja1weAACopYO3S/Puu+/GXXfdFUOHDo3PP/88lixZsnZqBgAA1OzpZtN4invvvTf222+/2HHHHWPs2LExcODA+OSTT9Z+DQEAgJrVYjF+/Pj405/+FMOGDYu2bdvGSSedlIWK2267bbWDugEAgJpvjYPFLrvskg3eOPHEE7MwsdNOO2Xr+/XrV5H1AwAAalJXqKlTp2Zdnw488ECtEwAAwP8WLN5///1sPMXZZ5+d3RQv3adi0qRJUadOnTU9BAAAUNuDRevWrWPAgAHZLFB/+ctfYsaMGbH33nvH0qVLsxmh3n777YqtKQAAULNmhTrooIPir3/9a3z22Wdx6623xujRo6Ndu3bZOAwAAKD2+Z+CRZF0F76f//zn8fLLL8fEiRPjgAMOWHs1AwAAqo06hUKhUNmVqE23OgcAgJp4nbtGLRaHHnpovPDCC99ZbsGCBfG73/0uhgwZsua1BQAAasd9LH70ox/Fsccem6WVI444Ijp37hytWrWKxo0bx5w5c2LKlCnx3HPPxciRI+Owww6L6667ruJrDgAAVL+uUIsWLYrhw4fHAw88kIWI1BySHaBOney+Fj179ow+ffpE+/bto7bRFQoAgNp+nfs/j7FIB//222+jefPm0aBBg6jNBAsAAGr7de4adYUqTXqCtAAAAOSabhYAACARLAAAgNwECwAAIDfBAgAAWPfBYtttt40vvvhilfVz587NtgEAALVPuYPFhx9+GMuWLSv1Pheffvrp2qoXAABQjazxdLOPPvpo8fePP/54ialmU9B4+umnY5tttln7NQQAAGpOsDj66KOL77R96qmnltiWbpCXQsUNN9yw9msIAADUnGCxfPny7Ov3vve9GD9+fGy66aYVWS8AAKAaKfedtz/44IOKqQkAAFBtlTtYJGk8RVpmzZpV3JJR5K677lpbdQMAAGpqsLj88svjiiuuiM6dO8cWW2yRjbkAAABqt3JPN3vHHXfE0KFD48UXX4yHH344RowYUWKpaEOGDMkGijdu3Di6du0aL730Upnlhw8fHu3atcvKd+zYMUaOHFlie6FQiIEDB2Yhab311osePXrEO++8U8GvAgAAanmwWLx4cXTv3j0qwwMPPBAXXHBBDBo0KCZOnBi77rpr9OzZM+uSVZqxY8dG7969o0+fPjFp0qRsZqu0TJ48ubjMtddeG7fccksWmFJY2mCDDbJjLly4cB2+MgAAqGXB4owzzoj7778/KsONN94Yffv2jdNPPz06dOiQhYH1119/teM6br755jj00EPj4osvjvbt28eVV14Zu+++e9x6663FrRWDBw+OSy+9NI466qjYZZdd4t57743p06dnrTHVwSeffBJjxozJvtrHe+BzUDN+FqpqvezjPfA58LOQ5/eB3zmxzt6DSlMop1/84heFZs2aFfbbb7/CueeeWzj//PNLLBVl0aJFhXr16hVGjBhRYv0pp5xSOPLII0vdp02bNoWbbrqpxLqBAwcWdtlll+z79957r5DegkmTJpUok15bep1rat68edlx0td16Y9//GOhbt262XOnr0OGDCl89dVXZS6pjH28Bz4HVfdnoarWyz7eA58DPwt+t1X+Z+BPf/pTYV0rz3VunfRPeYLIgQceuNptaSD36NGjoyKkVoTWrVtn3Zu6detWvP5Xv/pV/Pe//826Ma2sYcOGcc8992TdoYrcdttt2QD0mTNnZsfae++9s2OnMRZFjj/++Oy1pK5XpVm0aFG2FJk/f360adMm5s2bF02aNIl1IaXWrbfeepVZuQAAqJnq1asXH374YWy55Zbr7DnTdW7Tpk3X6Dq33LNCpaaY2u7qq6/OwkllSgPMhQoAgNpj2bJl8e67767TYFHh97FI0ot67733Yr/99stmU0oNHxU59Wy603dKaamlYUXpccuWLUvdJ60vq3zR17RuxRaL9LhTp06rrUv//v2zQeQrt1isS9tvv33UrVu3RLhI78+UKVOylp3SfPrpp9lYE/t4D3wOqubPgp9R74HPgZ+Fmvj7oKrWq7rus91220WVVd5+VrNnzy4cdNBBhTp16mR9vdI4heT0008vXHDBBYWK1KVLl2xcR5Fly5YVWrduXbj66qtLLX/88ccXDj/88BLrunXrVjjrrLOy75cvX15o2bJl4frrry/envqPNWrUqPC3v/2tyo+xSP3s0riT9Nzp65r0u7OP98DnoGr/LFTVetnHe+Bz4Gchz+8Dv3MK6+w9WNvKc51b7mBx8sknF3r27FmYNm1aYcMNNywOFqNGjSp06NChUJGGDRuWXfQPHTq0MGXKlMKZZ56ZDSSfMWNGcd369etXXP75558v1K9fPwsOb775ZmHQoEGFBg0aFF5//fXiMtdcc012jEceeaTw2muvFY466qjC9773vcK3335b5YNFks7DmDFjsq/28R74HNSMn4WqWi/7eA98Dvws5Pl94HdOYZ29B9Vm8HbqPvT4449n95DYaKON4tVXX41tt9023n///Wy61q+++qrimlcisqlir7vuupgxY0bWXSndgyLdKC854IADspvnpRv4rXiDvDSdbBrokroPpftW9OrVq3h7evnpvhh33nlnzJ07N/bZZ59sgPcOO+xQIYNaAACguijPdW65g0UKE+nmdOkifcVg8fLLL2c3lvviiy+ithEsAACo7de55b5B3r777pvdRK5IGrCdBpWkloCypqIFAABqrnLPCpUCxMEHH5y1UCxevDi7j8Qbb7wRX375ZTz//PMVU0sAAKBKK3eLxc477xxvv/12NhbhqKOOiq+//jqOOeaYmDRpUrRt27ZiagkAANScFoslS5bEoYceGnfccUcMGDCg4moFAADU3BaLBg0axGuvvVZxtQEAAGpHV6if/OQn8ec//7liagMAANSOwdtLly6Nu+66K5566qnYY489YoMNNiix/cYbb1yb9QMAAGpisJg8eXLsvvvu2fdpEPeK0tSzAABA7VOuYLFs2bK4/PLLo2PHjrHxxhtXXK0AAICaO8aiXr16ccghh8TcuXMrrkYAAEDtuI/F+++/XzG1AQAAakewuOqqq+Kiiy6Kxx57LD777LOYP39+iQUAAKh96hQKhUJ5dqhbt26pg7XTYdLjNA6jtkmBqmnTpjFv3rxo0qRJZVcHAADW+XVuuWeFGjNmTJ66AQAANVC5g8X+++9fMTUBAABqT7B45plnyty+33775akPAABQG4LFAQccsMq6Fcda1MYxFgAAUNuVe1aoOXPmlFhmzZoVo0aNij333DOeeOKJiqklAABQs1os0qjwlX3/+9+Phg0bxgUXXBATJkxYW3UDAABqaovF6rRo0SKmTp26tg4HAADU5BaL1157rcTjdP+KdKO8a665Jjp16rQ26wYAANTUYJHCQxqsvfJ99fbaa6+466671mbdAACAmhosPvjgg1XuxL3ZZptF48aN12a9AACAmhwstt5664qpCQAAUPMHb48ePTo6dOgQ8+fPX2XbvHnzYqeddopnn312bdcPAACoScFi8ODB0bdv32jSpEmpU9CeddZZceONN67t+gEAADUpWLz66qtx6KGHrnb7IYcc4h4WAABQS61xsJg5c2Y0aNBgtdvr168fn3/++dqqFwAAUBODRevWrWPy5Mll3t9iiy22WFv1AgAAamKw6NWrV1x22WWxcOHCVbZ9++23MWjQoDj88MPXdv0AAIBqoE5h5TvdldEVavfdd4969erFueeeGzvuuGO2/q233oohQ4bEsmXLYuLEidGiRYuobdJMWWkAe5odq7TB7QAAUNOvc9f4PhYpMIwdOzbOPvvs6N+/f/Gdt9NduHv27JmFi9oYKgAAgHLeIC/dHG/kyJExZ86cePfdd7Nwsf3228fGG2/svQQAgFqs3HfeTlKQ2HPPPdd+bQAAgJo9eBsAAGB1BAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNoTLL788ss46aSTokmTJtGsWbPo06dPfPXVV2Xus3DhwjjnnHOiefPmseGGG8axxx4bM2fOLN7+6quvRu/evaNNmzax3nrrRfv27ePmm29eB68GAABqlmoTLFKoeOONN+LJJ5+Mxx57LJ555pk488wzy9zn/PPPj3/+858xfPjw+O9//xvTp0+PY445pnj7hAkTYvPNN4+//vWv2bEHDBgQ/fv3j1tvvXUdvCIAAKg56hQKhUJUcW+++WZ06NAhxo8fH507d87WjRo1Knr16hWffPJJtGrVapV95s2bF5tttlncf//9cdxxx2Xr3nrrraxVYty4cbHXXnuV+lyphSM93+jRo9e4fvPnz4+mTZtmz5laVAAAoCYoz3VutWixSEEgdX8qChVJjx49om7duvHiiy+Wuk9qjViyZElWrki7du1iq622yo63OulN22STTcqsz6JFi7I3ecUFAABqs2oRLGbMmJF1WVpR/fr1swCQtq1un4YNG2aBZEUtWrRY7T5jx46NBx544Du7WF199dVZcita0hgNAACozSo1WPTr1y/q1KlT5pK6L60LkydPjqOOOioGDRoUhxxySJll0ziM1LJRtEybNm2d1BEAAKqq+pX55BdeeGGcdtppZZbZdttto2XLljFr1qwS65cuXZrNFJW2lSatX7x4ccydO7dEq0WaFWrlfaZMmRIHH3xw1lJx6aWXfme9GzVqlC0AAEAVCBZpcHVavku3bt2ygJDGTeyxxx7ZujS4evny5dG1a9dS90nlGjRoEE8//XQ2zWwyderU+Pjjj7PjFUmzQR100EFx6qmnxm9+85u19toAAKA2qRazQiU/+MEPstaGO+64IxuUffrpp2eDudOsT8mnn36atTrce++90aVLl2zd2WefHSNHjoyhQ4dmo9jPO++84rEURd2fUqjo2bNnXHfddcXPVa9evTUKPEXMCgUAQE1UnuvcSm2xKI/77rsvzj333Cw8pNmgUivELbfcUrw9hY3UIvHNN98Ur7vpppuKy6aZnFKAuO2224q3P/jgg/H5559n97FIS5Gtt946Pvzww3X46gAAoHqrNi0WVZkWCwAAaqIadx8LAACgahMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAAHITLAAAgNwECwAAIDfBAgAAyE2wAAAAchMsAACA2hMsvvzyyzjppJOiSZMm0axZs+jTp0989dVXZe6zcOHCOOecc6J58+ax4YYbxrHHHhszZ84stewXX3wRW265ZdSpUyfmzp1bQa8CAABqpmoTLFKoeOONN+LJJ5+Mxx57LJ555pk488wzy9zn/PPPj3/+858xfPjw+O9//xvTp0+PY445ptSyKajssssuFVR7AACo2eoUCoVCVHFvvvlmdOjQIcaPHx+dO3fO1o0aNSp69eoVn3zySbRq1WqVfebNmxebbbZZ3H///XHcccdl6956661o3759jBs3Lvbaa6/isrfffns88MADMXDgwDj44INjzpw5WavImpo/f340bdo0e87UogIAADVBea5zq0WLRQoC6UK/KFQkPXr0iLp168aLL75Y6j4TJkyIJUuWZOWKtGvXLrbaaqvseEWmTJkSV1xxRdx7773Z8QAAgPKrH9XAjBkzYvPNNy+xrn79+rHJJptk21a3T8OGDVdpeWjRokXxPosWLYrevXvHddddlwWO999/f43qk/ZLy4pJDgAAarNK/RN9v379ssHSZS2p+1JF6d+/f9Y16ic/+Um59rv66quzJqGipU2bNhVWRwAAqA4qtcXiwgsvjNNOO63MMttuu220bNkyZs2aVWL90qVLs5mi0rbSpPWLFy/OZnhasdUizQpVtM/o0aPj9ddfjwcffDB7XDTcZNNNN40BAwbE5ZdfvtpAcsEFF5RosRAuAACozSo1WKTB1Wn5Lt26dcsCQho3scceexSHguXLl0fXrl1L3SeVa9CgQTz99NPZNLPJ1KlT4+OPP86Ol/zjH/+Ib7/9tnifNDj8pz/9aTz77LPRtm3b1danUaNG2QIAAFSjMRapu9Khhx4affv2jTvuuCMblH3uuefGj3/84+IZoT799NNsRqc0CLtLly5ZF6U0hWxqWUhjMdIo9vPOOy8LFUUzQq0cHmbPnl38fOWZFQoAAGq7ahEskvvuuy8LEyk8pNmbUivELbfcUrw9hY3UIvHNN98Ur7vpppuKy6bB1j179ozbbrutkl4BAADUXNXiPhZVnftYAABQE9W4+1gAAABVm2ABAADkJlgAAAC5CRYAAEBuggUAAJCbYAEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAACQm2ABAADkJlgAAAC5CRYAAEBuggUAAJCbYAEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAACQm2ABAADkJlgAAAC5CRYAAEBuggUAAJCbYAEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAAAgWAAAAJVPiwUAAJCbYAEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAACQm2ABAADkVj//ISgUCtmbMH/+fG8GAAA1RtH1bdH1blkEi7VgwYIF2dc2bdqsjcMBAECVu95t2rRpmWXqFNYkflCm5cuXx/Tp02OjjTaKOnXqrPMUmQLNtGnTokmTJuv0ualczn3t5dzXXs597eXc117zK/laL0WFFCpatWoVdeuWPYpCi8VakN7kLbfcMipT+qAJFrWTc197Ofe1l3Nfezn3tVeTSrzW+66WiiIGbwMAALkJFgAAQG6CRTXXqFGjGDRoUPaV2sW5r72c+9rLua+9nPvaq1E1utYzeBsAAMhNiwUAAJCbYAEAAOQmWAAAALkJFtXAkCFDYptttonGjRtH165d46WXXiqz/PDhw6Ndu3ZZ+Y4dO8bIkSPXWV2pvHP/xz/+Mfbdd9/YeOONs6VHjx7f+Vmh5vzcFxk2bFh2o86jjz66wutI1Tj3c+fOjXPOOSe22GKLbHDnDjvs4Pd+LTn3gwcPjh133DHWW2+97AZq559/fixcuHCd1Ze145lnnokjjjgiuwFd+v398MMPf+c+//nPf2L33XfPfua32267GDp0aNU4HenO21Rdw4YNKzRs2LBw1113Fd54441C3759C82aNSvMnDmz1PLPP/98oV69eoVrr722MGXKlMKll15aaNCgQeH1119f53Vn3Z77E088sTBkyJDCpEmTCm+++WbhtNNOKzRt2rTwySefOBU1/NwX+eCDDwqtW7cu7LvvvoWjjjpqndWXyjv3ixYtKnTu3LnQq1evwnPPPZd9Bv7zn/8UXnnlFaelhp/7++67r9CoUaPsazrvjz/+eGGLLbYonH/++eu87uQzcuTIwoABAwoPPfRQIV2ajxgxoszy77//fmH99dcvXHDBBdm13u9///vs2m/UqFGVfioEiyquS5cuhXPOOaf48bJlywqtWrUqXH311aWWP/744wuHHXZYiXVdu3YtnHXWWRVeVyr33K9s6dKlhY022qhwzz33ODW14Nyn8929e/fCn/70p8Kpp54qWNSSc3/77bcXtt1228LixYvXYS2pCuc+lT3ooINKrEsXmnvvvbcTVI3FGgSLX/3qV4WddtqpxLoTTjih0LNnz0Jl0xWqClu8eHFMmDAh69JSpG7dutnjcePGlbpPWr9i+aRnz56rLU/NOfcr++abb2LJkiWxySabVGBNqSrn/oorrojNN988+vTp46TUonP/6KOPRrdu3bKuUC1atIidd945fvvb38ayZcvWYc2pjHPfvXv3bJ+i7lLvv/9+1gWuV69eTkgNN64KX+vVr+wKsHqzZ8/O/nNI/1msKD1+6623St1nxowZpZZP66nZ535l//d//5f111z5lw8179w/99xz8ec//zleeeWVdVRLqsq5TxeTo0ePjpNOOim7qHz33Xfj5z//efZHhXRDLWruuT/xxBOz/fbZZ5/U+ySWLl0aP/vZz+KSSy5ZR7WmssxYzbXe/Pnz49tvv83G3FQWLRZQA11zzTXZIN4RI0ZkgwCpuRYsWBAnn3xyNnh/0003rezqsI4tX748a6m68847Y4899ogTTjghBgwYEHfccYdzUcOlwbupdeq2226LiRMnxkMPPRT/+te/4sorr6zsqlGLabGowtJFQr169WLmzJkl1qfHLVu2LHWftL485ak5577I9ddfnwWLp556KnbZZZcKrimVfe7fe++9+PDDD7MZRVa82Ezq168fU6dOjbZt2zpRNfTnPs0E1aBBg2y/Iu3bt8/+opm61zRs2LDC603lnPvLLrss+6PCGWeckT1Os0B+/fXXceaZZ2bhMnWlomZquZprvSZNmlRqa0XiU1eFpf8Q0l+gnn766RIXDOlx6lNbmrR+xfLJk08+udry1Jxzn1x77bXZX6tGjRoVnTt3Xke1pTLPfZpa+vXXX8+6QRUtRx55ZBx44IHZ92kKSmruz/3ee++ddX8qCpPJ22+/nQUOoaJmn/s0jm7l8FAUMP/fGGBqqm5V+VqvskeP893Tz6Xp5IYOHZpNKXbmmWdm08/NmDEj237yyScX+vXrV2K62fr16xeuv/76bMrRQYMGmW62lpz7a665Jpuq8MEHHyx89tlnxcuCBQsq8VWwLs79yswKVXvO/ccff5zN/nbuuecWpk6dWnjssccKm2++eeGqq66qxFfBujj36f/3dO7/9re/ZdOPPvHEE4W2bdtms0NSvSxYsCCbKj4t6dL8xhtvzL7/6KOPsu3pvKfzv/J0sxdffHF2rZemmjfdLGsszU+81VZbZReNaTq6F154oXjb/vvvn11ErOjvf/97YYcddsjKp+nI/vWvf3m3a8G533rrrbNfSCsv6T8fav7P/YoEi9p17seOHZtNK54uStPUs7/5zW+y6Yep2ed+yZIlhV//+tdZmGjcuHGhTZs2hZ///OeFOXPmVFLt+V+NGTOm1P+/i853+prO/8r7dOrUKfuspJ/7u+++u1AV1En/VHarCQAAUL0ZYwEAAOQmWAAAALkJFgAAQG6CBQAAkJtgAQAA5CZYAAAAuQkWAABAboIFAACQm2ABQIXaZpttYvDgwVX6Xf7zn/8chxxySLn2mT17dmy++ebxySefVFi9AKoTwQKAUh1xxBFx6KGHlrrt2WefjTp16sRrr71W7ncv7ffwww9XmXd94cKFcdlll8WgQYOyx+edd160b9++1LIff/xx1KtXLx599NHYdNNN45RTTineD6C2EywAKFWfPn3iySefLPUv8nfffXd07tw5dtlll2r/7j344IPRpEmT2HvvvYtf91tvvRVjx45dpezQoUOzVopevXplj08//fS477774ssvv1zn9QaoagQLAEp1+OGHx2abbZZdTK/oq6++iuHDh2cX4Mk//vGP2GmnnaJRo0ZZt6cbbrhhte9o2p788Ic/zFouih6/9957cdRRR0WLFi1iww03jD333DOeeuqpEvt+9tlncdhhh8V6660X3/ve9+L+++9fpZvV3Llz44wzzsjqncLCQQcdFK+++mqZZ3jYsGFZ60yRTp06xe677x533XVXiXKFQiF7L0499dSoX79+ti697latWsWIESN8ioBaT7AAoFTp4jl19UkX0+miukgKFcuWLYvevXvHhAkT4vjjj48f//jH8frrr8evf/3rrFvRymGkyPjx44tbPFJQKHqcwkpqBXj66adj0qRJWResdLGfuh4VSXWZPn16/Oc//8nCzJ133hmzZs0qcfwf/ehH2bp///vfWd1SQDj44IPLbFF47rnnstaXFaXQ9Pe//z2+/vrr4nXpeT/44IP46U9/WqJsly5dsq5hALVeAQBW480330yJojBmzJjidfvuu2/hJz/5Sfb9iSeeWPj+979fYp+LL7640KFDh+LHW2+9deGmm24qfpyON2LEiO98z3faaafC73//+xL1GD9+fPH2d955J1tXdOxnn3220KRJk8LChQtLHKdt27aFP/zhD6U+x5w5c7JjPPPMM6usb9y4ceHuu+8uXnfyyScX9tlnn1WOcf755xcOOOCA73w9ADWdFgsAVqtdu3bRvXv34m5B7777bvbX+aJuUG+++Wbx2IQi6fE777yTtWqsqdRicdFFF2WDpps1a5Z1h0rHLmqxmDp1ataCklogimy33Xax8cYbFz9OXZ7ScZo3b57tX7SkVobU1ao03377bfa1cePGJdanOhxzzDHFr3v+/PlZK0nR615R6pr1zTffrPFrBaip/l8nUQBYjXQxnWZKGjJkSNaFqW3btrH//vuv1fcrhYo0UPz666/PAkO6WD/uuONi8eLFa3yMFCq22GKLrMvSylJQKE0KIWmsx5w5c0p93akbVQpTY8aMyWaDSl2tVpa6WaUxHQC1nRYLAMqUxlDUrVs3Gyx97733ZmMM0sV4kloYnn/++RLl0+MddtghuxAvTYMGDVZpzUj7nHbaadmg7o4dO0bLli3jww8/LN6+4447xtKlS7PxF0XSBf+KgSC1ZsyYMSNr2UjhZMUlTQ1bmoYNG0aHDh1iypQpq2w78MADs0HiKUylJY0j2WCDDVYpN3ny5Nhtt93KeAcBagfBAoAype5EJ5xwQvTv3z8bcJ0CQJELL7wwG3B95ZVXxttvvx333HNP3HrrrVkLxOqkmZzSPikEFAWD7bffPh566KF45ZVXsi5NJ554YixfvrxEl6wePXrEmWeeGS+99FIWMNL3qWWjKOSk7d26dYujjz46nnjiiSyYpCljBwwYEC+//PJq69OzZ89sAPfK0nFTiLr99ttj3LhxpXaDSl2g0iDx8t5cD6AmEiwA+E7pojqFgHQRnqZXXbGVIM2elKZs3XnnnWPgwIFxxRVXlAgfK0vT0aZuT23atCn+S/+NN96YjZdI4znSbFDpeVYcT5Gk1pI0He1+++2XtWz07ds3Ntpoo+LxESkIjBw5Mtue7i+RWk1SK8NHH32U7VfWa0v7zZs3b5Vt6XWk9Wla2a5du66y/ZFHHomtttoq9t13X58ioNark0Zw1/p3AYBqJ924L4WTdL+LNBYijzR2IgWZ1CpTHnvttVf84he/yFpYAGo7LRYAVAujR4+ORx99NJvlKXVxSq0RqVtVaqHI67rrrsu6fJXH7Nmzs5mj0v08AAgtFgBUD48//ng2puP999/PukClblPprttbb711ZVcNAMECAABYG3SFAgAAchMsAACA3AQLAAAgN8ECAADITbAAAAByEywAAIDcBAsAACA3wQIAAMhNsAAAACKv/w+nxdIioQ6CcgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot the IV curve: current vs voltage\n", + "iv_df.plot(x=\"voltage (V)\", y=\"current (A)\", figsize=(8, 5), marker=\".\", color=\"k\", legend=False)\n", + "plt.xlabel(\"Voltage (V)\")\n", + "plt.ylabel(\"Current (A)\")\n", + "plt.title(\"IV Sweep\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 3d40e7eda754fde254c065d01849d706bc1e7cc1 Mon Sep 17 00:00:00 2001 From: Jesalina Date: Wed, 13 May 2026 18:19:25 -0400 Subject: [PATCH 2/2] Bug fix: remove popup from amr gui --- Measurements/AMR/amr_GUI.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Measurements/AMR/amr_GUI.py b/Measurements/AMR/amr_GUI.py index bd717b7..cdac4fb 100644 --- a/Measurements/AMR/amr_GUI.py +++ b/Measurements/AMR/amr_GUI.py @@ -290,7 +290,8 @@ def run_measurement(self): frequency=frequency, measure_time=measure_time, sensitivity=sensitivity, - save_dir=save_dir + save_dir=save_dir, + live_plot=False, ) self.is_measuring = True