This is V2, a ground-up rebuild. V1 was built back in 2021 as a self-teaching project.
Bowde is a browser-based control-systems workbench: type a transfer function, get Bode, Nyquist, Nichols, pole-zero, and time-domain response plots — all recomputed live, with stability metrics (gain/phase margin, settling time) derived alongside them. Everything runs client-side; there is no backend.
- LaTeX equation input. Enter a transfer function
G(p)in the Laplace variablep(e.g.1 / (1+ap)). Any other letter becomes a free variable, exposed as a slider (linear or logarithmic) so you can sweep a parameter and watch every diagram update in real time. - Five synchronized views. Bode (gain + phase), Nyquist, Nichols, pole-zero map, and time-domain step/impulse response, plus an all-in-one layout — all driven off the same computed data.
- Closed-form-free numerics. No symbolic Laplace inversion: poles and zeros come from an eigenvalue decomposition of the rationalized numerator/denominator's companion matrix (arbitrary polynomial degree, not just the cubics
mathjs's built-in solver handles), and the time response comes from a numerical inverse Laplace transform (Gaver–Stehfest). Seecomputation.utils.ts. - Derived stability metrics. Gain/phase crossover frequencies, gain margin, phase margin, and 5%-band settling time, read directly off the sampled curves.
- Adjustable precision. Draft / Standard / High presets trade sample density (frequency decades and time-domain points) against recompute cost — useful since every parameter tweak recomputes every visible curve.
Formulas are algebraic expressions in p (the Laplace variable), evaluated by mathjs:
1 / (1 + ap) first-order lag, with slider variable `a`
(p + 2) / (p^2 + p + 5) arbitrary rational function
pis reserved for the Laplace variable — for frequency-domain plots it's substituted withjωat each swept frequency; for the time-domain solve it's substituted with the real Gaver–Stehfest abscissae.- Any other letter (
a–o,q–z) used in a formula is treated as a free variable. Adding a slider for that letter under Variables binds it; referencing an unbound letter clears that equation's curves rather than throwing. - The time-domain response convolves the transfer function with whatever input signal is configured in the Time Response panel (step, impulse, etc.) — internally
(input) * (G(p)), inverted once.
| Layer | Choice |
|---|---|
| Framework | Angular 21 (standalone components, signals) |
| Math input | MathLive |
| Computation | mathjs — complex arithmetic, polynomial rationalization, eigenvalues |
| Rendering | p5.js (canvas-based diagram rendering) |
| Layout | angular-split |
| Export | html-to-image |
| Testing | Vitest |
| Deployment | GitHub Actions → GitHub Pages (deploy-pages.yml) |
Requires Node.js and npm (the repo pins npm@10.9.3 via packageManager).
cd bowde
npm install
npm start # ng serve — http://localhost:4200Other scripts (run from bowde/):
npm run build # production build → dist/bowde/browser
npm run watch # dev-mode build, rebuilds on change
npm test # unit tests via VitestNo license file is currently published in this repository — treat the code as all-rights-reserved unless a LICENSE is added.