Metadata-Version: 2.5
Name: impulso_mna
Version: 3.0.0
Summary: A package for the simulation of analog electronic circuits using Modified Nodal Analysis
Project-URL: Homepage, https://github.com/kvdijken/impulso-mna
Author-email: kvdijken <sla_nippers_0x@icloud.com>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.14
Requires-Dist: numpy
Provides-Extra: examples
Requires-Dist: labellines; extra == 'examples'
Requires-Dist: matplotlib; extra == 'examples'
Requires-Dist: quantiphy; extra == 'examples'
Provides-Extra: test
Requires-Dist: pytest; extra == 'test'
Description-Content-Type: text/markdown

# impulso-mna

![Status](https://img.shields.io/badge/status-stable-brightgreen)
![Focus](https://img.shields.io/badge/focus-minimal%20core-blue)
![Architecture](https://img.shields.io/badge/architecture-simple-success)

**impulso-mna** is a Python package for circuit simulation based on **Modified Nodal Analysis (MNA)**. It provides a flexible and extensible framework for DC, AC, and transient analysis of electrical circuits, with a strong focus on clarity, composability, and performance.

The package is now in version 3.0.0.

The package is installed as `impulso-mna` but imported as:

```python
import impulso
```

---

## ✨ Features

* Modified Nodal Analysis (MNA) core
* Unified framework for:
  * DC operating point analysis
  * AC small-signal analysis
  * Transient simulation
* Support for:
  * Resistors, capacitors, inductors
  * Independent voltage and current sources
  * Nonlinear components (e.g. diodes, BJTs)
* Companion models for transient analysis
* Steady-state detection for transient simulations
* Several steady-state detectors for different types of signals
* Extensible component API for custom devices
* Designed for readability and experimentation

---

## 💡 Motivation

**impulso-mna** was created to provide a fully Python-native alternative to existing (semi-)advanced circuit simulation tools.

Many available Python-based circuit simulators rely on external backends (such as SPICE engines). While powerful, these approaches often introduce:

* Additional installation complexity
* Platform-specific issues
* Indirect workflows (Python → external simulator → results back to Python)

This can make them harder to use, especially in iterative or programmatic contexts.

---

### 🐍 A pure Python approach

**impulso-mna** is implemented entirely in Python and depends only on `numpy` for numerical computations.

This design choice provides:

* Simple installation and portability
* Full transparency of the simulation process
* Direct access to all internal data structures

---

### 🔄 Tight integration with Python workflows

A key goal of this package is to make circuit simulation **a first-class part of Python code**, rather than an external tool.

Simulation results are directly available as Python objects, which makes it straightforward to:

* Integrate simulations into optimization loops
* Perform parameter sweeps programmatically
* Couple circuit models with other numerical or scientific workflows
* Build custom analysis pipelines

These workflows are often cumbersome or inefficient when using traditional simulator integrations.

---

### 🎯 Positioning

* Use **`impulso-mna`** for a minimal, stable foundation
* Use **`impulsox-mna`** when you need more control, flexibility, or want to experiment with advanced techniques

Together, they aim to provide a clean, Python-first ecosystem for circuit simulation without external dependencies.

---

## 📦 Installation

```bash
pip install impulso-mna
```

For development (editable install):

```bash
git clone https://github.com/<your-username>/impulso-mna.git
cd impulso-mna
pip install -e .
```

---

## 🚀 Quick Example

```python
import impulso as imp

# Create a circuit
ckt = imp.Circuit()

# Add components
ckt.add(imp.Resistor("R1", n1=1, n2=0, value=1e3))
ckt.add(imp.VoltageSource("V1", n_plus=1, n_minus=0, value=5.0))

# Solve DC operating point
solution = ckt.solve_dc()

print(solution.node_voltages)
```

---

## 📊 Example Simulations

The repository includes several example simulations demonstrating the capabilities of the library.

### 1. Diode I–V Curve

Simulates the nonlinear current–voltage characteristic of a diode using DC sweep.

* Demonstrates:
  * Nonlinear solving
  * Operating point convergence
* Output: exponential I–V curve

![Alt text](images/diode_IV-curve.png)

---

### 2. NPN Transistor Output Characteristics

Generates a family of curves (Ic vs Vce) for different base currents.

* Demonstrates:
  * BJT modeling (e.g. Ebers–Moll)
  * Parameter sweeps
* Output: characteristic transistor curves including saturation behavior and output resistance (Early voltage).

![Alt text](images/npn-curves.png)

---

### 3. Pulse Counting FM Detector

Implements a simple frequency-modulation detector based on pulse counting.

* Demonstrates:
  * Transient simulation
  * Time-domain signal processing
* Output: recovered modulation signal from pulse frequency

![Alt text](images/pulse-counter.png)

---

### 4. Dirac Pulse Driving an RC Network

Applies a Dirac-like pulse to an RC circuit and observes the response.

* Demonstrates:
  * Impulse-like excitation
  * Transient response of linear systems
* Output: exponential decay consistent with RC time constant

![Alt text](images/dirac-pulse.png)

---

### 5. Relaxation oscillator

This is a relaxation oscillator as described in https://youtu.be/2a1I1X3RV0g. This is a hard circuit to simulate and takes more than than the other typical example scripts.

![Alt text](images/w2aew_105.png)

---

## ⏱️ Steady-State Detection

Transient simulations do not always have a predictable settling time. In particular, this can be a problem when running parameter sweeps, where changing a circuit parameter can significantly change the time required for the circuit to reach its final behaviour.

**impulso-mna** provides steady-state detectors that can automatically terminate a transient simulation when the circuit's dynamic state has reached the requested condition.

The detectors automatically monitor **all capacitor voltages and inductor currents**. This set of signals is fixed and cannot be changed by the user. The detectors therefore evaluate the complete dynamic state of the circuit rather than requiring the user to select particular signals to monitor.

This makes it possible to run simulations until they have actually settled, rather than selecting an unnecessarily long fixed simulation time.

A typical use case is a parameter sweep in which the settling time varies:

```text
parameter sweep
      │
      ▼
transient simulation
      │
      ├── not settled → continue
      │
      └── settled → stop
```

This is particularly useful for circuits containing oscillators, resonators, filters, and other systems for which the required simulation time is difficult to predict analytically.

### Detector types

Several detectors are available, each intended for a different type of steady-state behaviour:

| Detector | Intended signal behaviour | Detection principle |
|---|---|---|
| **DC** | Constant signal | Checks variation over a recent time window |
| **Mean** | Slowly varying or noisy signal | Checks the change in the window mean |
| **MeanEnvelope** | Periodic signal | Checks both the mean and signal envelope |
| **Periodic** | Periodic signal | Detects repetition using autocorrelation |
| **SubSamplingPeriodic** | Periodic signal | Periodic detection with sub-sample period estimation |

All detectors operate on the same automatically determined set of signals: **every capacitor voltage and every inductor current present in the circuit**.

### DC detector

The DC detector is intended for circuits whose dynamic state should settle to constant values.

It examines a recent window of capacitor voltages and inductor currents and determines whether their variation is below the specified tolerance.

This is useful for circuits such as:

* RC networks settling to a final voltage
* Detector or demodulator outputs settling to a DC level
* Bias voltages reaching their operating values

### Mean detector

The Mean detector is useful when the instantaneous dynamic signals may contain some variation or noise, but their average values should become stable.

Instead of requiring every sample to be nearly identical, the detector compares the mean values of successive portions of the observation window.

This makes it less sensitive to instantaneous fluctuations than a simple DC detector.

### MeanEnvelope detector

For periodic signals, the average value alone is not sufficient to establish that the circuit has reached a steady state. The amplitude may still be changing even though its mean has already stabilized.

The MeanEnvelope detector therefore requires both:

* The mean value of the monitored dynamic signals to have stabilized
* Their signal envelope to have stabilized

This is useful for oscillators and other circuits where the desired steady state is a periodic waveform with a stable amplitude and DC offset.

### Periodic detector

The Periodic detector is intended for circuits whose steady state is periodic.

Rather than comparing individual samples at fixed time offsets, it determines whether the monitored dynamic signals repeat with a stable period. The detector uses autocorrelation to identify the periodicity.

The signals are first demeaned and normalized so that the correlation primarily describes waveform repetition rather than absolute signal level.

The observation window should contain **multiple periods** of the waveform. A window that is too short can prevent reliable identification of the fundamental period.

### SubSamplingPeriodic detector

The SubSamplingPeriodic detector extends periodic detection by estimating the period with **sub-sample resolution**.

The correlation peak does not necessarily occur exactly at an integer number of simulation time steps. The detector therefore uses the neighbouring correlation samples to interpolate the position of the correlation peak.

This allows the estimated period, and consequently the detected frequency, to have a resolution finer than the transient simulation time step.

### Tolerances

Steady-state detection uses absolute and relative tolerances.

The **absolute tolerance** is useful for controlling the maximum permitted change in the physical units of a signal. It is especially useful for small signals or when the expected signal magnitude is close to zero.

The **relative tolerance** makes the criterion scale with the magnitude of the signal and is useful when the monitored dynamic quantities have significantly different magnitudes.

For noisy signals, an absolute tolerance can often be more appropriate than a strict relative-error criterion because small random fluctuations can otherwise prevent the detector from declaring steady state.

### Observation window

All detectors operate on a recent window of transient results rather than requiring the complete transient history.

The choice of window size is important:

* A window that is too short may contain insufficient information to establish steady state.
* A longer window generally provides a more reliable measurement but requires the circuit to remain simulated for longer before detection is possible.
* For periodic detection, the window should contain several periods of the expected waveform.

Consequently, the window size is part of the detector configuration rather than simply being a performance parameter.

### Using a detector to terminate a transient simulation

Transient simulation can be terminated using a steady-state detector that is evaluated after each transient step.

The detector automatically evaluates **all capacitor voltages and inductor currents** in the circuit. No selection of monitored signals is required or possible.

The transient solver continues until the detector reports that the requested steady state has been reached, or until the configured maximum simulation time is exceeded.

This allows the transient simulation API to support both fixed-time and condition-based termination.

### Why this is useful

Steady-state detection is particularly valuable for **parameter sweeps where settling time varies**.

For example, when sweeping the frequency of an FM carrier through a detector circuit, the settling time may depend on the circuit response at each frequency. A fixed simulation time must either be chosen conservatively or risk terminating before the circuit has settled.

A steady-state detector instead allows each simulation to run only as long as necessary, while checking the complete dynamic state of the circuit.
---

## 🧠 Design Philosophy

* **Minimal but powerful**: Focus on essential abstractions
* **Explicit stamping**: Components directly contribute to MNA matrices
* **Unified API**: Same interface across DC / AC / transient
* **Extensibility first**: Easy to implement custom components
* **Adaptive transient termination**: Simulations can stop when their signals have actually reached steady state

---

## 🧩 Component Model

Each component contributes to the system via:

* Admittance / conductance
* Current injections
* Additional equations (for voltage sources, inductors, etc.)

Nonlinear components are handled through iterative solving (e.g. Newton-Raphson), with operating point linearization for AC analysis.

---

## 🔧 Development Workflow

Recommended setup:

```bash
pip install -e .[dev]
```

Typical structure:

```text
.
├── impulso/
├── examples/
├── tests/
└── pyproject.toml
```

Run examples:

```bash
python examples/diode_curve.py
```

---

## 📈 Performance Notes

* Uses NumPy for linear algebra
* Designed to be efficient but still readable
* Profiling suggests convergence checks can be a bottleneck — optimizations welcome
* Steady-state detection operates on the recent observation window rather than requiring the complete transient history

---

## 🤝 Contributing

Contributions are welcome. Areas of interest include:

* Performance improvements
* Additional device models
* Better convergence strategies
* Documentation and examples

---

## 📄 License

MIT License (or your chosen license)

---

## 🎯 Scope & Philosophy

**impulso-mna** is intentionally designed as a **minimal, foundational implementation of Modified Nodal Analysis (MNA)**.

Its purpose is to provide:

* A clear and correct reference implementation of MNA
* A lightweight engine for DC, AC, and transient simulation
* A clean and predictable API for circuit construction and analysis
* Reliable condition-based termination of transient simulations

The package prioritizes **clarity, stability, and simplicity** over feature breadth. It is deliberately kept:

* Easy to read and reason about
* Easy to extend for custom components and experiments
* Free from heavy abstractions, dependency injection, or complex infrastructure

This makes `impulso-mna` suitable both as a practical simulation tool and as a foundation for understanding and developing circuit solvers.

---

## 🚧 Advanced Features

Advanced functionality is provided in a separate package:

**impulsox-mna** *(planned)*

This package targets more demanding simulation scenarios and may include:

* More sophisticated semiconductor device models (e.g. advanced BJT/MOSFET models)
* Enhanced nonlinear convergence strategies
* Sparse and high-performance numerical backends
* RF and high-frequency analysis tools
* Noise analysis
* Extended simulation workflows and tooling

---

## 🔗 Relationship Between Packages

The two packages are **intentionally independent and self-contained**:

```text
impulso-mna   → minimal, stable, and dependency-light MNA implementation
impulsox-mna  → advanced, feature-rich, fully independent simulator
```

Key design principles:

* **No dependency relationship**: `impulsox-mna` does not depend on `impulso-mna`
* **Parallel design**: both packages follow a similar structure and philosophy
* **Full autonomy**: each package is complete and usable on its own

This separation ensures that:

* `impulso-mna` remains compact, transparent, and stable
* `impulsox-mna` can evolve freely without introducing complexity into the core
* The base package avoids architectural overhead such as dependency injection or layered abstractions

---

## 🏁 Roadmap

**impulso-mna** is intended to remain a **stable and minimal core package**. Its functionality is largely complete and will not significantly expand over time.

Future development will focus on:

* Bug fixes and correctness improvements
* Code quality, readability, and maintainability
* Minor usability enhancements where appropriate

No major new features or architectural changes are planned for this package.

More advanced functionality and experimental features will be developed separately in **`impulsox-mna`**.

---

## 📦 Requirements

### ▶️ Core (runtime)

The core of **impulso-mna** is intentionally lightweight and depends only on a small set of packages:

* `numpy` — numerical computations and matrix operations

These are the only dependencies required to **use the simulator itself**.

---

### 📊 Optional (examples & visualization)

The following packages are used for running examples and visualizing results:

* `matplotlib` — plotting simulation results
* `quantiphy` — formatted physical quantities

`matplotlib` brings in several supporting dependencies (e.g. `cycler`, `kiwisolver`, `pillow`, etc.).

---

### 🧪 Development & testing

For development, testing, and contributing:

* `pytest` — test framework
* `pluggy`, `iniconfig`, `Pygments` — pytest dependencies

---

### 🛠 Build system

* `setuptools`
* `wheel`

---

### 🔗 Development note on impulso-mna

During development, you may encounter setups that include:

```text
-e git+https://github.com/kvdijken/impulso-mna.git@<commit>#egg=impulso
```

This is **only for development and comparison purposes**.

* **impulsox-mna does not depend on impulso-mna**
* Both packages are fully independent implementations

---

## ⚙️ Installation

### Minimal installation

```bash
pip install impulso-mna
```

---

### Development environment

To reproduce the full development setup:

```bash
pip install -r requirements.txt
```

---

## 📝 Notes

* Runtime dependencies are intentionally minimal
* Additional packages are only required for examples, testing, and development
* Future versions may formalize this split via optional dependency groups (e.g. `extras_require`)
