npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ndse-tools-js

v1.1.0

Published

Node.js library for electrical power system simulation: Load Flow and Transient Stability Analysis.

Downloads

169

Readme

NDSE Tools for Electrical Power System

npm version Node.js >= 18 License: GPL-2.0-or-later CI

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-tools

Requires 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 entries

Running the examples

git clone https://github.com/tamashiroBR/ndse-tools-js.git
cd ndse-tools-js
npm test

Contributing

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.