ndse-tools-js
v1.1.0
Published
Node.js library for electrical power system simulation: Load Flow and Transient Stability Analysis.
Downloads
169
Maintainers
Readme
NDSE Tools for Electrical Power System
NDSE Tools is a Node.js library for electrical power system simulation, providing tools for steady-state Load Flow analysis and time-domain Transient Stability Analysis.
Originally developed in PHP as part of a doctoral thesis at the Federal University of Uberlândia (UFU) to investigate web-based interaction strategies for electrical engineering simulation, this package is a pure Python port of the original codebase — with no external numerical dependencies.
It provides:
- AC Newton-Raphson Load Flow with Q-limit enforcement
- Transient Stability Analysis via implicit trapezoidal integration + Newton-Raphson corrector
- Classical (
Gen1) and salient-pole 4th-order (Gen2) synchronous generator models - IEEE Type I (
Exc1) and Type ST1 (Exc2) excitation system models - A complete math toolkit:
Complex,Matrix,Sparse, LU decomposition — no external dependencies
Installation
npm install ndse-toolsRequires Node.js ≥ 18.
Quick Start
Load Flow (IEEE 9-bus)
const { LoadFlow } = require('ndse-tools');
const data = {
optLF: [100, 10, 1e-3, 1], // [Sbase(MVA), maxIter, tol, qlim]
bus: [
// [id, type, Pg(MW), Qg(MVAr), Pl(MW), Ql(MVAr), Gs, Bs, Vm(pu), Va(deg), Qmax, Qmin]
[1, 3, 0, 0, 0, 0, 0, 0, 1.040, 0, 300, -300],
[2, 2, 163, 0, 0, 0, 0, 0, 1.025, 0, 300, -300],
[3, 2, 85, 0, 0, 0, 0, 0, 1.025, 0, 300, -300],
[4, 1, 0, 0, 0, 0, 0, 0, 1.000, 0, 0, 0],
[5, 1, 0, 0, 90, 30, 0, 0, 1.000, 0, 0, 0],
// ...
],
branch: [
// [from, to, r(pu), x(pu), b(pu), tap, shift(deg), status]
[1, 4, 0.0000, 0.0576, 0.0000, 1, 0, 1],
// ...
]
};
const lf = new LoadFlow(data);
const result = lf.run();
console.log(`Converged in ${result.iteration} iterations`);
console.log(`Losses: ${result.loss[0].toFixed(2)} MW`);
// result.bus[i] → [id, Vm, Va_deg, Pg, Qg, Pl, Ql, Qmax, Qmin]
// result.branch[i] → [from, to, Pkm, Qkm, Pmk, Qmk, Ploss, Qloss]Transient Stability Analysis (IEEE 9-bus)
const { TransientAnalysis } = require('ndse-tools');
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('examples/stability_9bus.json', 'utf8'));
const ta = new TransientAnalysis(data);
const result = ta.run();
// result.time → Float64 time vector
// result.delta → [[δ1, δ2, δ3], ...] rotor angles (deg)
// result.omega → [[ω1, ω2, ω3], ...] speeds (pu)
// result.volt → [[V1, V2, V3], ...] terminal voltages (pu)
// result.pmec → mechanical power (pu)
// result.efd → field voltage (pu)Input Data Format
optLF — Load-flow options
[Sbase(MVA), maxIter, tolerance, qlim]| Field | Type | Description |
|-------|------|-------------|
| Sbase | number | System base power in MVA (default 100) |
| maxIter | integer | Maximum Newton-Raphson iterations (default 10) |
| tolerance | number | Convergence tolerance in pu (default 1e-3) |
| qlim | 0 or 1 | Enable reactive-power limit enforcement (default 1) |
bus — Bus data matrix
Each row: [id, type, Pg, Qg, Pl, Ql, Gs, Bs, Vm, Va, Qmax, Qmin]
| Index | Field | Unit | Description |
|-------|-------|------|-------------|
| 0 | id | — | Bus number (1-indexed) |
| 1 | type | — | 1=PQ, 2=PV, 3=Slack |
| 2 | Pg | MW | Active power generated |
| 3 | Qg | MVAr | Reactive power generated (free for PV/Slack) |
| 4 | Pl | MW | Active load |
| 5 | Ql | MVAr | Reactive load |
| 6 | Gs | pu | Shunt conductance |
| 7 | Bs | pu | Shunt susceptance |
| 8 | Vm | pu | Voltage magnitude (initial guess / setpoint) |
| 9 | Va | deg | Voltage angle (initial guess) |
| 10 | Qmax | MVAr | Generator Q upper limit |
| 11 | Qmin | MVAr | Generator Q lower limit |
branch — Branch data matrix
Each row: [from, to, r, x, b, tap, shift, status]
| Index | Field | Unit | Description |
|-------|-------|------|-------------|
| 0 | from | — | From-bus number |
| 1 | to | — | To-bus number |
| 2 | r | pu | Series resistance |
| 3 | x | pu | Series reactance |
| 4 | b | pu | Total shunt susceptance |
| 5 | tap | pu | Off-nominal tap ratio (0 = line) |
| 6 | shift | deg | Phase shift angle |
| 7 | status | 0/1 | In-service flag |
optTA — Transient-analysis options
[freq0(Hz), starttime(s), stoptime(s), stepsize(s)]gen — Generator dynamic data
Each row: [bus_id, model, H, D, xd, xd_tr, ...]
Gen1 (classical 2nd-order) — 9 columns:
[bus_id, 1, H, D, xd, xd_tr, 0, 0, 0]
Gen2 (salient-pole 4th-order) — 10 columns:
[bus_id, 2, H, D, xd, xq, xd_tr, xq_tr, Td_tr, Tq_tr]
| Field | Unit | Description |
|-------|------|-------------|
| H | s | Inertia constant |
| D | pu | Damping coefficient |
| xd | pu | d-axis synchronous reactance |
| xq | pu | q-axis synchronous reactance |
| xd_tr | pu | d-axis transient reactance |
| xq_tr | pu | q-axis transient reactance |
| Td_tr | s | d-axis transient open-circuit time constant |
| Tq_tr | s | q-axis transient open-circuit time constant |
exc — Exciter data
Exc1 (IEEE Type I) — [bus_id, 1, Ka, Ta, Ke, Te, Kf, Tf, Aex, Bex, Urmin, Urmax]
Exc2 (IEEE Type ST1) — [bus_id, 2, Ka, Ta, Kf, Tf, Tr, Vrmin, Vrmax, Kc, Kd, Ki]
event — Disturbance events
Each row: [type, from_bus, to_bus, time(s), z_fault(pu)]
| type | Description |
|--------|-------------|
| 1 | Network disturbance. z_fault > 0 → apply shunt fault at to_bus with admittance 1/z_fault; z_fault = 0 → clear fault / restore network |
| 2 | Line trip (future) |
| 3 | Restore Y-bus (future) |
API Reference
LoadFlow
const lf = new LoadFlow(data);| Method | Returns | Description |
|--------|---------|-------------|
| run() | Object | Solve and return results |
| run_json() | string | Same as run() but JSON-serialised |
| make_ybus() | void | Build the admittance matrix |
| get_ybus() | Sparse | Return the built Y-bus |
| get_option(key) | any | Read a solver option |
| get_data(name, row?, col?) | any | Access raw input data |
| get_n(name) | number | Count buses / branches / transformers / lines |
Result object:
{
iteration: 3,
bus: [[id, Vm, Va_deg, Pg, Qg, Pl, Ql, Qmax, Qmin], ...],
branch: [[from, to, Pkm, Qkm, Pmk, Qmk, Ploss, Qloss], ...],
loss: [Ploss_MW, Qloss_MVAr]
}TransientAnalysis
const ta = new TransientAnalysis(data);| Method | Returns | Description |
|--------|---------|-------------|
| run() | Object | Run and return time-series results |
| run_json() | string | Same, JSON-serialised |
| get_option(key) | any | Read a solver option |
Result object:
{
time: [t0, t1, ...], // seconds
delta: [[δ1, δ2, ...], ...], // rotor angles (degrees)
omega: [[ω1, ω2, ...], ...], // rotor speeds (pu of ω₀)
volt: [[V1, V2, ...], ...], // terminal voltages (pu)
pmec: [[Pm1, Pm2, ...], ...], // mechanical power (pu)
efd: [[Efd1, Efd2, ...], ...] // field voltage (pu)
}Math utilities
All math classes are available as named exports:
const { Complex, Angle, Matrix, Sparse, linalg } = require('ndse-tools');
// Complex number (rectangular)
const z = new Complex(3, 4);
z.abs(); // 5
z.ang(); // radians
z.re; z.img;
z.add(other); z.sub(other); z.multiply(other); z.div(other);
z.conj(); z.neg(); z.inv();
// Complex number (polar)
const p = new Complex(1.04, new Angle(30, 'deg'));
// LU decomposition and solve (Sparse input)
const { lu_decomp, lu_solver } = linalg;
const LU = lu_decomp(sparseMatrix);
const x = lu_solver(LU, b); // b may contain Complex entriesRunning the examples
git clone https://github.com/tamashiroBR/ndse-tools-js.git
cd ndse-tools-js
npm testContributing
Bug reports and pull requests are welcome on GitHub.
Please include a minimal reproducible case and reference the relevant section of the input-data format above.
License
GPL-2.0-or-later — see LICENSE.
