No project description provided
Project description
# keysight-b2901
A Python library for running electrochemical experiments from the Keysight B2901A / B2901BL Source-Measure Unit (SMU). Provides a clean interface for common galvanostatic and potentiostatic techniques, with built-in CSV logging, live plotting, and hardware safety limits.
Designed for 4-wire (Kelvin) sensing with the counter/sense terminals connected to a reference electrode, as is typical in 3-electrode electrochemical cells.
## Installation
pip install keysight-b2901
## Supported methods
- constant\_current — galvanostatic hold for a fixed duration
- constant\_voltage — potentiostatic hold for a fixed duration
- constant\_current\_until\_cutoff — galvanostatic hold until a voltage limit is reached
- constant\_voltage\_until\_cutoff — potentiostatic hold until a current limit is reached
- charge\_discharge\_cycle — automated galvanostatic charge/discharge cycling (GCD)
- cyclic\_voltammetry — software-stepped CV sweep at a specified scan rate
All methods accept an optional LivePlotter for real-time V and I strip-charts, and write to a thread-safe CSV via DataLogger.
---
## Usage
### Finding your instrument address
import pyvisa
rm = pyvisa.ResourceManager()
print(rm.list\_resources())
\# e.g. 'USB0::0x2A8D::0x9101::MY63320360::INSTR'
---
### Constant current hold
from keysight\_echem import KeysightB2901, DataLogger, LivePlotter, SafetyLimits
ADDR = 'USB0::0x2A8D::0x9101::MY63320360::INSTR'
safety = SafetyLimits(max\_voltage=4.5, min\_voltage=-0.5,
  max\_current=1.0, min\_current=-1.0)
plotter = LivePlotter(title='CC Hold', current\_unit='mA')
with KeysightB2901(ADDR, safety=safety) as smu:
  with DataLogger('cc\_hold.csv') as log:
  smu.constant\_current(
  current=0.5, # A
  duration=120, # s
  sample\_rate=10, # Hz
  voltage\_compliance=5.0,
  logger=log,
  plotter=plotter,
  )
plotter.save('cc\_hold.png')
plotter.keep\_open()
---
### GITT (Galvanostatic Intermittent Titration Technique)
GITT consists of a series of current pulses each followed by a relaxation period. It can be built directly from constant\_current and constant\_current\_until\_cutoff in a loop:
from keysight\_echem import KeysightB2901, DataLogger, LivePlotter
import time
ADDR = 'USB0::0x2A8D::0x9101::MY63320360::INSTR'
PULSES = 20
plotter = LivePlotter(title='GITT', current\_unit='mA')
with KeysightB2901(ADDR) as smu:
  with DataLogger('gitt.csv') as log:
  for i in range(PULSES):
  # --- current pulse ---
  smu.constant\_current(
  current=0.1, # A
  duration=60, # s per pulse
  sample\_rate=10,
  voltage\_compliance=5.0,
  logger=log,
  plotter=plotter,
  status=f'pulse\_{i+1}',
  )
  # --- relaxation (output already off; just wait and measure at OCV) ---
  smu.constant\_current(
  current=0.0, # zero current = open circuit measurement
  duration=300, # s relaxation
  sample\_rate=2,
  voltage\_compliance=5.0,
  logger=log,
  plotter=plotter,
  status=f'relax\_{i+1}',
  )
