@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,103 @@
|
|
|
1
|
+
import { Worked } from "../core/worked.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/waves/springs.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Hooke's law: the force a spring exerts at a given extension, newtons.
|
|
6
|
+
*
|
|
7
|
+
* SIGNED, and the sign is the point: stretch a spring in the positive
|
|
8
|
+
* direction and it pulls back in the negative one. Returning |kx| would lose
|
|
9
|
+
* exactly the fact that makes the motion periodic.
|
|
10
|
+
*
|
|
11
|
+
* Valid up to the limit of proportionality. Past that a real spring keeps
|
|
12
|
+
* stretching for less force and eventually does not come back, which is
|
|
13
|
+
* `@classytic/stage/physics`'s stress-strain territory rather than this one.
|
|
14
|
+
*/
|
|
15
|
+
declare const springForce: (stiffness: number, extension: number) => number;
|
|
16
|
+
/** The extension a given force produces, metres: x = F/k. Takes the magnitude. */
|
|
17
|
+
declare const springExtension: (stiffness: number, force: number) => number;
|
|
18
|
+
/**
|
|
19
|
+
* The stiffness of a spring, from how far a hanging mass stretches it:
|
|
20
|
+
* k = mg/e.
|
|
21
|
+
*
|
|
22
|
+
* This is how k is actually MEASURED, and it is the first line of most spring
|
|
23
|
+
* questions: you are told a 200 g mass stretches the spring by 10 cm, and the
|
|
24
|
+
* 19.6 N/m you need is not given to you.
|
|
25
|
+
*
|
|
26
|
+
* `extension` is the extra length caused by hanging the mass, not the length of
|
|
27
|
+
* the spring.
|
|
28
|
+
*/
|
|
29
|
+
declare const stiffnessFromExtension: (mass: number, extension: number, gravity?: number) => number;
|
|
30
|
+
/** How far a hanging mass stretches a spring, metres: e = mg/k. The inverse of the above. */
|
|
31
|
+
declare const staticExtension: (mass: number, stiffness: number, gravity?: number) => number;
|
|
32
|
+
/**
|
|
33
|
+
* The period of a hanging mass, from the extension it causes: T = 2π√(e/g).
|
|
34
|
+
*
|
|
35
|
+
* The MASS HAS CANCELLED, and that is worth stopping on. Substituting k = mg/e
|
|
36
|
+
* into T = 2π√(m/k) removes m entirely, so a spring stretched 10 cm by whatever
|
|
37
|
+
* is hanging on it has a period of 0.63 s whatever that thing weighs. Hang
|
|
38
|
+
* twice the mass: it stretches twice as far, and the period is the same.
|
|
39
|
+
*
|
|
40
|
+
* It is the same cancellation that makes a pendulum period massless, arrived at
|
|
41
|
+
* from the other direction, and it turns a two-step question into one line.
|
|
42
|
+
*/
|
|
43
|
+
declare const springPeriodFromExtension: (extension: number, gravity?: number) => number;
|
|
44
|
+
/**
|
|
45
|
+
* Stiffness from the oscillation it produces: k = mω².
|
|
46
|
+
*
|
|
47
|
+
* The bridge back from `shm` to this module, and the reason a differential
|
|
48
|
+
* equation like `4·d²x/dt² + 100x = 0` can be read off directly: it is
|
|
49
|
+
* m·x'' + k·x = 0 with m = 4 and k = 100, so ω = √(k/m) = 5 rad/s. Nothing has
|
|
50
|
+
* to be solved.
|
|
51
|
+
*/
|
|
52
|
+
declare const stiffnessFromAngularFrequency: (mass: number, omega: number) => number;
|
|
53
|
+
/**
|
|
54
|
+
* Springs end to end: 1/k = 1/k₁ + 1/k₂ + …
|
|
55
|
+
*
|
|
56
|
+
* The combination is SOFTER than either spring alone, which is the result that
|
|
57
|
+
* surprises people. Both springs carry the whole load, and both stretch, so the
|
|
58
|
+
* extensions add while the force does not: more give for the same pull.
|
|
59
|
+
*
|
|
60
|
+
* Note this is the resistor rule upside down, because stiffness is the
|
|
61
|
+
* spring's opposition to stretching, so it plays the part of conductance.
|
|
62
|
+
* Anyone who has met resistors first tends to import the wrong one of the two
|
|
63
|
+
* formulas, which is precisely why both are named here rather than left to be
|
|
64
|
+
* remembered.
|
|
65
|
+
*/
|
|
66
|
+
declare function stiffnessInSeries(...stiffnesses: number[]): number;
|
|
67
|
+
/**
|
|
68
|
+
* Springs side by side: k = k₁ + k₂ + …
|
|
69
|
+
*
|
|
70
|
+
* STIFFER than either alone. They share the load and stretch together, so the
|
|
71
|
+
* forces add at a common extension. A car sits on four of these.
|
|
72
|
+
*/
|
|
73
|
+
declare function stiffnessInParallel(...stiffnesses: number[]): number;
|
|
74
|
+
/**
|
|
75
|
+
* The stiffness of a PIECE of a spring, given what fraction of the original
|
|
76
|
+
* length it is: k' = k / fraction.
|
|
77
|
+
*
|
|
78
|
+
* Stiffness goes as 1/length. Half a spring is twice as stiff, a third of a
|
|
79
|
+
* spring three times as stiff. The reason is that every coil stretches by the
|
|
80
|
+
* same amount under a given load, so fewer coils give less total extension for
|
|
81
|
+
* the same force.
|
|
82
|
+
*
|
|
83
|
+
* The check that this is right and not backwards: the pieces put back in series
|
|
84
|
+
* must return the original spring, and `springs.test.ts` asserts exactly that.
|
|
85
|
+
*/
|
|
86
|
+
declare function cutSpringStiffness(stiffness: number, lengthFraction: number): number;
|
|
87
|
+
/**
|
|
88
|
+
* Cut a spring into pieces in a given ratio, returning each piece's stiffness.
|
|
89
|
+
*
|
|
90
|
+
* `splitSpringStiffness(60, [1, 2])` cuts a 60 N/m spring in the ratio 1:2 and
|
|
91
|
+
* gives [180, 90]: the short piece is the stiff one. The ratio is taken as
|
|
92
|
+
* lengths, and needs no normalising.
|
|
93
|
+
*/
|
|
94
|
+
declare function splitSpringStiffness(stiffness: number, ratio: readonly number[]): number[];
|
|
95
|
+
/**
|
|
96
|
+
* The stiffness question worked: measure the extension, get k, get the period.
|
|
97
|
+
*
|
|
98
|
+
* Both routes to the period are shown, because they must agree and a learner
|
|
99
|
+
* who has only ever seen T = 2π√(m/k) does not expect the mass to drop out.
|
|
100
|
+
*/
|
|
101
|
+
declare function stiffnessFromExtensionSteps(mass: number, extension: number, gravity?: number, sf?: number): Worked;
|
|
102
|
+
//#endregion
|
|
103
|
+
export { cutSpringStiffness, splitSpringStiffness, springExtension, springForce, springPeriodFromExtension, staticExtension, stiffnessFromAngularFrequency, stiffnessFromExtension, stiffnessFromExtensionSteps, stiffnessInParallel, stiffnessInSeries };
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { calc, texSigFigs } from "../core/worked.mjs";
|
|
2
|
+
import { G_EARTH } from "../physics/kinematics/free-fall.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/waves/springs.ts
|
|
5
|
+
/**
|
|
6
|
+
* Real springs: stiffness, and where a number for it comes from.
|
|
7
|
+
*
|
|
8
|
+
* ## Why this is separate from `shm`
|
|
9
|
+
*
|
|
10
|
+
* `shm` takes ω as given and describes the motion. This module is about
|
|
11
|
+
* everything that happens BEFORE that: a spring arrives as a coil with a
|
|
12
|
+
* length, and a question gives you a hanging mass, or two springs bolted
|
|
13
|
+
* together, or a spring that has been cut in half. Each of those is an
|
|
14
|
+
* arithmetic step that produces the k which `shm` then uses.
|
|
15
|
+
*
|
|
16
|
+
* Keeping them apart matters because the mistakes live here. A learner who can
|
|
17
|
+
* quote T = 2π√(m/k) still loses the mark by adding two stiffnesses that were
|
|
18
|
+
* in series.
|
|
19
|
+
*
|
|
20
|
+
* ## The one relation everything else follows from
|
|
21
|
+
*
|
|
22
|
+
* F = −kx
|
|
23
|
+
*
|
|
24
|
+
* The minus sign is the physics: the force points BACK towards the natural
|
|
25
|
+
* length, which is what makes the motion oscillate rather than run away. Drop
|
|
26
|
+
* it and you have described a spring that throws things.
|
|
27
|
+
*
|
|
28
|
+
* ## Stiffness is not a property of the material
|
|
29
|
+
*
|
|
30
|
+
* It is a property of the material AND the geometry. Half a spring is twice as
|
|
31
|
+
* stiff, because each coil now carries the same force over half as much give.
|
|
32
|
+
* That is `cutSpringStiffness`, and it is the step that makes the classic
|
|
33
|
+
* "a spring is cut in the ratio 1:2" question tractable rather than magic.
|
|
34
|
+
*
|
|
35
|
+
* ## Units
|
|
36
|
+
*
|
|
37
|
+
* SI. Stiffness in newtons per metre, extension in metres, mass in kilograms,
|
|
38
|
+
* force in newtons.
|
|
39
|
+
*/
|
|
40
|
+
const finite = (value, what) => {
|
|
41
|
+
if (!Number.isFinite(value)) throw new RangeError(`${what} must be a finite number.`);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
const positive = (value, what) => {
|
|
45
|
+
if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${what} must be positive.`);
|
|
46
|
+
return value;
|
|
47
|
+
};
|
|
48
|
+
const everyPositive = (values, what) => {
|
|
49
|
+
if (values.length === 0) throw new RangeError(`${what} needs at least one spring.`);
|
|
50
|
+
for (const value of values) positive(value, what);
|
|
51
|
+
return values;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Hooke's law: the force a spring exerts at a given extension, newtons.
|
|
55
|
+
*
|
|
56
|
+
* SIGNED, and the sign is the point: stretch a spring in the positive
|
|
57
|
+
* direction and it pulls back in the negative one. Returning |kx| would lose
|
|
58
|
+
* exactly the fact that makes the motion periodic.
|
|
59
|
+
*
|
|
60
|
+
* Valid up to the limit of proportionality. Past that a real spring keeps
|
|
61
|
+
* stretching for less force and eventually does not come back, which is
|
|
62
|
+
* `@classytic/stage/physics`'s stress-strain territory rather than this one.
|
|
63
|
+
*/
|
|
64
|
+
const springForce = (stiffness, extension) => -positive(stiffness, "A spring stiffness") * finite(extension, "An extension");
|
|
65
|
+
/** The extension a given force produces, metres: x = F/k. Takes the magnitude. */
|
|
66
|
+
const springExtension = (stiffness, force) => Math.abs(finite(force, "A force")) / positive(stiffness, "A spring stiffness");
|
|
67
|
+
/**
|
|
68
|
+
* The stiffness of a spring, from how far a hanging mass stretches it:
|
|
69
|
+
* k = mg/e.
|
|
70
|
+
*
|
|
71
|
+
* This is how k is actually MEASURED, and it is the first line of most spring
|
|
72
|
+
* questions: you are told a 200 g mass stretches the spring by 10 cm, and the
|
|
73
|
+
* 19.6 N/m you need is not given to you.
|
|
74
|
+
*
|
|
75
|
+
* `extension` is the extra length caused by hanging the mass, not the length of
|
|
76
|
+
* the spring.
|
|
77
|
+
*/
|
|
78
|
+
const stiffnessFromExtension = (mass, extension, gravity = G_EARTH) => positive(mass, "A mass") * positive(gravity, "A gravitational field strength") / positive(extension, "An extension");
|
|
79
|
+
/** How far a hanging mass stretches a spring, metres: e = mg/k. The inverse of the above. */
|
|
80
|
+
const staticExtension = (mass, stiffness, gravity = G_EARTH) => positive(mass, "A mass") * positive(gravity, "A gravitational field strength") / positive(stiffness, "A spring stiffness");
|
|
81
|
+
/**
|
|
82
|
+
* The period of a hanging mass, from the extension it causes: T = 2π√(e/g).
|
|
83
|
+
*
|
|
84
|
+
* The MASS HAS CANCELLED, and that is worth stopping on. Substituting k = mg/e
|
|
85
|
+
* into T = 2π√(m/k) removes m entirely, so a spring stretched 10 cm by whatever
|
|
86
|
+
* is hanging on it has a period of 0.63 s whatever that thing weighs. Hang
|
|
87
|
+
* twice the mass: it stretches twice as far, and the period is the same.
|
|
88
|
+
*
|
|
89
|
+
* It is the same cancellation that makes a pendulum period massless, arrived at
|
|
90
|
+
* from the other direction, and it turns a two-step question into one line.
|
|
91
|
+
*/
|
|
92
|
+
const springPeriodFromExtension = (extension, gravity = G_EARTH) => 2 * Math.PI * Math.sqrt(positive(extension, "An extension") / positive(gravity, "A gravitational field strength"));
|
|
93
|
+
/**
|
|
94
|
+
* Stiffness from the oscillation it produces: k = mω².
|
|
95
|
+
*
|
|
96
|
+
* The bridge back from `shm` to this module, and the reason a differential
|
|
97
|
+
* equation like `4·d²x/dt² + 100x = 0` can be read off directly: it is
|
|
98
|
+
* m·x'' + k·x = 0 with m = 4 and k = 100, so ω = √(k/m) = 5 rad/s. Nothing has
|
|
99
|
+
* to be solved.
|
|
100
|
+
*/
|
|
101
|
+
const stiffnessFromAngularFrequency = (mass, omega) => positive(mass, "A mass") * positive(omega, "An angular frequency") ** 2;
|
|
102
|
+
/**
|
|
103
|
+
* Springs end to end: 1/k = 1/k₁ + 1/k₂ + …
|
|
104
|
+
*
|
|
105
|
+
* The combination is SOFTER than either spring alone, which is the result that
|
|
106
|
+
* surprises people. Both springs carry the whole load, and both stretch, so the
|
|
107
|
+
* extensions add while the force does not: more give for the same pull.
|
|
108
|
+
*
|
|
109
|
+
* Note this is the resistor rule upside down, because stiffness is the
|
|
110
|
+
* spring's opposition to stretching, so it plays the part of conductance.
|
|
111
|
+
* Anyone who has met resistors first tends to import the wrong one of the two
|
|
112
|
+
* formulas, which is precisely why both are named here rather than left to be
|
|
113
|
+
* remembered.
|
|
114
|
+
*/
|
|
115
|
+
function stiffnessInSeries(...stiffnesses) {
|
|
116
|
+
everyPositive(stiffnesses, "A spring stiffness");
|
|
117
|
+
return 1 / stiffnesses.reduce((sum, k) => sum + 1 / k, 0);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Springs side by side: k = k₁ + k₂ + …
|
|
121
|
+
*
|
|
122
|
+
* STIFFER than either alone. They share the load and stretch together, so the
|
|
123
|
+
* forces add at a common extension. A car sits on four of these.
|
|
124
|
+
*/
|
|
125
|
+
function stiffnessInParallel(...stiffnesses) {
|
|
126
|
+
everyPositive(stiffnesses, "A spring stiffness");
|
|
127
|
+
return stiffnesses.reduce((sum, k) => sum + k, 0);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The stiffness of a PIECE of a spring, given what fraction of the original
|
|
131
|
+
* length it is: k' = k / fraction.
|
|
132
|
+
*
|
|
133
|
+
* Stiffness goes as 1/length. Half a spring is twice as stiff, a third of a
|
|
134
|
+
* spring three times as stiff. The reason is that every coil stretches by the
|
|
135
|
+
* same amount under a given load, so fewer coils give less total extension for
|
|
136
|
+
* the same force.
|
|
137
|
+
*
|
|
138
|
+
* The check that this is right and not backwards: the pieces put back in series
|
|
139
|
+
* must return the original spring, and `springs.test.ts` asserts exactly that.
|
|
140
|
+
*/
|
|
141
|
+
function cutSpringStiffness(stiffness, lengthFraction) {
|
|
142
|
+
const k = positive(stiffness, "A spring stiffness");
|
|
143
|
+
const fraction = positive(lengthFraction, "A length fraction");
|
|
144
|
+
if (fraction > 1) throw new RangeError(`A piece cut from a spring cannot be ${fraction} of its length: a fraction is at most 1.`);
|
|
145
|
+
return k / fraction;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Cut a spring into pieces in a given ratio, returning each piece's stiffness.
|
|
149
|
+
*
|
|
150
|
+
* `splitSpringStiffness(60, [1, 2])` cuts a 60 N/m spring in the ratio 1:2 and
|
|
151
|
+
* gives [180, 90]: the short piece is the stiff one. The ratio is taken as
|
|
152
|
+
* lengths, and needs no normalising.
|
|
153
|
+
*/
|
|
154
|
+
function splitSpringStiffness(stiffness, ratio) {
|
|
155
|
+
const k = positive(stiffness, "A spring stiffness");
|
|
156
|
+
everyPositive(ratio, "A ratio part");
|
|
157
|
+
const total = ratio.reduce((sum, part) => sum + part, 0);
|
|
158
|
+
return ratio.map((part) => cutSpringStiffness(k, part / total));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The stiffness question worked: measure the extension, get k, get the period.
|
|
162
|
+
*
|
|
163
|
+
* Both routes to the period are shown, because they must agree and a learner
|
|
164
|
+
* who has only ever seen T = 2π√(m/k) does not expect the mass to drop out.
|
|
165
|
+
*/
|
|
166
|
+
function stiffnessFromExtensionSteps(mass, extension, gravity = G_EARTH, sf = 3) {
|
|
167
|
+
const m = positive(mass, "A mass");
|
|
168
|
+
const e = positive(extension, "An extension");
|
|
169
|
+
const g = positive(gravity, "A gravitational field strength");
|
|
170
|
+
const k = stiffnessFromExtension(m, e, g);
|
|
171
|
+
const period = 2 * Math.PI * Math.sqrt(m / k);
|
|
172
|
+
return calc().step("kx = mg", "at rest the spring force balances the weight, so the extension measures k").step(`k = \\frac{mg}{e} = \\frac{${texSigFigs(m, sf)} \\times ${texSigFigs(g, sf)}}{${texSigFigs(e, sf)}} = ${texSigFigs(k, sf)}\\ \\mathrm{N\\,m^{-1}}`).step(`T = 2\\pi\\sqrt{\\frac{m}{k}} = ${texSigFigs(period, sf)}\\ \\mathrm{s}`, "the usual route, which needs the k we just found").step(`T = 2\\pi\\sqrt{\\frac{e}{g}} = ${texSigFigs(springPeriodFromExtension(e, g), sf)}\\ \\mathrm{s}`, "substituting k = mg/e cancels the mass entirely: the extension alone fixes the period").done(k);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
//#endregion
|
|
176
|
+
export { cutSpringStiffness, splitSpringStiffness, springExtension, springForce, springPeriodFromExtension, staticExtension, stiffnessFromAngularFrequency, stiffnessFromExtension, stiffnessFromExtensionSteps, stiffnessInParallel, stiffnessInSeries };
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Wave } from "./wave.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/waves/superposition.d.ts
|
|
4
|
+
/** The sum of several waves at a point and time, by the principle of superposition. */
|
|
5
|
+
declare function superpose(waves: readonly Wave[], x: number, t: number): number;
|
|
6
|
+
/**
|
|
7
|
+
* Displacement of a standing wave: y = 2A·sin(kx)·cos(ωt).
|
|
8
|
+
*
|
|
9
|
+
* `amplitude` is that of EACH travelling wave, so the antinodes swing to twice
|
|
10
|
+
* it. That doubling is the part worth keeping explicit: a standing wave is
|
|
11
|
+
* built from two waves and its antinodes are louder than either.
|
|
12
|
+
*/
|
|
13
|
+
declare function standingWave(amplitude: number, wavelength: number, frequency: number, x: number, t: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* How a string or pipe can vibrate.
|
|
16
|
+
*
|
|
17
|
+
* `both-ends-fixed` is a string, and also a pipe closed at both ends.
|
|
18
|
+
* `both-ends-open` is an open pipe: antinodes at each end, same wavelengths as
|
|
19
|
+
* the string. `one-end-open` is a closed pipe, and it is the odd one out.
|
|
20
|
+
*/
|
|
21
|
+
type BoundaryKind = 'both-ends-fixed' | 'both-ends-open' | 'one-end-open';
|
|
22
|
+
/**
|
|
23
|
+
* The wavelength of harmonic n, metres.
|
|
24
|
+
*
|
|
25
|
+
* A string fixed at both ends fits a whole number of HALF wavelengths, so
|
|
26
|
+
* λ = 2L/n. A pipe closed at one end has a node at the closed end and an
|
|
27
|
+
* antinode at the open one, so it fits an ODD number of QUARTER wavelengths:
|
|
28
|
+
* λ = 4L/n with n odd. That is why a closed pipe sounds an octave lower than an
|
|
29
|
+
* open one of the same length and why it is missing its even harmonics, which
|
|
30
|
+
* is most of what makes a clarinet sound like a clarinet.
|
|
31
|
+
*/
|
|
32
|
+
declare function harmonicWavelength(length: number, n: number, boundary?: BoundaryKind): number;
|
|
33
|
+
/** The frequency of harmonic n, Hz, for a wave travelling at `speed`. */
|
|
34
|
+
declare function harmonicFrequency(length: number, n: number, speed: number, boundary?: BoundaryKind): number;
|
|
35
|
+
/** The harmonic numbers a boundary admits, in order, up to `count` of them. */
|
|
36
|
+
declare function harmonicSeries(count: number, boundary?: BoundaryKind): number[];
|
|
37
|
+
/**
|
|
38
|
+
* Node positions on [0, L] for harmonic n, metres.
|
|
39
|
+
*
|
|
40
|
+
* Nodes are where the displacement is always zero. A string fixed at both ends
|
|
41
|
+
* has one at each end, so harmonic n has n + 1 of them.
|
|
42
|
+
*/
|
|
43
|
+
declare function nodePositions(length: number, n: number, boundary?: BoundaryKind): number[];
|
|
44
|
+
/** Antinode positions on [0, L] for harmonic n, metres: halfway between the nodes. */
|
|
45
|
+
declare function antinodePositions(length: number, n: number, boundary?: BoundaryKind): number[];
|
|
46
|
+
/** The distance between adjacent nodes, metres: half a wavelength, always. */
|
|
47
|
+
declare const nodeSpacing: (wavelength: number) => number;
|
|
48
|
+
/**
|
|
49
|
+
* The speed of a wave on a stretched string: v = √(T/μ).
|
|
50
|
+
*
|
|
51
|
+
* `tension` in newtons, `massPerLength` in kg/m. Tightening a string raises its
|
|
52
|
+
* pitch as the square ROOT of the tension, so an octave needs four times the
|
|
53
|
+
* tension, which is why instruments are strung with different gauges rather
|
|
54
|
+
* than tuned by tension alone.
|
|
55
|
+
*/
|
|
56
|
+
declare const stringWaveSpeed: (tension: number, massPerLength: number) => number;
|
|
57
|
+
/**
|
|
58
|
+
* Beat frequency, Hz: |f₁ − f₂|.
|
|
59
|
+
*
|
|
60
|
+
* Heard as a throb rather than as two notes when the difference is small. A
|
|
61
|
+
* piano tuner listens for this going to zero, which is a far more sensitive
|
|
62
|
+
* test than comparing two pitches by ear.
|
|
63
|
+
*/
|
|
64
|
+
declare const beatFrequency: (f1: number, f2: number) => number;
|
|
65
|
+
/**
|
|
66
|
+
* The envelope of a beat pattern at time t, as a fraction of the peak.
|
|
67
|
+
*
|
|
68
|
+
* Two equal tones add to 2A·cos(π·Δf·t)·cos(2π·f̄·t): a fast oscillation at the
|
|
69
|
+
* MEAN frequency inside a slow envelope at half the difference. The loudness
|
|
70
|
+
* peaks twice per envelope cycle, once at each extreme, which is why the beat
|
|
71
|
+
* you HEAR is at |f₁ − f₂| and not at half of it.
|
|
72
|
+
*/
|
|
73
|
+
declare function beatEnvelope(f1: number, f2: number, t: number): number;
|
|
74
|
+
/** The displacement of two superposed tones of equal amplitude at time t. */
|
|
75
|
+
declare function beatDisplacement(amplitude: number, f1: number, f2: number, t: number): number;
|
|
76
|
+
interface TwoSourcePoint {
|
|
77
|
+
/** Distance from the first source, m. */
|
|
78
|
+
r1: number;
|
|
79
|
+
/** Distance from the second source, m. */
|
|
80
|
+
r2: number;
|
|
81
|
+
/** r1 − r2, m. */
|
|
82
|
+
pathDifference: number;
|
|
83
|
+
/** Combined displacement at this instant, for equal sources. */
|
|
84
|
+
displacement: number;
|
|
85
|
+
/** Standing envelope: 1 on a maximum line, 0 on a minimum line. */
|
|
86
|
+
envelope: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Two point sources, in phase, at a point in the plane.
|
|
90
|
+
*
|
|
91
|
+
* The ripple-tank calculation. `envelope` is the part that does not change with
|
|
92
|
+
* time and is therefore what makes the fixed pattern of bright and dark lines:
|
|
93
|
+
* |cos(k·Δr/2)|, one on the constructive lines and zero on the destructive
|
|
94
|
+
* ones. `displacement` is the instantaneous sum, which is what animates.
|
|
95
|
+
*
|
|
96
|
+
* Separating the two is the point. A lab that draws only the instantaneous sum
|
|
97
|
+
* shows a shimmer with no visible structure; the pattern is in the envelope.
|
|
98
|
+
*/
|
|
99
|
+
/**
|
|
100
|
+
* The standing ENVELOPE at a point, from the two path lengths: |cos(k·Δr/2)|.
|
|
101
|
+
*
|
|
102
|
+
* 1 on a constructive line, 0 on a destructive one, and it does not depend on
|
|
103
|
+
* time, which is why the pattern of bright and dark lines holds still.
|
|
104
|
+
*
|
|
105
|
+
* Takes the distances rather than the geometry, and returns a bare number
|
|
106
|
+
* rather than a record, because this is the function a canvas render loop calls
|
|
107
|
+
* once per pixel. `twoSourceField` is the readable version for everything else
|
|
108
|
+
* and is built from this one, so there is still a single formula.
|
|
109
|
+
*/
|
|
110
|
+
declare function twoSourceEnvelope(r1: number, r2: number, wavelength: number): number;
|
|
111
|
+
/** The instantaneous sum at a point, from the two path lengths. The hot-path twin of the above. */
|
|
112
|
+
declare function twoSourceDisplacement(r1: number, r2: number, wavelength: number, frequency: number, t: number, amplitude?: number): number;
|
|
113
|
+
declare function twoSourceField(source1: {
|
|
114
|
+
x: number;
|
|
115
|
+
y: number;
|
|
116
|
+
}, source2: {
|
|
117
|
+
x: number;
|
|
118
|
+
y: number;
|
|
119
|
+
}, point: {
|
|
120
|
+
x: number;
|
|
121
|
+
y: number;
|
|
122
|
+
}, wavelength: number, frequency: number, t: number, amplitude?: number): TwoSourcePoint;
|
|
123
|
+
//#endregion
|
|
124
|
+
export { BoundaryKind, TwoSourcePoint, antinodePositions, beatDisplacement, beatEnvelope, beatFrequency, harmonicFrequency, harmonicSeries, harmonicWavelength, nodePositions, nodeSpacing, standingWave, stringWaveSpeed, superpose, twoSourceDisplacement, twoSourceEnvelope, twoSourceField };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { angularFrequency, displacement, waveNumber } from "./wave.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/waves/superposition.ts
|
|
4
|
+
/**
|
|
5
|
+
* Superposition: what happens where waves meet.
|
|
6
|
+
*
|
|
7
|
+
* ## One principle, three consequences
|
|
8
|
+
*
|
|
9
|
+
* The principle is that displacements ADD. Everything below is that statement
|
|
10
|
+
* applied to a different pair of waves:
|
|
11
|
+
*
|
|
12
|
+
* two sources, one medium → an interference pattern, fixed in space
|
|
13
|
+
* two waves, opposite ways → a STANDING wave, with nodes that never move
|
|
14
|
+
* two close frequencies → BEATS, a throb at |f₁ − f₂|
|
|
15
|
+
*
|
|
16
|
+
* No new physics enters at any step, which is worth saying because the three
|
|
17
|
+
* are usually taught as three topics.
|
|
18
|
+
*
|
|
19
|
+
* ## The standing wave, and why it stands
|
|
20
|
+
*
|
|
21
|
+
* y = 2A·sin(kx)·cos(ωt)
|
|
22
|
+
*
|
|
23
|
+
* The x and the t have come apart. That separation IS the difference between a
|
|
24
|
+
* standing wave and a travelling one: the shape sin(kx) is fixed in space and
|
|
25
|
+
* only its scale cos(ωt) changes, so the zeros stay put. In a travelling wave
|
|
26
|
+
* the two are locked together inside one bracket and the zeros move along.
|
|
27
|
+
*
|
|
28
|
+
* A standing wave carries no net energy, because it is two equal waves carrying
|
|
29
|
+
* energy in opposite directions.
|
|
30
|
+
*
|
|
31
|
+
* ## Units
|
|
32
|
+
*
|
|
33
|
+
* SI. Lengths in metres, frequencies in hertz, time in seconds.
|
|
34
|
+
*/
|
|
35
|
+
const finite = (value, what) => {
|
|
36
|
+
if (!Number.isFinite(value)) throw new RangeError(`${what} must be a finite number.`);
|
|
37
|
+
return value;
|
|
38
|
+
};
|
|
39
|
+
const positive = (value, what) => {
|
|
40
|
+
if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${what} must be positive.`);
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
43
|
+
const wholeNumber = (value, what) => {
|
|
44
|
+
if (!Number.isInteger(value) || value < 1) throw new RangeError(`${what} must be a whole number of at least 1.`);
|
|
45
|
+
return value;
|
|
46
|
+
};
|
|
47
|
+
/** The sum of several waves at a point and time, by the principle of superposition. */
|
|
48
|
+
function superpose(waves, x, t) {
|
|
49
|
+
return waves.reduce((sum, wave) => sum + displacement(wave, x, t), 0);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Displacement of a standing wave: y = 2A·sin(kx)·cos(ωt).
|
|
53
|
+
*
|
|
54
|
+
* `amplitude` is that of EACH travelling wave, so the antinodes swing to twice
|
|
55
|
+
* it. That doubling is the part worth keeping explicit: a standing wave is
|
|
56
|
+
* built from two waves and its antinodes are louder than either.
|
|
57
|
+
*/
|
|
58
|
+
function standingWave(amplitude, wavelength, frequency, x, t) {
|
|
59
|
+
return 2 * positive(amplitude, "An amplitude") * Math.sin(waveNumber(wavelength) * finite(x, "A position")) * Math.cos(angularFrequency(frequency) * finite(t, "A time"));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The wavelength of harmonic n, metres.
|
|
63
|
+
*
|
|
64
|
+
* A string fixed at both ends fits a whole number of HALF wavelengths, so
|
|
65
|
+
* λ = 2L/n. A pipe closed at one end has a node at the closed end and an
|
|
66
|
+
* antinode at the open one, so it fits an ODD number of QUARTER wavelengths:
|
|
67
|
+
* λ = 4L/n with n odd. That is why a closed pipe sounds an octave lower than an
|
|
68
|
+
* open one of the same length and why it is missing its even harmonics, which
|
|
69
|
+
* is most of what makes a clarinet sound like a clarinet.
|
|
70
|
+
*/
|
|
71
|
+
function harmonicWavelength(length, n, boundary = "both-ends-fixed") {
|
|
72
|
+
const L = positive(length, "A length");
|
|
73
|
+
const order = wholeNumber(n, "A harmonic number");
|
|
74
|
+
if (boundary === "one-end-open") {
|
|
75
|
+
if (order % 2 === 0) throw new RangeError(`A pipe closed at one end has no harmonic ${order}: only the odd harmonics fit, which is why it sounds hollow.`);
|
|
76
|
+
return 4 * L / order;
|
|
77
|
+
}
|
|
78
|
+
return 2 * L / order;
|
|
79
|
+
}
|
|
80
|
+
/** The frequency of harmonic n, Hz, for a wave travelling at `speed`. */
|
|
81
|
+
function harmonicFrequency(length, n, speed, boundary = "both-ends-fixed") {
|
|
82
|
+
return positive(speed, "A wave speed") / harmonicWavelength(length, n, boundary);
|
|
83
|
+
}
|
|
84
|
+
/** The harmonic numbers a boundary admits, in order, up to `count` of them. */
|
|
85
|
+
function harmonicSeries(count, boundary = "both-ends-fixed") {
|
|
86
|
+
const howMany = wholeNumber(count, "A count of harmonics");
|
|
87
|
+
const step = boundary === "one-end-open" ? 2 : 1;
|
|
88
|
+
return Array.from({ length: howMany }, (_, i) => 1 + i * step);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Node positions on [0, L] for harmonic n, metres.
|
|
92
|
+
*
|
|
93
|
+
* Nodes are where the displacement is always zero. A string fixed at both ends
|
|
94
|
+
* has one at each end, so harmonic n has n + 1 of them.
|
|
95
|
+
*/
|
|
96
|
+
function nodePositions(length, n, boundary = "both-ends-fixed") {
|
|
97
|
+
const L = positive(length, "A length");
|
|
98
|
+
const spacing = harmonicWavelength(L, n, boundary) / 2;
|
|
99
|
+
const start = boundary === "both-ends-open" ? spacing / 2 : 0;
|
|
100
|
+
const out = [];
|
|
101
|
+
for (let x = start; x <= L + 1e-9; x += spacing) out.push(Math.min(x, L));
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
/** Antinode positions on [0, L] for harmonic n, metres: halfway between the nodes. */
|
|
105
|
+
function antinodePositions(length, n, boundary = "both-ends-fixed") {
|
|
106
|
+
const L = positive(length, "A length");
|
|
107
|
+
const spacing = harmonicWavelength(L, n, boundary) / 2;
|
|
108
|
+
const start = boundary === "both-ends-open" ? 0 : spacing / 2;
|
|
109
|
+
const out = [];
|
|
110
|
+
for (let x = start; x <= L + 1e-9; x += spacing) out.push(Math.min(x, L));
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** The distance between adjacent nodes, metres: half a wavelength, always. */
|
|
114
|
+
const nodeSpacing = (wavelength) => positive(wavelength, "A wavelength") / 2;
|
|
115
|
+
/**
|
|
116
|
+
* The speed of a wave on a stretched string: v = √(T/μ).
|
|
117
|
+
*
|
|
118
|
+
* `tension` in newtons, `massPerLength` in kg/m. Tightening a string raises its
|
|
119
|
+
* pitch as the square ROOT of the tension, so an octave needs four times the
|
|
120
|
+
* tension, which is why instruments are strung with different gauges rather
|
|
121
|
+
* than tuned by tension alone.
|
|
122
|
+
*/
|
|
123
|
+
const stringWaveSpeed = (tension, massPerLength) => Math.sqrt(positive(tension, "A tension") / positive(massPerLength, "A mass per unit length"));
|
|
124
|
+
/**
|
|
125
|
+
* Beat frequency, Hz: |f₁ − f₂|.
|
|
126
|
+
*
|
|
127
|
+
* Heard as a throb rather than as two notes when the difference is small. A
|
|
128
|
+
* piano tuner listens for this going to zero, which is a far more sensitive
|
|
129
|
+
* test than comparing two pitches by ear.
|
|
130
|
+
*/
|
|
131
|
+
const beatFrequency = (f1, f2) => Math.abs(positive(f1, "A frequency") - positive(f2, "A frequency"));
|
|
132
|
+
/**
|
|
133
|
+
* The envelope of a beat pattern at time t, as a fraction of the peak.
|
|
134
|
+
*
|
|
135
|
+
* Two equal tones add to 2A·cos(π·Δf·t)·cos(2π·f̄·t): a fast oscillation at the
|
|
136
|
+
* MEAN frequency inside a slow envelope at half the difference. The loudness
|
|
137
|
+
* peaks twice per envelope cycle, once at each extreme, which is why the beat
|
|
138
|
+
* you HEAR is at |f₁ − f₂| and not at half of it.
|
|
139
|
+
*/
|
|
140
|
+
function beatEnvelope(f1, f2, t) {
|
|
141
|
+
const difference = positive(f1, "A frequency") - positive(f2, "A frequency");
|
|
142
|
+
return Math.abs(Math.cos(Math.PI * difference * finite(t, "A time")));
|
|
143
|
+
}
|
|
144
|
+
/** The displacement of two superposed tones of equal amplitude at time t. */
|
|
145
|
+
function beatDisplacement(amplitude, f1, f2, t) {
|
|
146
|
+
const A = positive(amplitude, "An amplitude");
|
|
147
|
+
const time = finite(t, "A time");
|
|
148
|
+
return A * Math.sin(2 * Math.PI * positive(f1, "A frequency") * time) + A * Math.sin(2 * Math.PI * positive(f2, "A frequency") * time);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Two point sources, in phase, at a point in the plane.
|
|
152
|
+
*
|
|
153
|
+
* The ripple-tank calculation. `envelope` is the part that does not change with
|
|
154
|
+
* time and is therefore what makes the fixed pattern of bright and dark lines:
|
|
155
|
+
* |cos(k·Δr/2)|, one on the constructive lines and zero on the destructive
|
|
156
|
+
* ones. `displacement` is the instantaneous sum, which is what animates.
|
|
157
|
+
*
|
|
158
|
+
* Separating the two is the point. A lab that draws only the instantaneous sum
|
|
159
|
+
* shows a shimmer with no visible structure; the pattern is in the envelope.
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* The standing ENVELOPE at a point, from the two path lengths: |cos(k·Δr/2)|.
|
|
163
|
+
*
|
|
164
|
+
* 1 on a constructive line, 0 on a destructive one, and it does not depend on
|
|
165
|
+
* time, which is why the pattern of bright and dark lines holds still.
|
|
166
|
+
*
|
|
167
|
+
* Takes the distances rather than the geometry, and returns a bare number
|
|
168
|
+
* rather than a record, because this is the function a canvas render loop calls
|
|
169
|
+
* once per pixel. `twoSourceField` is the readable version for everything else
|
|
170
|
+
* and is built from this one, so there is still a single formula.
|
|
171
|
+
*/
|
|
172
|
+
function twoSourceEnvelope(r1, r2, wavelength) {
|
|
173
|
+
return Math.abs(Math.cos(waveNumber(wavelength) * (r1 - r2) / 2));
|
|
174
|
+
}
|
|
175
|
+
/** The instantaneous sum at a point, from the two path lengths. The hot-path twin of the above. */
|
|
176
|
+
function twoSourceDisplacement(r1, r2, wavelength, frequency, t, amplitude = 1) {
|
|
177
|
+
const k = waveNumber(wavelength);
|
|
178
|
+
const phase = angularFrequency(frequency) * t;
|
|
179
|
+
return amplitude * (Math.sin(k * r1 - phase) + Math.sin(k * r2 - phase));
|
|
180
|
+
}
|
|
181
|
+
function twoSourceField(source1, source2, point, wavelength, frequency, t, amplitude = 1) {
|
|
182
|
+
const A = positive(amplitude, "An amplitude");
|
|
183
|
+
const r1 = Math.hypot(point.x - source1.x, point.y - source1.y);
|
|
184
|
+
const r2 = Math.hypot(point.x - source2.x, point.y - source2.y);
|
|
185
|
+
const time = finite(t, "A time");
|
|
186
|
+
return {
|
|
187
|
+
r1,
|
|
188
|
+
r2,
|
|
189
|
+
pathDifference: r1 - r2,
|
|
190
|
+
displacement: twoSourceDisplacement(r1, r2, wavelength, frequency, time, A),
|
|
191
|
+
envelope: twoSourceEnvelope(r1, r2, wavelength)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
//#endregion
|
|
196
|
+
export { antinodePositions, beatDisplacement, beatEnvelope, beatFrequency, harmonicFrequency, harmonicSeries, harmonicWavelength, nodePositions, nodeSpacing, standingWave, stringWaveSpeed, superpose, twoSourceDisplacement, twoSourceEnvelope, twoSourceField };
|