Skip to main content

A Python library for modeling, analyzing, and simulating feedback control loops.

Project description

loopkit

A Python library for modeling, analyzing, and simulating feedback control loops, with a focus on scientific and engineering applications such as laser locking, electronics, and precision instrumentation.


🔧 What is loopkit?

loopkit provides an object-oriented framework for building and analyzing control loops as directed graphs of signal-processing components. It supports:

  • Modular design of control systems using Python classes and NumPy/Scipy tools
  • Construction of linear time-invariant (LTI) models via symbolic transfer functions or tabulated data
  • Frequency-domain and time-domain simulation of system behavior
  • Visualization and analysis of loop stability, gain, noise propagation, and performance
  • Extensibility through subclassing and dynamic graph generation

The library is designed with scientific control systems in mind—especially applications in optics, interferometry, and laser metrology.


🧩 Key Features

  • Component-based modeling: Each system block is a Component with defined transfer functions, inputs, and outputs.
  • Flexible interconnection: Loops are defined by connecting components into directed graphs, not just serial chains.
  • Simulation support: Built-in methods to simulate step responses, noise propagation, and open/closed-loop behavior.
  • Plotting utilities: Visualize Bode plots, noise budgets, signal flow graphs, and more.
  • Extensible: Easily define custom blocks, auto-generate loop structures, and integrate with hardware configurations.

📦 Installation

pip install loopkit

For block diagram generation (loop.block_diagram()), install the optional dependencies:

pip install loopkit[diagram]

Note: pytikz is required for block diagrams but is not on PyPI. Install it from the allefeld fork:

pip install git+https://github.com/allefeld/pytikz.git

🚀 Quick Start

Example

import numpy as np
import matplotlib.pyplot as plt
from loopkit.component import Component
from loopkit.components import PIControllerComponent
from loopkit.loop import LOOP
import loopkit.loopmath as lm

# Define loop parameters
sps = 80e6  # Loop update frequency in Hz
frfr = np.logspace(np.log10(1e0), np.log10(40e6), int(1e5))[:-1]  # Frequency array (Hz)

# Define Plant using Laplace-domain string (auto-discretized)
w_n = 2 * np.pi * 1e6 # 10 kHz resonance
zeta = 2.0 # damping ratio
plant = Component("Plant", sps=sps, tf=f"{w_n**2} / (s**2 + {2*zeta*w_n}*s + {w_n**2})", domain='s')

# Define Sensor using z-domain string (explicit difference equation)
sensor = Component("Sensor", sps=sps, tf="(0.391 + 0.391*z**-1) / (1 - 0.218*z**-1)", domain='z')

# Compute the P-servo log2 gain from a dB value
p_log2_gain = lm.db_to_log2_gain(15)

# Compute the integrator log2 gains for a certain cross-over frequency with the P-servo
i_log2_gain = lm.gain_for_crossover_frequency(p_log2_gain, sps, 1e5, kind='I')

# Define PI controller component with those gains
controller = PIControllerComponent("Controller", sps=sps, Kp=p_log2_gain, Ki=i_log2_gain)

# Build the loop
loop = LOOP(sps, [plant, sensor, controller], name="My Loop")

ugf, margin = lm.get_margin(loop.Gf(f=frfr), frfr, deg=True, unwrap_phase=True, interpolate=True) # compute UGF and phase margin

print(f"Unity gain frequency = {ugf:.4e} Hz; Phase margin = {margin:.4f} degrees")

# Visualize block diagram
loop.block_diagram(dpi=150)

# Bode plot of open-loop gain
ax = loop.bode_plot(frfr)
ax[0].axvline(x=ugf, ls='--', c='gray')
ax[1].axvline(x=ugf, ls='--', c='gray')
plt.show()

# Nyquist plot of open-loop gain
ax = loop.nyquist_plot(frfr, which='G', logy=True, logx=True, critical_point=True)
plt.show()

🧪 Specialized Loop Implementations

The loopkit.loops subpackage provides pre-built loop models:

  • PLL: Digital phase-locked loop model.
  • MokuLaserLock: Laser frequency lock model for Moku hardware (heterodyne phase-locking).
  • NPROLaserLock: Composite model for NPRO laser frequency stabilization using PZT and temperature control loops with digital PLL (phasemeter) readout.
  • LaserLockPZT, LaserLockTemp: Building blocks for laser lock subsystems.
from loopkit.loops import PLL, MokuLaserLock, NPROLaserLock

📚 Documentation

In-depth API documentation, tutorials, and example notebooks coming soon.


💡 Design Philosophy

  • Favor explicit, graph-based design over implicit signal paths
  • Maintain clarity between loop structure and numerical simulation
  • Support rapid prototyping of complex control systems
  • Blend symbolic (transfer function) and numeric (data-driven) components

👥 Contributing

Contributions are welcome! We are especially interested in:

  • New component definitions (hardware models, filters, sensors)
  • Visualization tools for loop inspection
  • Test coverage and validation scripts
  • Real-world loop configurations from physics labs

📜 License

BSD 3-Clause License.


🛰 Authors & Acknowledgments

Developed by Miguel Dovale, based on an initial implementation by Kohei Yamamoto.


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

loopkit-1.0.1.tar.gz (137.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

loopkit-1.0.1-py3-none-any.whl (111.7 kB view details)

Uploaded Python 3

File details

Details for the file loopkit-1.0.1.tar.gz.

File metadata

  • Download URL: loopkit-1.0.1.tar.gz
  • Upload date:
  • Size: 137.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for loopkit-1.0.1.tar.gz
Algorithm Hash digest
SHA256 abcf0039a2adf0d6116ce72f679a66b6d0c6fb47f70811360781e7efd4440f2d
MD5 78dbd380526278290e064f29c70f5e6d
BLAKE2b-256 74143280fb37a55d27d7d2e676eb3ab4349e3e8650b2198b07b88af3bf4f0f2e

See more details on using hashes here.

File details

Details for the file loopkit-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: loopkit-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 111.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for loopkit-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 60657619692727d22efcb5ba4566cc82b126317bb011985eb9612099fbc228e1
MD5 2a9a57de6bf3dfad0e192e81406ad661
BLAKE2b-256 2e6eba08ed20fdd1c23abeef6e29092e0acb9162d5570a75146103c88cd8a19a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page