plotter.save('gitt.png')
plotter.keep\_open()
Each pulse/relax pair is labelled in the CSV and plotted in a distinct colour, so the titration steps are immediately visible.
---
### Conductance-based MPPT (Maximum Power Point Tracking)
The incremental conductance algorithm tracks the maximum power point of a source (e.g. a photoelectrochemical cell) by comparing the incremental conductance dI/dV to the instantaneous conductance I/V and stepping the current accordingly:
- If dI/dV + I/V > 0 → increase current (moving toward MPP)
- If dI/dV + I/V < 0 → decrease current (overshot MPP)
- If dI/dV + I/V ≈ 0 → at MPP, hold
from keysight\_echem import KeysightB2901, DataLogger, LivePlotter
import time
ADDR = 'USB0::0x2A8D::0x9101::MY63320360::INSTR'
I\_MIN = 0.0 # A — lower current bound
I\_MAX = 0.5 # A — upper current bound
I\_STEP = 0.005 # A — perturbation step size
TOLERANCE = 1e-4 # conductance tolerance for "at MPP"
INTERVAL = 0.5 # s between MPPT updates
DURATION = 600 # s total run time
plotter = LivePlotter(title='MPPT', current\_unit='mA')
with KeysightB2901(ADDR) as smu:
  with DataLogger('mppt.csv') as log:
  current\_setpoint = 0.05 # A — initial guess
  v\_prev, i\_prev = None, None
  t\_end = time.time() + DURATION
  while time.time() < t\_end:
  # Apply current and take a single timed sample
  smu.constant\_current(
  current=current\_setpoint,
  duration=INTERVAL,
  sample\_rate=1,
  voltage\_compliance=5.0,
  logger=log,
  plotter=plotter,
  status='mppt',
  )
  # Read the last logged values back from the plotter's buffer
  seg = plotter.\_segments.get('mppt')
  if seg is None or len(seg\['v']) < 2:
  continue
  v\_now = seg\['v']\[-1]
  i\_now = seg\['i']\[-1] / 1e3 # plotter stores in mA; convert back to A
  if v\_prev is not None:
  dV = v\_now - v\_prev
  dI = i\_now - i\_prev
  if abs(dV) > 1e-6: # avoid division by zero
  inc\_conductance = dI / dV
  inst\_conductance = i\_now / v\_now if abs(v\_now) > 1e-6 else 0.0
  error = inc\_conductance + inst\_conductance
  if error > TOLERANCE:
  current\_setpoint = min(current\_setpoint + I\_STEP, I\_MAX)
  elif error < -TOLERANCE:
  current\_setpoint = max(current\_setpoint - I\_STEP, I\_MIN)
  # else: within tolerance, hold current
  v\_prev, i\_prev = v\_now, i\_now
plotter.save('mppt.png')
plotter.keep\_open()
**Note:** For a real MPPT deployment you would tune
I\_STEP,INTERVAL, andTOLERANCEto match the time constants of your cell. Smaller steps give finer tracking at the cost of convergence speed.
---
## Safety limits
All methods respect a SafetyLimits object that acts as a software-level emergency stop independent of the instrument's own compliance settings:
from keysight\_echem import SafetyLimits
safety = SafetyLimits(
  max\_voltage = 4.5, # V
  min\_voltage = -0.5, # V
  max\_current = 1.0, # A
  min\_current = -1.0, # A
)
smu = KeysightB2901(ADDR, safety=safety)
If either boundary is exceeded during any measurement the output is switched off immediately and the loop exits.
---
## License
MIT. Not affiliated with or endorsed by Keysight Technologies.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keysight_echem-0.1.1.tar.gz.
File metadata
- Download URL: keysight_echem-0.1.1.tar.gz
- Upload date:
- Size: 13.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f2eb6bef7cfa7165e0a67e702d7cbb9f694844c3ff9b50d3f4b81333a80b9a05
|
|
| MD5 |
7642834e365d08753a7664465481e417
|
|
| BLAKE2b-256 |
f4c43a898b353e371853f4cc3ebe5dce06a1c5af6bf740cfd42684790aa19599
|
File details
Details for the file keysight_echem-0.1.1-py2.py3-none-any.whl.
File metadata
- Download URL: keysight_echem-0.1.1-py2.py3-none-any.whl
- Upload date:
- Size: 14.0 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f553368d0d4ed5ff238894a51bccc8f789394d8812f251a5b1635291c10dbd6
|
|
| MD5 |
4933a9389bd2344ceb8578362560bd4d
|
|
| BLAKE2b-256 |
4441e0b4998d20611e4ba59043ac925fe37e36ada6f27f4846fc2327ad1f9f22
|