API Reference
Developer reference for CircuitJS1 internals
Core Classes
CirSim - Main Simulator
The central controller class that manages the entire simulation.
Key Methods
public class CirSim {
// Circuit analysis and simulation
void analyzeCircuit() // Setup circuit for analysis
void stampCircuit() // Build admittance matrix
void runCircuit() // Execute simulation timestep
// Matrix operations
void stampResistor(int n1, int n2, double r)
void stampVoltageSource(int n1, int n2, int vs, double v)
void stampCurrentSource(int n1, int n2, double i)
// UI and display
void updateScreen() // Refresh display
void drawCircuit() // Render all elements
// File operations
String dumpCircuit() // Serialize circuit
void loadCircuit(String dump) // Deserialize circuit
}CircuitElm - Base Element Class
Abstract base class for all circuit elements.
Required Overrides
public abstract class CircuitElm {
// Identification
abstract int getDumpType(); // Unique element type ID
abstract int getPostCount(); // Number of connection points
// Simulation
abstract void stamp(); // Add to matrix (linear)
void doStep() {} // Update each timestep (nonlinear)
boolean nonLinear() { return false; }
// Visualization
abstract void draw(); // Render element
abstract void setPoints(); // Calculate geometry
abstract Point getPost(int n); // Get connection point
// User interface
void getInfo(String arr[]) {} // Mouse-over information
EditInfo getEditInfo(int n) { return null; }
void setEditInfo(int n, EditInfo ei) {}
// Serialization
String dump() { return super.dump(); }
}Element Lifecycle
- Construction - Element created by user or file load
- setPoints() - Calculate geometry and connection points
- stamp() - Add linear components to matrix (once per analysis)
- doStep() - Update nonlinear components (each timestep)
- draw() - Render visual representation
Simulation Engine
Modified Nodal Analysis (MNA)
CircuitJS1 uses MNA to solve circuits as matrix equations: Ax = b
- A: Admittance matrix (conductances, voltage sources)
- x: Solution vector (node voltages, currents)
- b: Right-hand side (current sources, voltage source values)
Matrix Building
// Linear elements stamp once during analysis
void stamp() {
sim.stampResistor(nodes[0], nodes[1], 1.0/resistance);
}
// Nonlinear elements update each iteration
void doStep() {
double current = calculateCurrent();
sim.stampCurrentSource(nodes[0], nodes[1], current);
}Node Numbering
- Node 0: Always ground (0V reference)
- Positive integers: Circuit nodes
- Negative integers: Internal nodes (for complex elements)
Stamping Functions
Resistor Stamping
void stampResistor(int n1, int n2, double conductance) {
// Add conductance to diagonal terms
// Subtract from off-diagonal terms
}Voltage Source Stamping
void stampVoltageSource(int n1, int n2, int vs, double voltage) {
// Add row/column for voltage source current
// Enforce voltage constraint
}Current Source Stamping
void stampCurrentSource(int n1, int n2, double current) {
// Add current to right-hand side vector
}Component Implementation Patterns
Passive Components
Simple linear elements that stamp once:
public class ResistorElm extends CircuitElm {
double resistance = 1000; // 1kΩ default
public void stamp() {
sim.stampResistor(nodes[0], nodes[1], resistance);
}
public void getInfo(String arr[]) {
arr[0] = "resistor";
arr[1] = "R = " + getUnitText(resistance, sim.ohmString);
arr[2] = "I = " + getCurrentText(getCurrent());
arr[3] = "P = " + getUnitText(getPower(), "W");
}
}Active Components
Nonlinear elements that update each timestep:
public class DiodeElm extends CircuitElm {
double fwdrop = 0.7; // Forward voltage drop
double zvoltage = 0; // Zener voltage (0 = regular diode)
public boolean nonLinear() { return true; }
public void doStep() {
double voltage = volts[0] - volts[1];
double current;
if (voltage > fwdrop) {
// Forward biased - exponential model
current = leakage * (Math.exp(voltage/vt) - 1);
} else if (zvoltage > 0 && voltage < -zvoltage) {
// Zener breakdown
current = -leakage * Math.exp((-voltage-zvoltage)/vt);
} else {
// Reverse biased - small leakage
current = leakage;
}
sim.stampCurrentSource(nodes[0], nodes[1], current);
}
}Digital Components
Logic elements with discrete states:
public class AndGateElm extends GateElm {
public boolean calcFunction() {
boolean result = true;
for (int i = 0; i < getPostCount()-1; i++) {
if (!getInput(i)) {
result = false;
break;
}
}
return result;
}
}Drawing and UI
Coordinate System
- Circuit canvas uses pixel coordinates
- Origin (0,0) at top-left
- Positive X to the right, positive Y downward
Drawing Methods
public void draw() {
setBbox(); // Set bounding box for selection
draw2Leads(); // Draw connection lines
// Draw component symbol
g.setColor(needsHighlight() ? selectColor : whiteColor);
drawThickLine(point1, point2);
// Draw component-specific graphics
drawResistorSymbol(point1, point2);
drawPosts(); // Draw connection dots
// Add current animation if enabled
if (sim.dragElm != this) {
drawDots();
}
}User Interface Elements
Edit Dialogs
public EditInfo getEditInfo(int n) {
switch (n) {
case 0:
return new EditInfo("Resistance (ohms)", resistance, 0, 0);
case 1:
return new EditInfo("Power Rating (W)", powerRating, 0, 0);
}
return null;
}
public void setEditInfo(int n, EditInfo ei) {
switch (n) {
case 0: resistance = ei.value; break;
case 1: powerRating = ei.value; break;
}
}File Format
Circuit Serialization
Circuits are saved as text with space-separated values:
$ 1 0.000005 10.20027730826997 50 5 50
r 144 144 144 208 0 1000
w 144 144 208 144 0
L 208 144 256 144 0 0 false 5 0
Format Details
- $: Circuit metadata (version, timestep, etc.)
- Element lines:
type x1 y1 x2 y2 flags [parameters...] - w: Wire connections
- r: Resistor with resistance value
- L: Inductor with inductance and initial current
Element Dump Format
public String dump() {
return super.dump() + " " + resistance + " " + powerRating;
}
// Constructor for loading
public ResistorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) {
super(xa, ya, xb, yb, f);
resistance = Double.parseDouble(st.nextToken());
if (st.hasMoreTokens()) {
powerRating = Double.parseDouble(st.nextToken());
}
}Performance Optimization
Matrix Efficiency
- Sparse matrices: Only store non-zero elements
- LU decomposition: Factorize matrix once for linear circuits
- Row elimination: Remove trivial equations
Drawing Optimization
- Dirty rectangles: Only redraw changed areas
- Level of detail: Simplify complex elements when zoomed out
- Canvas optimization: Minimize graphics operations
Extension Points
Adding New Elements
- Choose base class:
CircuitElm,ChipElm,CompositeElm - Implement required methods: See CircuitElm reference above
- Add to factory: Update
constructElement()method - Add to menu: Update UI component lists
Custom Analysis
// Add custom analysis methods to CirSim
public void customAnalysis() {
// Access circuit matrix and solution
double[][] matrix = circuitMatrix;
double[] solution = circuitRightSide;
// Perform custom calculations
// Update display or export results
}This API reference covers the core interfaces for extending CircuitJS1. For implementation examples, see the existing element classes in the source code.