@classytic/stage 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.mjs +18 -0
- package/dist/atomic/aufbau.d.mts +144 -0
- package/dist/atomic/aufbau.mjs +384 -0
- package/dist/atomic/elements.d.mts +67 -0
- package/dist/atomic/elements.mjs +785 -0
- package/dist/atomic/emission.d.mts +112 -0
- package/dist/atomic/emission.mjs +179 -0
- package/dist/atomic/index.d.mts +8 -0
- package/dist/atomic/index.mjs +9 -0
- package/dist/atomic/periodic.d.mts +82 -0
- package/dist/atomic/periodic.mjs +231 -0
- package/dist/atomic/properties.d.mts +100 -0
- package/dist/atomic/properties.mjs +574 -0
- package/dist/atomic/shells.d.mts +137 -0
- package/dist/atomic/shells.mjs +170 -0
- package/dist/atomic/trends.d.mts +148 -0
- package/dist/atomic/trends.mjs +225 -0
- package/dist/chem/chromatography.d.mts +66 -0
- package/dist/chem/chromatography.mjs +63 -0
- package/dist/chem/complex.d.mts +114 -0
- package/dist/chem/complex.mjs +234 -0
- package/dist/chem/cycle.d.mts +75 -0
- package/dist/chem/cycle.mjs +145 -0
- package/dist/chem/equation.d.mts +86 -0
- package/dist/chem/equation.mjs +168 -0
- package/dist/chem/formula.d.mts +90 -0
- package/dist/chem/formula.mjs +201 -0
- package/dist/chem/functional-groups.d.mts +31 -0
- package/dist/chem/functional-groups.mjs +187 -0
- package/dist/chem/hazard.d.mts +94 -0
- package/dist/chem/hazard.mjs +329 -0
- package/dist/chem/index.d.mts +34 -33
- package/dist/chem/index.mjs +34 -28
- package/dist/chem/ionic.d.mts +98 -0
- package/dist/chem/ionic.mjs +156 -0
- package/dist/chem/layout.d.mts +46 -0
- package/dist/chem/layout.mjs +342 -0
- package/dist/chem/lewis.d.mts +79 -0
- package/dist/chem/lewis.mjs +163 -0
- package/dist/chem/molecular-orbital.d.mts +114 -0
- package/dist/chem/molecular-orbital.mjs +201 -0
- package/dist/chem/molecule.d.mts +154 -0
- package/dist/chem/molecule.mjs +282 -0
- package/dist/chem/nmr.d.mts +153 -0
- package/dist/chem/nmr.mjs +165 -0
- package/dist/chem/polymer.d.mts +65 -0
- package/dist/chem/polymer.mjs +179 -0
- package/dist/chem/redox.d.mts +138 -0
- package/dist/chem/redox.mjs +328 -0
- package/dist/chem/relations.d.mts +183 -0
- package/dist/chem/relations.mjs +299 -0
- package/dist/chem/skeleton.d.mts +51 -0
- package/dist/chem/skeleton.mjs +186 -0
- package/dist/chem/solution.d.mts +116 -0
- package/dist/chem/solution.mjs +186 -0
- package/dist/chem/species.d.mts +47 -0
- package/dist/chem/species.mjs +128 -0
- package/dist/chem/stereo.d.mts +108 -0
- package/dist/chem/stereo.mjs +286 -0
- package/dist/chem/stoichiometry.d.mts +95 -0
- package/dist/chem/stoichiometry.mjs +145 -0
- package/dist/chem/synthesis.d.mts +113 -0
- package/dist/chem/synthesis.mjs +281 -0
- package/dist/chem/vsepr.d.mts +80 -0
- package/dist/chem/vsepr.mjs +247 -0
- package/dist/circuit/ac.d.mts +163 -0
- package/dist/circuit/ac.mjs +452 -0
- package/dist/circuit/dc.d.mts +92 -0
- package/dist/circuit/dc.mjs +333 -0
- package/dist/circuit/index.d.mts +5 -92
- package/dist/circuit/index.mjs +5 -332
- package/dist/circuit/network.d.mts +99 -0
- package/dist/circuit/network.mjs +440 -0
- package/dist/circuit/topology.d.mts +102 -0
- package/dist/circuit/topology.mjs +143 -0
- package/dist/colour/absorption.d.mts +79 -0
- package/dist/colour/absorption.mjs +137 -0
- package/dist/colour/index.d.mts +6 -0
- package/dist/colour/index.mjs +7 -0
- package/dist/colour/name.d.mts +14 -0
- package/dist/colour/name.mjs +76 -0
- package/dist/colour/observer.d.mts +31 -0
- package/dist/colour/observer.mjs +46 -0
- package/dist/colour/spectrum.d.mts +61 -0
- package/dist/colour/spectrum.mjs +108 -0
- package/dist/colour/srgb.d.mts +49 -0
- package/dist/colour/srgb.mjs +108 -0
- package/dist/core/constants.d.mts +138 -0
- package/dist/core/constants.mjs +139 -0
- package/dist/core/index.d.mts +3 -1
- package/dist/core/index.mjs +3 -1
- package/dist/core/vec3.d.mts +94 -0
- package/dist/core/vec3.mjs +123 -0
- package/dist/core/worked.d.mts +35 -0
- package/dist/core/worked.mjs +44 -0
- package/dist/electro/cell.d.mts +102 -0
- package/dist/electro/cell.mjs +170 -0
- package/dist/electro/conductivity.d.mts +157 -0
- package/dist/electro/conductivity.mjs +156 -0
- package/dist/electro/couples.d.mts +114 -0
- package/dist/electro/couples.mjs +334 -0
- package/dist/electro/electrolysis.d.mts +96 -0
- package/dist/electro/electrolysis.mjs +274 -0
- package/dist/electro/faraday.d.mts +150 -0
- package/dist/electro/faraday.mjs +118 -0
- package/dist/electro/index.d.mts +6 -0
- package/dist/electro/index.mjs +7 -0
- package/dist/finance/accounting/adjustments.d.mts +17 -0
- package/dist/finance/accounting/adjustments.mjs +202 -0
- package/dist/finance/accounting/analysis.d.mts +8 -0
- package/dist/finance/accounting/analysis.mjs +205 -0
- package/dist/finance/accounting/clubs.d.mts +21 -0
- package/dist/finance/accounting/clubs.mjs +217 -0
- package/dist/finance/accounting/company-statements.d.mts +7 -0
- package/dist/finance/accounting/company-statements.mjs +150 -0
- package/dist/finance/accounting/harness.d.mts +7 -0
- package/dist/finance/accounting/harness.mjs +45 -0
- package/dist/finance/accounting/index.d.mts +18 -0
- package/dist/finance/accounting/index.mjs +18 -0
- package/dist/finance/accounting/journalize.d.mts +16 -0
- package/dist/finance/accounting/journalize.mjs +128 -0
- package/dist/finance/accounting/manufacturing.d.mts +8 -0
- package/dist/finance/accounting/manufacturing.mjs +236 -0
- package/dist/finance/accounting/partnership.d.mts +7 -0
- package/dist/finance/accounting/partnership.mjs +152 -0
- package/dist/finance/accounting/period-case.d.mts +6 -0
- package/dist/finance/accounting/period-case.mjs +71 -0
- package/dist/finance/accounting/post.d.mts +9 -0
- package/dist/finance/accounting/post.mjs +84 -0
- package/dist/finance/accounting/precision.d.mts +9 -0
- package/dist/finance/accounting/precision.mjs +15 -0
- package/dist/finance/accounting/rules.d.mts +21 -0
- package/dist/finance/accounting/rules.mjs +37 -0
- package/dist/finance/accounting/solve.d.mts +28 -0
- package/dist/finance/accounting/solve.mjs +92 -0
- package/dist/finance/accounting/statements.d.mts +7 -0
- package/dist/finance/accounting/statements.mjs +142 -0
- package/dist/finance/accounting/types.d.mts +649 -0
- package/dist/finance/accounting/validate.d.mts +7 -0
- package/dist/finance/accounting/validate.mjs +67 -0
- package/dist/finance/accounting/verification.d.mts +24 -0
- package/dist/finance/accounting/verification.mjs +386 -0
- package/dist/finance/bizsim.d.mts +21 -39
- package/dist/finance/bizsim.mjs +276 -97
- package/dist/finance/index.d.mts +20 -43
- package/dist/finance/index.mjs +19 -77
- package/dist/finance/investment-math.d.mts +7 -0
- package/dist/finance/investment-math.mjs +18 -0
- package/dist/finance/management-accounting/budgeting.d.mts +7 -0
- package/dist/finance/management-accounting/budgeting.mjs +189 -0
- package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
- package/dist/finance/management-accounting/cash-budget.mjs +154 -0
- package/dist/finance/management-accounting/costing.d.mts +8 -0
- package/dist/finance/management-accounting/costing.mjs +175 -0
- package/dist/finance/management-accounting/decisions.d.mts +8 -0
- package/dist/finance/management-accounting/decisions.mjs +164 -0
- package/dist/finance/management-accounting/index.d.mts +13 -0
- package/dist/finance/management-accounting/index.mjs +13 -0
- package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
- package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
- package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
- package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
- package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
- package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
- package/dist/finance/management-accounting/management-case.d.mts +8 -0
- package/dist/finance/management-accounting/management-case.mjs +91 -0
- package/dist/finance/management-accounting/master-budget.d.mts +7 -0
- package/dist/finance/management-accounting/master-budget.mjs +137 -0
- package/dist/finance/management-accounting/production-costing.d.mts +8 -0
- package/dist/finance/management-accounting/production-costing.mjs +214 -0
- package/dist/finance/management-accounting/types.d.mts +644 -0
- package/dist/finance/management-accounting/variances.d.mts +7 -0
- package/dist/finance/management-accounting/variances.mjs +150 -0
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +1 -1
- package/dist/math/analysis.d.mts +61 -0
- package/dist/math/analysis.mjs +187 -0
- package/dist/math/answer-check.d.mts +50 -0
- package/dist/math/answer-check.mjs +106 -0
- package/dist/math/calculus.d.mts +4 -9
- package/dist/math/calculus.mjs +216 -7
- package/dist/math/complex.d.mts +93 -0
- package/dist/math/complex.mjs +239 -0
- package/dist/math/expr.d.mts +23 -0
- package/dist/math/expr.mjs +36 -0
- package/dist/math/index.d.mts +8 -22
- package/dist/math/index.mjs +8 -37
- package/dist/math/latex.mjs +2 -1
- package/dist/math/parse.mjs +1 -1
- package/dist/math/poly.d.mts +55 -0
- package/dist/math/poly.mjs +273 -0
- package/dist/math/rearrange.d.mts +14 -0
- package/dist/math/rearrange.mjs +125 -0
- package/dist/math/solve.d.mts +21 -0
- package/dist/math/solve.mjs +75 -0
- package/dist/networking/addressing.d.mts +26 -0
- package/dist/networking/addressing.mjs +33 -0
- package/dist/networking/cloud/access.d.mts +36 -0
- package/dist/networking/cloud/access.mjs +95 -0
- package/dist/networking/cloud/containers.d.mts +43 -0
- package/dist/networking/cloud/containers.mjs +54 -0
- package/dist/networking/cloud/edge.d.mts +17 -0
- package/dist/networking/cloud/edge.mjs +31 -0
- package/dist/networking/cloud/failure-domains.d.mts +19 -0
- package/dist/networking/cloud/failure-domains.mjs +22 -0
- package/dist/networking/cloud/geo-routing.d.mts +22 -0
- package/dist/networking/cloud/geo-routing.mjs +64 -0
- package/dist/networking/cloud/index.d.mts +18 -0
- package/dist/networking/cloud/index.mjs +19 -0
- package/dist/networking/cloud/inference-reliability.d.mts +30 -0
- package/dist/networking/cloud/inference-reliability.mjs +76 -0
- package/dist/networking/cloud/inference.d.mts +118 -0
- package/dist/networking/cloud/inference.mjs +179 -0
- package/dist/networking/cloud/infrastructure.d.mts +45 -0
- package/dist/networking/cloud/infrastructure.mjs +96 -0
- package/dist/networking/cloud/observability.d.mts +24 -0
- package/dist/networking/cloud/observability.mjs +34 -0
- package/dist/networking/cloud/orchestration.d.mts +32 -0
- package/dist/networking/cloud/orchestration.mjs +38 -0
- package/dist/networking/cloud/recovery.d.mts +21 -0
- package/dist/networking/cloud/recovery.mjs +27 -0
- package/dist/networking/cloud/releases.d.mts +42 -0
- package/dist/networking/cloud/releases.mjs +135 -0
- package/dist/networking/cloud/scaling.d.mts +25 -0
- package/dist/networking/cloud/scaling.mjs +65 -0
- package/dist/networking/cloud/secrets.d.mts +39 -0
- package/dist/networking/cloud/secrets.mjs +68 -0
- package/dist/networking/cloud/server-deployment.d.mts +29 -0
- package/dist/networking/cloud/server-deployment.mjs +72 -0
- package/dist/networking/cloud/storage.d.mts +16 -0
- package/dist/networking/cloud/storage.mjs +58 -0
- package/dist/networking/cloud/vpc.d.mts +18 -0
- package/dist/networking/cloud/vpc.mjs +100 -0
- package/dist/networking/delivery.d.mts +34 -0
- package/dist/networking/delivery.mjs +52 -0
- package/dist/networking/index.d.mts +47 -0
- package/dist/networking/index.mjs +47 -0
- package/dist/networking/ipv6.d.mts +28 -0
- package/dist/networking/ipv6.mjs +17 -0
- package/dist/networking/journeys.d.mts +83 -0
- package/dist/networking/journeys.mjs +161 -0
- package/dist/networking/models/airtime.d.mts +87 -0
- package/dist/networking/models/airtime.mjs +130 -0
- package/dist/networking/models/cellular.d.mts +157 -0
- package/dist/networking/models/cellular.mjs +252 -0
- package/dist/networking/models/encapsulation.d.mts +98 -0
- package/dist/networking/models/encapsulation.mjs +132 -0
- package/dist/networking/models/handover.d.mts +116 -0
- package/dist/networking/models/handover.mjs +209 -0
- package/dist/networking/models/handshake.d.mts +90 -0
- package/dist/networking/models/handshake.mjs +122 -0
- package/dist/networking/models/index.d.mts +14 -0
- package/dist/networking/models/index.mjs +15 -0
- package/dist/networking/models/media.d.mts +82 -0
- package/dist/networking/models/media.mjs +188 -0
- package/dist/networking/models/satellite.d.mts +86 -0
- package/dist/networking/models/satellite.mjs +121 -0
- package/dist/networking/models/spectrum.d.mts +83 -0
- package/dist/networking/models/spectrum.mjs +235 -0
- package/dist/networking/models/switch.d.mts +80 -0
- package/dist/networking/models/switch.mjs +155 -0
- package/dist/networking/models/vlan.d.mts +62 -0
- package/dist/networking/models/vlan.mjs +100 -0
- package/dist/networking/models/vpn.d.mts +66 -0
- package/dist/networking/models/vpn.mjs +125 -0
- package/dist/networking/models/wifi-privacy.d.mts +82 -0
- package/dist/networking/models/wifi-privacy.mjs +130 -0
- package/dist/networking/models/wifi.d.mts +240 -0
- package/dist/networking/models/wifi.mjs +562 -0
- package/dist/networking/nat-traversal.d.mts +24 -0
- package/dist/networking/nat-traversal.mjs +38 -0
- package/dist/networking/protocols.d.mts +17 -0
- package/dist/networking/protocols.mjs +57 -0
- package/dist/networking/queue.d.mts +12 -0
- package/dist/networking/queue.mjs +18 -0
- package/dist/networking/route-learning.d.mts +23 -0
- package/dist/networking/route-learning.mjs +43 -0
- package/dist/networking/routing.d.mts +11 -0
- package/dist/networking/routing.mjs +25 -0
- package/dist/networking/signals.d.mts +26 -0
- package/dist/networking/signals.mjs +35 -0
- package/dist/networking/subnet.d.mts +49 -0
- package/dist/networking/subnet.mjs +89 -0
- package/dist/networking/tcp-reliability.d.mts +24 -0
- package/dist/networking/tcp-reliability.mjs +38 -0
- package/dist/networking/topology/contract.d.mts +123 -0
- package/dist/networking/topology/index.d.mts +4 -0
- package/dist/networking/topology/index.mjs +4 -0
- package/dist/networking/topology/presets.d.mts +7 -0
- package/dist/networking/topology/presets.mjs +302 -0
- package/dist/networking/topology/simulation.d.mts +8 -0
- package/dist/networking/topology/simulation.mjs +179 -0
- package/dist/networking/wireless.d.mts +11 -0
- package/dist/networking/wireless.mjs +17 -0
- package/dist/optics/imaging.d.mts +218 -0
- package/dist/optics/imaging.mjs +276 -0
- package/dist/optics/index.d.mts +7 -0
- package/dist/optics/index.mjs +8 -0
- package/dist/optics/laws.d.mts +70 -0
- package/dist/optics/laws.mjs +195 -0
- package/dist/optics/prism.d.mts +148 -0
- package/dist/optics/prism.mjs +197 -0
- package/dist/optics/refraction.d.mts +201 -0
- package/dist/optics/refraction.mjs +270 -0
- package/dist/optics/wave-optics.d.mts +171 -0
- package/dist/optics/wave-optics.mjs +259 -0
- package/dist/physics/ac/index.d.mts +183 -0
- package/dist/physics/ac/index.mjs +203 -0
- package/dist/physics/dynamics/forces.d.mts +98 -0
- package/dist/physics/dynamics/forces.mjs +153 -0
- package/dist/physics/dynamics/friction.d.mts +76 -0
- package/dist/physics/dynamics/friction.mjs +119 -0
- package/dist/physics/dynamics/system.d.mts +68 -0
- package/dist/physics/dynamics/system.mjs +125 -0
- package/dist/physics/electrostatics/index.d.mts +169 -0
- package/dist/physics/electrostatics/index.mjs +249 -0
- package/dist/physics/energy/centre-of-mass.d.mts +115 -0
- package/dist/physics/energy/centre-of-mass.mjs +180 -0
- package/dist/physics/energy/conservation.d.mts +81 -0
- package/dist/physics/energy/conservation.mjs +129 -0
- package/dist/physics/energy/power.d.mts +90 -0
- package/dist/physics/energy/power.mjs +167 -0
- package/dist/physics/energy/spring.d.mts +73 -0
- package/dist/physics/energy/spring.mjs +129 -0
- package/dist/physics/energy/store.d.mts +63 -0
- package/dist/physics/energy/store.mjs +108 -0
- package/dist/physics/energy/theorem.d.mts +65 -0
- package/dist/physics/energy/theorem.mjs +113 -0
- package/dist/physics/energy/work.d.mts +114 -0
- package/dist/physics/energy/work.mjs +219 -0
- package/dist/physics/gravitation/body.d.mts +85 -0
- package/dist/physics/gravitation/body.mjs +168 -0
- package/dist/physics/gravitation/kepler.d.mts +127 -0
- package/dist/physics/gravitation/kepler.mjs +216 -0
- package/dist/physics/gravitation/law.d.mts +117 -0
- package/dist/physics/gravitation/law.mjs +175 -0
- package/dist/physics/gravitation/orbit.d.mts +119 -0
- package/dist/physics/gravitation/orbit.mjs +202 -0
- package/dist/physics/gravitation/potential.d.mts +114 -0
- package/dist/physics/gravitation/potential.mjs +202 -0
- package/dist/physics/gravitation/variation.d.mts +97 -0
- package/dist/physics/gravitation/variation.mjs +175 -0
- package/dist/physics/index.d.mts +35 -0
- package/dist/physics/index.mjs +36 -0
- package/dist/physics/integral-sweep.d.mts +63 -0
- package/dist/physics/integral-sweep.mjs +126 -0
- package/dist/physics/kinematics/equations.d.mts +47 -0
- package/dist/physics/kinematics/equations.mjs +126 -0
- package/dist/physics/kinematics/free-fall.d.mts +53 -0
- package/dist/physics/kinematics/free-fall.mjs +71 -0
- package/dist/physics/kinematics/given.d.mts +16 -0
- package/dist/physics/kinematics/given.mjs +55 -0
- package/dist/physics/kinematics/roots.d.mts +41 -0
- package/dist/physics/kinematics/roots.mjs +72 -0
- package/dist/physics/kinematics/solve.d.mts +52 -0
- package/dist/physics/kinematics/solve.mjs +172 -0
- package/dist/physics/magnetism/biot-savart.d.mts +161 -0
- package/dist/physics/magnetism/biot-savart.mjs +353 -0
- package/dist/physics/magnetism/flux.d.mts +94 -0
- package/dist/physics/magnetism/flux.mjs +313 -0
- package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
- package/dist/physics/magnetism/geomagnetism.mjs +184 -0
- package/dist/physics/magnetism/index.d.mts +12 -0
- package/dist/physics/magnetism/index.mjs +74 -0
- package/dist/physics/magnetism/lorentz.d.mts +28 -0
- package/dist/physics/magnetism/lorentz.mjs +88 -0
- package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
- package/dist/physics/magnetism/magnetic-force.mjs +169 -0
- package/dist/physics/momentum/collide.d.mts +77 -0
- package/dist/physics/momentum/collide.mjs +115 -0
- package/dist/physics/momentum/impulse.d.mts +89 -0
- package/dist/physics/momentum/impulse.mjs +159 -0
- package/dist/physics/momentum/planar.d.mts +60 -0
- package/dist/physics/momentum/planar.mjs +110 -0
- package/dist/physics/projectile.d.mts +107 -0
- package/dist/physics/projectile.mjs +185 -0
- package/dist/physics/rotation/angular.d.mts +85 -0
- package/dist/physics/rotation/angular.mjs +130 -0
- package/dist/physics/rotation/circular.d.mts +79 -0
- package/dist/physics/rotation/circular.mjs +131 -0
- package/dist/physics/rotation/inertia.d.mts +164 -0
- package/dist/physics/rotation/inertia.mjs +332 -0
- package/dist/physics/rotation/torque.d.mts +65 -0
- package/dist/physics/rotation/torque.mjs +134 -0
- package/dist/physics/vectors.d.mts +64 -0
- package/dist/physics/vectors.mjs +114 -0
- package/dist/quantity/index.d.mts +119 -0
- package/dist/quantity/index.mjs +417 -0
- package/dist/relation/derive.d.mts +74 -0
- package/dist/relation/derive.mjs +73 -0
- package/dist/relation/index.d.mts +56 -0
- package/dist/relation/index.mjs +234 -0
- package/dist/scene/evaluators.mjs +1 -1
- package/dist/sim/thermal.mjs +45 -20
- package/dist/thermo/calorimetry.d.mts +207 -0
- package/dist/thermo/calorimetry.mjs +345 -0
- package/dist/thermo/cycles.d.mts +142 -0
- package/dist/thermo/cycles.mjs +256 -0
- package/dist/thermo/entropy.d.mts +87 -0
- package/dist/thermo/entropy.mjs +140 -0
- package/dist/thermo/expansion.d.mts +130 -0
- package/dist/thermo/expansion.mjs +178 -0
- package/dist/thermo/gas.d.mts +197 -0
- package/dist/thermo/gas.mjs +279 -0
- package/dist/thermo/heat-transfer.d.mts +164 -0
- package/dist/thermo/heat-transfer.mjs +217 -0
- package/dist/thermo/index.d.mts +9 -82
- package/dist/thermo/index.mjs +9 -132
- package/dist/thermo/processes.d.mts +95 -0
- package/dist/thermo/processes.mjs +154 -0
- package/dist/thermo/temperature.d.mts +174 -0
- package/dist/thermo/temperature.mjs +236 -0
- package/dist/waves/damping.d.mts +224 -0
- package/dist/waves/damping.mjs +317 -0
- package/dist/waves/doppler.d.mts +72 -0
- package/dist/waves/doppler.mjs +125 -0
- package/dist/waves/index.d.mts +10 -0
- package/dist/waves/index.mjs +10 -0
- package/dist/waves/pendulum.d.mts +130 -0
- package/dist/waves/pendulum.mjs +211 -0
- package/dist/waves/pitch.d.mts +125 -0
- package/dist/waves/pitch.mjs +158 -0
- package/dist/waves/shm.d.mts +170 -0
- package/dist/waves/shm.mjs +279 -0
- package/dist/waves/springs.d.mts +103 -0
- package/dist/waves/springs.mjs +176 -0
- package/dist/waves/superposition.d.mts +124 -0
- package/dist/waves/superposition.mjs +196 -0
- package/dist/waves/wave.d.mts +154 -0
- package/dist/waves/wave.mjs +178 -0
- package/package.json +74 -2
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import { complex_exports } from "../math/complex.mjs";
|
|
2
|
+
import { findBridgeShape, findDangling, findParallelGroup, findSelfLoop, findSeriesPair, isReduced, mergedId, validateTopology } from "./topology.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/circuit/ac.ts
|
|
5
|
+
/**
|
|
6
|
+
* @classytic/stage/circuit/ac-impedance — AC steady state: impedance, phasors, resonance and the frequency response of a network.
|
|
7
|
+
*
|
|
8
|
+
* This is the engine the DC ones were a special case of, and saying that plainly is the point of
|
|
9
|
+
* the file. `network-reduction` showed that resistors and capacitors reduce by the same rules with
|
|
10
|
+
* the arithmetic swapped. The swap was never real. It was an artefact of insisting on real numbers:
|
|
11
|
+
*
|
|
12
|
+
* Z_R = R Z_L = jωL Z_C = 1/(jωC)
|
|
13
|
+
*
|
|
14
|
+
* and with those, series ALWAYS adds impedance and parallel always adds admittance, for every
|
|
15
|
+
* component at every frequency. The reciprocal that looked like a special rule for capacitors is
|
|
16
|
+
* just what 1/(jωC) does when you add it up.
|
|
17
|
+
*
|
|
18
|
+
* ── What this buys that DC could not ────────────────────────────────────────────────────────────
|
|
19
|
+
* Everything that depends on frequency, which is most of what a circuit is actually used for:
|
|
20
|
+
* filters, resonance, tuning, coupling, the reason a loudspeaker crossover works, the reason an
|
|
21
|
+
* oscilloscope probe is compensated. It is the core of an undergraduate circuits course and it is
|
|
22
|
+
* on A2 physics as the LCR circuit.
|
|
23
|
+
*
|
|
24
|
+
* ── How it is checked ───────────────────────────────────────────────────────────────────────────
|
|
25
|
+
* Phasor algebra is easy to get subtly wrong in the sign of the reactance, and a test that compares
|
|
26
|
+
* the algebra with itself would never notice. So the tests integrate the governing ODE of a driven
|
|
27
|
+
* series RLC forward in time and measure the steady-state amplitude and phase off the waveform,
|
|
28
|
+
* then compare that with what this file predicts. Time domain against frequency domain is the
|
|
29
|
+
* strongest independent check available for this, and it catches a sign error immediately: a
|
|
30
|
+
* current that should lag would be measured leading.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* The complex kernel is NAMESPACED on purpose, and must stay that way here.
|
|
34
|
+
*
|
|
35
|
+
* `@classytic/stage/math` re-exports it as `export * as complex` because `complex` and `poly` both
|
|
36
|
+
* export an `add` and a `mul` that mean entirely different things. Importing them flat compiles and
|
|
37
|
+
* then silently resolves to whichever the bundler saw last. `C.add` costs two characters and
|
|
38
|
+
* removes the possibility.
|
|
39
|
+
*/
|
|
40
|
+
const { abs, add, argDeg, cx, div, mul, sub } = complex_exports;
|
|
41
|
+
const finitePositive = (value, what) => {
|
|
42
|
+
if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${what} must be positive`);
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
const finiteNonNegative = (value, what) => {
|
|
46
|
+
if (!Number.isFinite(value) || value < 0) throw new RangeError(`${what} must be zero or more`);
|
|
47
|
+
return value;
|
|
48
|
+
};
|
|
49
|
+
/** A resistance so small it is a wire, used to keep a division from blowing up. */
|
|
50
|
+
const TINY = 1e-12;
|
|
51
|
+
/**
|
|
52
|
+
* The impedance of one component at angular frequency ω.
|
|
53
|
+
*
|
|
54
|
+
* R Z = R real, and the same at every frequency
|
|
55
|
+
* L Z = jωL purely positive-imaginary: current LAGS the voltage
|
|
56
|
+
* C Z = 1/(jωC) = −j/(ωC) purely negative-imaginary: current LEADS the voltage
|
|
57
|
+
*
|
|
58
|
+
* The signs are the whole content of the topic, and they are why a capacitor and an inductor can
|
|
59
|
+
* cancel each other out exactly.
|
|
60
|
+
*/
|
|
61
|
+
function impedanceOf(element, omegaRadPerS) {
|
|
62
|
+
const omega = finiteNonNegative(omegaRadPerS, "angular frequency");
|
|
63
|
+
switch (element.kind) {
|
|
64
|
+
case "R": return cx(finiteNonNegative(element.value, `resistor ${element.id}`), 0);
|
|
65
|
+
case "L": return cx(0, omega * finiteNonNegative(element.value, `inductor ${element.id}`));
|
|
66
|
+
case "C": {
|
|
67
|
+
const c = finitePositive(element.value, `capacitor ${element.id}`);
|
|
68
|
+
if (omega === 0) return cx(Infinity, 0);
|
|
69
|
+
return cx(0, -1 / (omega * c));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Reactance: the imaginary part. Positive is inductive, negative is capacitive. */
|
|
74
|
+
const reactance = (z) => z.im;
|
|
75
|
+
/** Resistance: the real part, which is the only part that dissipates energy. */
|
|
76
|
+
const resistance = (z) => z.re;
|
|
77
|
+
/** Magnitude |Z|, in ohms. */
|
|
78
|
+
const magnitude = (z) => abs(z);
|
|
79
|
+
/** Phase of the impedance in degrees. Positive means the current lags the voltage. */
|
|
80
|
+
const phaseDeg = (z) => argDeg(z);
|
|
81
|
+
/** Series impedances add. Always, for every component kind, at every frequency. */
|
|
82
|
+
function seriesImpedance(zs) {
|
|
83
|
+
return zs.reduce((sum, z) => add(sum, z), cx(0, 0));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Parallel impedances combine by adding ADMITTANCES, Y = 1/Z.
|
|
87
|
+
*
|
|
88
|
+
* An infinite impedance (a capacitor at DC) contributes zero admittance rather than breaking the
|
|
89
|
+
* sum, which is both numerically necessary and physically exactly right: an open branch in parallel
|
|
90
|
+
* changes nothing.
|
|
91
|
+
*/
|
|
92
|
+
function parallelImpedance(zs) {
|
|
93
|
+
let y = cx(0, 0);
|
|
94
|
+
for (const z of zs) {
|
|
95
|
+
if (!Number.isFinite(z.re) || !Number.isFinite(z.im)) continue;
|
|
96
|
+
if (abs(z) < 1e-12) return cx(0, 0);
|
|
97
|
+
y = add(y, div(cx(1, 0), z));
|
|
98
|
+
}
|
|
99
|
+
if (abs(y) < 1e-12) return cx(Infinity, 0);
|
|
100
|
+
return div(cx(1, 0), y);
|
|
101
|
+
}
|
|
102
|
+
const asTopology = (network) => ({
|
|
103
|
+
edges: network.elements,
|
|
104
|
+
terminals: network.terminals
|
|
105
|
+
});
|
|
106
|
+
/**
|
|
107
|
+
* The equivalent impedance between the terminals at one frequency.
|
|
108
|
+
*
|
|
109
|
+
* Uses the same structural rules as the DC reducer, from `topology.ts`, because the shape of a
|
|
110
|
+
* network has nothing to do with what it is made of. Only the arithmetic differs, and here the
|
|
111
|
+
* arithmetic is complex.
|
|
112
|
+
*
|
|
113
|
+
* A reduced edge is carried as an R whose "value" is meaningless; what matters is the impedance map
|
|
114
|
+
* kept alongside. Doing it that way means a merged branch is a first-class edge for the next rule
|
|
115
|
+
* rather than a special case.
|
|
116
|
+
*/
|
|
117
|
+
function equivalentImpedance(network, omegaRadPerS) {
|
|
118
|
+
validateTopology(asTopology(network));
|
|
119
|
+
const omega = finiteNonNegative(omegaRadPerS, "angular frequency");
|
|
120
|
+
let edges = network.elements.map((e) => ({
|
|
121
|
+
id: e.id,
|
|
122
|
+
a: e.a,
|
|
123
|
+
b: e.b
|
|
124
|
+
}));
|
|
125
|
+
const z = /* @__PURE__ */ new Map();
|
|
126
|
+
for (const element of network.elements) z.set(element.id, impedanceOf(element, omega));
|
|
127
|
+
const terminals = network.terminals;
|
|
128
|
+
const zOf = (edge) => z.get(edge.id) ?? cx(0, 0);
|
|
129
|
+
let guard = edges.length * 4 + 8;
|
|
130
|
+
while (guard-- > 0) {
|
|
131
|
+
const t = {
|
|
132
|
+
edges,
|
|
133
|
+
terminals
|
|
134
|
+
};
|
|
135
|
+
if (isReduced(t)) break;
|
|
136
|
+
const dangling = findDangling(t);
|
|
137
|
+
if (dangling) {
|
|
138
|
+
edges = edges.filter((e) => e.id !== dangling.edge.id);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const loop = findSelfLoop(t);
|
|
142
|
+
if (loop) {
|
|
143
|
+
edges = edges.filter((e) => e.id !== loop.id);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const group = findParallelGroup(t);
|
|
147
|
+
if (group) {
|
|
148
|
+
const id = mergedId(t, group);
|
|
149
|
+
const combined = parallelImpedance(group.map(zOf));
|
|
150
|
+
const ids = new Set(group.map((e) => e.id));
|
|
151
|
+
edges = [...edges.filter((e) => !ids.has(e.id)), {
|
|
152
|
+
id,
|
|
153
|
+
a: group[0].a,
|
|
154
|
+
b: group[0].b
|
|
155
|
+
}];
|
|
156
|
+
z.set(id, combined);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const pair = findSeriesPair(t);
|
|
160
|
+
if (pair) {
|
|
161
|
+
const id = mergedId(t, pair.edges);
|
|
162
|
+
const combined = seriesImpedance(pair.edges.map(zOf));
|
|
163
|
+
const ids = new Set(pair.edges.map((e) => e.id));
|
|
164
|
+
edges = [...edges.filter((e) => !ids.has(e.id)), {
|
|
165
|
+
id,
|
|
166
|
+
a: pair.ends[0],
|
|
167
|
+
b: pair.ends[1]
|
|
168
|
+
}];
|
|
169
|
+
z.set(id, combined);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const shape = findBridgeShape(t);
|
|
173
|
+
if (shape && bridgeBalances(zOf(shape.p), zOf(shape.q), zOf(shape.r), zOf(shape.s))) {
|
|
174
|
+
edges = edges.filter((e) => e.id !== shape.bridge.id);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const only = edges[0];
|
|
180
|
+
return only ? zOf(only) : null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Complex Gaussian elimination with partial pivoting.
|
|
184
|
+
*
|
|
185
|
+
* `solveLinear` in `@classytic/stage/circuit` does this for real matrices and cannot be reused:
|
|
186
|
+
* every entry here is a complex admittance, and pivoting has to compare MAGNITUDES rather than
|
|
187
|
+
* signed values. Small enough to own, and the alternative is to represent each complex unknown as
|
|
188
|
+
* two real ones and solve a system of twice the size, which doubles the work and makes every
|
|
189
|
+
* intermediate unreadable.
|
|
190
|
+
*/
|
|
191
|
+
function solveComplexLinear(matrix, rhs) {
|
|
192
|
+
const n = rhs.length;
|
|
193
|
+
const a = matrix.map((row, i) => [...row, rhs[i]]);
|
|
194
|
+
for (let col = 0; col < n; col++) {
|
|
195
|
+
let best = col;
|
|
196
|
+
for (let row = col + 1; row < n; row++) if (abs(a[row][col]) > abs(a[best][col])) best = row;
|
|
197
|
+
if (abs(a[best][col]) < 1e-18) return null;
|
|
198
|
+
if (best !== col) {
|
|
199
|
+
const swap = a[best];
|
|
200
|
+
a[best] = a[col];
|
|
201
|
+
a[col] = swap;
|
|
202
|
+
}
|
|
203
|
+
const pivot = a[col][col];
|
|
204
|
+
for (let row = col + 1; row < n; row++) {
|
|
205
|
+
const factor = div(a[row][col], pivot);
|
|
206
|
+
if (abs(factor) === 0) continue;
|
|
207
|
+
for (let k = col; k <= n; k++) a[row][k] = sub(a[row][k], mul(factor, a[col][k]));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const out = new Array(n).fill(cx(0, 0));
|
|
211
|
+
for (let row = n - 1; row >= 0; row--) {
|
|
212
|
+
let sum = a[row][n];
|
|
213
|
+
for (let col = row + 1; col < n; col++) sum = sub(sum, mul(a[row][col], out[col]));
|
|
214
|
+
out[row] = div(sum, a[row][row]);
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
/** Admittance of one element, with the two degenerate cases handled explicitly. */
|
|
219
|
+
function admittanceOf(element, omega) {
|
|
220
|
+
const z = impedanceOf(element, omega);
|
|
221
|
+
if (!Number.isFinite(z.re) || !Number.isFinite(z.im)) return cx(0, 0);
|
|
222
|
+
if (abs(z) < 1e-12) return cx(1 / TINY, 0);
|
|
223
|
+
return div(cx(1, 0), z);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The equivalent impedance of ANY network, by nodal analysis in the frequency domain.
|
|
227
|
+
*
|
|
228
|
+
* Where `equivalentImpedance` reduces by series and parallel and gives up honestly when those run
|
|
229
|
+
* out, this always answers. It injects one amp into the first terminal, grounds the second, solves
|
|
230
|
+
* the complex nodal equations and reads the voltage that appears: Z = V/I with I = 1.
|
|
231
|
+
*
|
|
232
|
+
* This is what makes the engine complete rather than merely correct. An unbalanced AC bridge has no
|
|
233
|
+
* series or parallel move anywhere in it, which is a fact about the shape and not a gap in the
|
|
234
|
+
* rules, and before this it could only be reported as unsolvable. A tool that reports defeat on a
|
|
235
|
+
* circuit an undergraduate is expected to analyse is a teaching aid, not an engine.
|
|
236
|
+
*
|
|
237
|
+
* The two coexist on purpose: the reducer narrates and this one answers, and the tests require them
|
|
238
|
+
* to agree wherever the reducer can finish.
|
|
239
|
+
*/
|
|
240
|
+
function impedanceByNodalAnalysis(network, omegaRadPerS) {
|
|
241
|
+
validateTopology(asTopology(network));
|
|
242
|
+
const omega = finiteNonNegative(omegaRadPerS, "angular frequency");
|
|
243
|
+
const [source, ground] = network.terminals;
|
|
244
|
+
const index = /* @__PURE__ */ new Map();
|
|
245
|
+
for (const element of network.elements) for (const node of [element.a, element.b]) if (node !== ground && !index.has(node)) index.set(node, index.size);
|
|
246
|
+
const driven = index.get(source);
|
|
247
|
+
if (driven === void 0) return null;
|
|
248
|
+
const n = index.size;
|
|
249
|
+
const build = (gmin) => {
|
|
250
|
+
const y = Array.from({ length: n }, () => Array.from({ length: n }, () => cx(0, 0)));
|
|
251
|
+
for (let k = 0; k < n; k++) y[k][k] = cx(gmin, 0);
|
|
252
|
+
for (const element of network.elements) {
|
|
253
|
+
const ya = admittanceOf(element, omega);
|
|
254
|
+
const i = element.a === ground ? -1 : index.get(element.a);
|
|
255
|
+
const j = element.b === ground ? -1 : index.get(element.b);
|
|
256
|
+
if (i === j) continue;
|
|
257
|
+
if (i >= 0) y[i][i] = add(y[i][i], ya);
|
|
258
|
+
if (j >= 0) y[j][j] = add(y[j][j], ya);
|
|
259
|
+
if (i >= 0 && j >= 0) {
|
|
260
|
+
y[i][j] = sub(y[i][j], ya);
|
|
261
|
+
y[j][i] = sub(y[j][i], ya);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return y;
|
|
265
|
+
};
|
|
266
|
+
const current = Array.from({ length: n }, (_, k) => k === driven ? cx(1, 0) : cx(0, 0));
|
|
267
|
+
/**
|
|
268
|
+
* A dangling branch leaves its far node connected to nothing else, which makes the matrix
|
|
269
|
+
* singular even though the network has a perfectly good answer. A tiny conductance to ground on
|
|
270
|
+
* every node fixes exactly that, and is what every circuit simulator does for the same reason.
|
|
271
|
+
* It is tried SECOND so an ordinary network is solved with no perturbation at all.
|
|
272
|
+
*/
|
|
273
|
+
const solved = solveComplexLinear(build(0), current) ?? solveComplexLinear(build(1e-12), current);
|
|
274
|
+
if (!solved) return null;
|
|
275
|
+
const v = solved[driven];
|
|
276
|
+
return v && Number.isFinite(v.re) && Number.isFinite(v.im) ? v : null;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Does an AC bridge balance?
|
|
280
|
+
*
|
|
281
|
+
* The condition is Z_P/Z_Q = Z_R/Z_S as COMPLEX numbers, which means the magnitudes must be in
|
|
282
|
+
* proportion AND the phases must match. That is two conditions, not one, and it is exactly why a
|
|
283
|
+
* real AC bridge has two adjustable components where a Wheatstone bridge has one. A student who
|
|
284
|
+
* has only met the DC bridge finds this genuinely surprising, and it falls straight out of using
|
|
285
|
+
* complex numbers rather than being an extra rule to remember.
|
|
286
|
+
*/
|
|
287
|
+
function bridgeBalances(p, q, r, s) {
|
|
288
|
+
if (abs(q) < 1e-12 || abs(s) < 1e-12) return false;
|
|
289
|
+
const left = div(p, q);
|
|
290
|
+
const right = div(r, s);
|
|
291
|
+
const scale = Math.max(1, abs(left), abs(right));
|
|
292
|
+
return abs({
|
|
293
|
+
re: left.re - right.re,
|
|
294
|
+
im: left.im - right.im
|
|
295
|
+
}) < 1e-9 * scale;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* The angular frequency at which an inductor and a capacitor cancel exactly.
|
|
299
|
+
*
|
|
300
|
+
* ωL = 1/(ωC) so ω₀ = 1/√(LC)
|
|
301
|
+
*
|
|
302
|
+
* At ω₀ a series LC pair has zero net reactance, so a series RLC looks purely resistive and the
|
|
303
|
+
* current is at a maximum. That is the whole of tuning: a radio picks one station by making its
|
|
304
|
+
* circuit resonate there and nowhere else.
|
|
305
|
+
*/
|
|
306
|
+
function resonantOmega(henries, farads) {
|
|
307
|
+
return 1 / Math.sqrt(finitePositive(henries, "inductance") * finitePositive(farads, "capacitance"));
|
|
308
|
+
}
|
|
309
|
+
/** Resonance in hertz, which is what a dial is marked in. */
|
|
310
|
+
const resonantHz = (henries, farads) => resonantOmega(henries, farads) / (2 * Math.PI);
|
|
311
|
+
/**
|
|
312
|
+
* The quality factor of a series RLC: how sharply it selects its resonant frequency.
|
|
313
|
+
*
|
|
314
|
+
* Q = (1/R)·√(L/C)
|
|
315
|
+
*
|
|
316
|
+
* A high Q is a narrow peak, which is a radio that separates adjacent stations. Resistance is what
|
|
317
|
+
* spoils it, because resistance is the only part that takes energy out of the oscillation.
|
|
318
|
+
*/
|
|
319
|
+
function qualityFactor(ohms, henries, farads) {
|
|
320
|
+
const r = finitePositive(ohms, "resistance");
|
|
321
|
+
return Math.sqrt(finitePositive(henries, "inductance") / finitePositive(farads, "capacitance")) / r;
|
|
322
|
+
}
|
|
323
|
+
/** The width of the resonance peak between its half-power points, in rad/s. */
|
|
324
|
+
const bandwidthRadPerS = (ohms, henries, farads) => resonantOmega(henries, farads) / qualityFactor(ohms, henries, farads);
|
|
325
|
+
/** How a network responds to a sinusoid of a given peak voltage at one frequency. */
|
|
326
|
+
function responseAt(network, omegaRadPerS, drivePeakV = 1) {
|
|
327
|
+
/**
|
|
328
|
+
* Uses the GENERAL solver, not the reducer.
|
|
329
|
+
*
|
|
330
|
+
* A frequency response is not a teaching narrative, it is an answer, and an unbalanced bridge has
|
|
331
|
+
* one even though series and parallel cannot find it. Reaching for the reducer here would make
|
|
332
|
+
* whole families of perfectly ordinary circuits unplottable.
|
|
333
|
+
*/
|
|
334
|
+
const impedance = impedanceByNodalAnalysis(network, omegaRadPerS);
|
|
335
|
+
if (!impedance) return null;
|
|
336
|
+
const magnitudeOhm = abs(impedance);
|
|
337
|
+
const drive = finiteNonNegative(drivePeakV, "driving voltage");
|
|
338
|
+
return {
|
|
339
|
+
omegaRadPerS,
|
|
340
|
+
impedance,
|
|
341
|
+
magnitudeOhm,
|
|
342
|
+
phaseDeg: argDeg(impedance),
|
|
343
|
+
currentAmp: magnitudeOhm > 1e-12 && Number.isFinite(magnitudeOhm) ? drive / magnitudeOhm : 0,
|
|
344
|
+
currentPhaseDeg: -argDeg(impedance)
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* A frequency sweep, spaced logarithmically.
|
|
349
|
+
*
|
|
350
|
+
* Log spacing is not a presentation choice. A response that matters over four decades has almost
|
|
351
|
+
* all of its structure in the first decade, and a linear sweep spends 90% of its points on the last
|
|
352
|
+
* one, where nothing happens. Every instrument that measures this sweeps logarithmically.
|
|
353
|
+
*/
|
|
354
|
+
function sweep(network, omegaFrom, omegaTo, points = 120, drivePeakV = 1) {
|
|
355
|
+
const from = finitePositive(omegaFrom, "start frequency");
|
|
356
|
+
const to = finitePositive(omegaTo, "end frequency");
|
|
357
|
+
if (to <= from) throw new RangeError("the sweep must end above where it started");
|
|
358
|
+
const n = Math.max(2, Math.floor(points));
|
|
359
|
+
const out = [];
|
|
360
|
+
for (let i = 0; i < n; i++) {
|
|
361
|
+
const response = responseAt(network, from * (to / from) ** (i / (n - 1)), drivePeakV);
|
|
362
|
+
if (response) out.push(response);
|
|
363
|
+
}
|
|
364
|
+
return out;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* The power factor, cos φ.
|
|
368
|
+
*
|
|
369
|
+
* Only the resistance dissipates energy. A purely reactive component takes energy in for a quarter
|
|
370
|
+
* cycle and gives every joule back in the next, so it carries current and consumes nothing. A
|
|
371
|
+
* factory with a poor power factor pays for current it never turns into anything, which is why
|
|
372
|
+
* power factor correction is a real industrial expense rather than a textbook curiosity.
|
|
373
|
+
*/
|
|
374
|
+
const powerFactor = (z) => {
|
|
375
|
+
const m = abs(z);
|
|
376
|
+
return m < 1e-12 ? 1 : z.re / m;
|
|
377
|
+
};
|
|
378
|
+
/** Average power actually dissipated, from RMS current: only the real part counts. */
|
|
379
|
+
const realPowerW = (z, rmsCurrentAmp) => finiteNonNegative(rmsCurrentAmp, "current") ** 2 * z.re;
|
|
380
|
+
/** Apparent power, which is what the supply has to be sized for: |Z| I². */
|
|
381
|
+
const apparentPowerVA = (z, rmsCurrentAmp) => finiteNonNegative(rmsCurrentAmp, "current") ** 2 * abs(z);
|
|
382
|
+
/** RMS is the peak divided by root two, for a sinusoid and for nothing else. */
|
|
383
|
+
const rmsFromPeak = (peak) => finiteNonNegative(peak, "peak") / Math.SQRT2;
|
|
384
|
+
/** A series RLC between A and B, the circuit every resonance question is about. */
|
|
385
|
+
function seriesRlc(ohms, henries, farads) {
|
|
386
|
+
return {
|
|
387
|
+
terminals: ["A", "B"],
|
|
388
|
+
elements: [
|
|
389
|
+
{
|
|
390
|
+
id: "R",
|
|
391
|
+
kind: "R",
|
|
392
|
+
value: ohms,
|
|
393
|
+
a: "A",
|
|
394
|
+
b: "M"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
id: "L",
|
|
398
|
+
kind: "L",
|
|
399
|
+
value: henries,
|
|
400
|
+
a: "M",
|
|
401
|
+
b: "N"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
id: "C",
|
|
405
|
+
kind: "C",
|
|
406
|
+
value: farads,
|
|
407
|
+
a: "N",
|
|
408
|
+
b: "B"
|
|
409
|
+
}
|
|
410
|
+
]
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/** A first-order RC low-pass: output taken across the capacitor. */
|
|
414
|
+
function rcLowPass(ohms, farads) {
|
|
415
|
+
return {
|
|
416
|
+
terminals: ["A", "B"],
|
|
417
|
+
elements: [{
|
|
418
|
+
id: "R",
|
|
419
|
+
kind: "R",
|
|
420
|
+
value: ohms,
|
|
421
|
+
a: "A",
|
|
422
|
+
b: "M"
|
|
423
|
+
}, {
|
|
424
|
+
id: "C",
|
|
425
|
+
kind: "C",
|
|
426
|
+
value: farads,
|
|
427
|
+
a: "M",
|
|
428
|
+
b: "B"
|
|
429
|
+
}]
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
/** The −3 dB corner of a first-order RC, where |Z_C| = R and the output has fallen to 1/√2. */
|
|
433
|
+
const rcCornerOmega = (ohms, farads) => 1 / (finitePositive(ohms, "resistance") * finitePositive(farads, "capacitance"));
|
|
434
|
+
/**
|
|
435
|
+
* The transfer function of a two-element divider: what fraction of the input appears across the
|
|
436
|
+
* second element, as a complex number carrying both size and phase shift.
|
|
437
|
+
*
|
|
438
|
+
* This is the potential divider again, with complex numbers, and recognising that is most of what
|
|
439
|
+
* makes filters approachable.
|
|
440
|
+
*/
|
|
441
|
+
function dividerGain(zSeries, zShunt) {
|
|
442
|
+
const total = add(zSeries, zShunt);
|
|
443
|
+
if (abs(total) < 1e-12) return cx(0, 0);
|
|
444
|
+
return div(zShunt, total);
|
|
445
|
+
}
|
|
446
|
+
/** Gain expressed in decibels, which is how every frequency response is actually plotted. */
|
|
447
|
+
const decibels = (gain) => gain <= 0 ? -Infinity : 20 * Math.log10(gain);
|
|
448
|
+
/** Multiply two complex numbers, re-exported so a caller need not import the maths kernel too. */
|
|
449
|
+
const timesC = mul;
|
|
450
|
+
|
|
451
|
+
//#endregion
|
|
452
|
+
export { TINY, apparentPowerVA, bandwidthRadPerS, bridgeBalances, decibels, dividerGain, equivalentImpedance, impedanceByNodalAnalysis, impedanceOf, magnitude, parallelImpedance, phaseDeg, powerFactor, qualityFactor, rcCornerOmega, rcLowPass, reactance, realPowerW, resistance, resonantHz, resonantOmega, responseAt, rmsFromPeak, seriesImpedance, seriesRlc, sweep, timesC };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region src/circuit/dc.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @classytic/stage/circuit/dc, a small, dependency-free circuit-solver kernel
|
|
4
|
+
* (a mini-SPICE) built on Modified Nodal Analysis (MNA). Like the `field` and `math`
|
|
5
|
+
* kernels it is pure, deterministic engine machinery: you describe a netlist of
|
|
6
|
+
* elements (resistors, sources, capacitors, inductors) and it returns the node
|
|
7
|
+
* voltages and branch currents, the correct numbers, so a current-electricity
|
|
8
|
+
* lab shows real results instead of hand-rolled per-lab arithmetic.
|
|
9
|
+
*
|
|
10
|
+
* • solveDC , DC operating point (capacitors open, inductors short).
|
|
11
|
+
* • solveTransient, time-stepped response (RC / RL / RLC) via Backward-Euler
|
|
12
|
+
* companion models: each reactive element becomes a
|
|
13
|
+
* conductance Geq in parallel with a current source Ieq each
|
|
14
|
+
* step, exactly how real simulators integrate the ODEs.
|
|
15
|
+
*
|
|
16
|
+
* Node 0 is ground (the reference). MNA stamps are additive, so parallel elements
|
|
17
|
+
* just sum. Nonlinear devices (diodes / transistors via Newton-Raphson) are the
|
|
18
|
+
* next layer and slot into the same stamping helpers.
|
|
19
|
+
*
|
|
20
|
+
* Conventions (validated against the MNA / Qucs companion-model references):
|
|
21
|
+
* • Resistor R between (n1,n2): conductance g = 1/R.
|
|
22
|
+
* • Current source I: drives `value` amps from n1 to n2 (injected into n2).
|
|
23
|
+
* • Voltage source V: value volts, n1 is + relative to n2 (adds a branch current
|
|
24
|
+
* unknown). Its solved current is positive flowing n1 → n2 inside the source.
|
|
25
|
+
*/
|
|
26
|
+
type NodeId = number;
|
|
27
|
+
interface Elem {
|
|
28
|
+
kind: 'R' | 'V' | 'I' | 'C' | 'L' | 'D' | 'M';
|
|
29
|
+
/** diode: n1=anode, n2=cathode. NMOS 'M': n1=drain, n2=source, n3=gate. */
|
|
30
|
+
n1: NodeId;
|
|
31
|
+
n2: NodeId;
|
|
32
|
+
/** gate node for an NMOS 'M'. */
|
|
33
|
+
n3?: NodeId;
|
|
34
|
+
/** ohms (R) / volts (V) / amps (I) / farads (C) / henries (L). Ignored for D / M. */
|
|
35
|
+
value: number;
|
|
36
|
+
/** diode saturation current Is (default 1e-12 A). */
|
|
37
|
+
is?: number;
|
|
38
|
+
/** diode ideality factor n (default 1). */
|
|
39
|
+
nIdeal?: number;
|
|
40
|
+
/** MOSFET threshold voltage Vth (default 2 V; for a PMOS the magnitude is used). */
|
|
41
|
+
vth?: number;
|
|
42
|
+
/** MOSFET transconductance parameter k = µCox·W/L (default 0.5 A/V²). */
|
|
43
|
+
k?: number;
|
|
44
|
+
/** P-channel MOSFET (conducts when the gate is LOW vs the source). Default NMOS. */
|
|
45
|
+
pmos?: boolean;
|
|
46
|
+
/** optional label, used to key the returned branch currents. */
|
|
47
|
+
id?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Solve A x = b by Gaussian elimination with partial pivoting. Returns null if singular. */
|
|
50
|
+
declare function solveLinear(A: number[][], b: number[]): number[] | null;
|
|
51
|
+
interface DCResult {
|
|
52
|
+
/** node voltages indexed by node id; [0] is ground = 0. */
|
|
53
|
+
nodeV: number[];
|
|
54
|
+
/** current through each branch element (V sources, and inductors), keyed by id. */
|
|
55
|
+
current: Record<string, number>;
|
|
56
|
+
ok: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** DC operating point: capacitors open, inductors short. Routes to the nonlinear solver for diodes / MOSFETs. */
|
|
59
|
+
declare function solveDC(elems: readonly Elem[]): DCResult;
|
|
60
|
+
/**
|
|
61
|
+
* Nonlinear DC via Newton-Raphson: each iteration linearizes every nonlinear device
|
|
62
|
+
* (diode Shockley with pnjlim limiting; NMOS square-law about the previous node
|
|
63
|
+
* voltages) into a companion conductance + current source, solves the linear system,
|
|
64
|
+
* and repeats until the solution settles.
|
|
65
|
+
*/
|
|
66
|
+
declare function solveDCNonlinear(elems: readonly Elem[], opts?: {
|
|
67
|
+
maxIter?: number;
|
|
68
|
+
tol?: number;
|
|
69
|
+
}): DCResult;
|
|
70
|
+
/** Current through an element given solved node voltages (R/I directly; C/L need state). */
|
|
71
|
+
declare function elementCurrent(e: Elem, nodeV: number[]): number;
|
|
72
|
+
interface TransientStep {
|
|
73
|
+
t: number;
|
|
74
|
+
nodeV: number[];
|
|
75
|
+
}
|
|
76
|
+
interface TransientOpts {
|
|
77
|
+
dt: number;
|
|
78
|
+
steps: number;
|
|
79
|
+
/** initial voltages across reactive elements, keyed by element index (default 0). */
|
|
80
|
+
initialV?: Map<number, number>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Time-stepped transient (Backward Euler). Returns the node-voltage trajectory,
|
|
84
|
+
* including t = 0. Reactive elements use companion models rebuilt every step.
|
|
85
|
+
*/
|
|
86
|
+
declare function solveTransient(elems: readonly Elem[], opts: TransientOpts): TransientStep[];
|
|
87
|
+
/** Equivalent resistance of resistors in series. */
|
|
88
|
+
declare function seriesR(...rs: number[]): number;
|
|
89
|
+
/** Equivalent resistance of resistors in parallel. */
|
|
90
|
+
declare function parallelR(...rs: number[]): number;
|
|
91
|
+
//#endregion
|
|
92
|
+
export { DCResult, Elem, NodeId, TransientOpts, TransientStep, elementCurrent, parallelR, seriesR, solveDC, solveDCNonlinear, solveLinear, solveTransient };
|