@classytic/stage 0.2.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/LICENSE +1 -1
- package/README.md +5 -1
- package/dist/_virtual/_rolldown/runtime.mjs +18 -0
- package/dist/assets/index.mjs +0 -1
- 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/builder/Palette.mjs +50 -89
- package/dist/builder/SceneBuilder.mjs +15 -73
- 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 +4 -1
- package/dist/core/index.mjs +4 -1
- package/dist/core/math.d.mts +26 -0
- package/dist/core/math.mjs +37 -0
- 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 +75 -0
- package/dist/finance/bizsim.mjs +296 -0
- package/dist/finance/index.d.mts +95 -0
- package/dist/finance/index.mjs +145 -0
- 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 +9 -8
- package/dist/index.mjs +5 -5
- package/dist/interaction/MovableDot.mjs +19 -0
- package/dist/interaction/useDraggable.mjs +24 -4
- 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 +17 -1
- package/dist/math/calculus.mjs +365 -2
- 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 +9 -23
- package/dist/math/index.mjs +9 -38
- package/dist/math/latex.mjs +10 -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/primitives/Dot.d.mts +2 -15
- package/dist/primitives/Dot.mjs +6 -4
- package/dist/primitives/Grid.d.mts +33 -17
- package/dist/primitives/Grid.mjs +89 -17
- package/dist/primitives/Label.d.mts +1 -14
- package/dist/primitives/Label.mjs +3 -2
- package/dist/primitives/Lines.d.mts +4 -32
- package/dist/primitives/Lines.mjs +10 -8
- package/dist/primitives/Shapes.d.mts +5 -43
- package/dist/primitives/Shapes.mjs +12 -10
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/primitives/props.mjs +31 -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/Scene.d.mts +6 -1
- package/dist/scene/Scene.mjs +15 -40
- 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/view/Stage.mjs +4 -11
- 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 +103 -23
- package/styles.css +125 -8
- package/dist/assets/kit/index.mjs +0 -4
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
//#region src/thermo/processes.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Quasi-static processes on an ideal gas, and the first law along each.
|
|
4
|
+
*
|
|
5
|
+
* THE MODEL. One ideal gas, pV = nRT, with a heat-capacity ratio γ = Cp/Cv. The
|
|
6
|
+
* first law ΔU = Q − W holds on every leg, with the sign convention that W is
|
|
7
|
+
* work done BY the gas and Q is heat added TO it:
|
|
8
|
+
*
|
|
9
|
+
* isothermal T const pV = const W = nRT·ln(V₂/V₁) Q = W ΔU = 0
|
|
10
|
+
* adiabatic Q = 0 pVᵞ = const W = (p₁V₁−p₂V₂)/(γ−1) = −ΔU ΔS = 0
|
|
11
|
+
* isobaric p const V/T = const W = pΔV Q = nCpΔT
|
|
12
|
+
* isochoric V const p/T = const W = 0 Q = ΔU = nCvΔT
|
|
13
|
+
* linear a straight line on the p–V diagram; W is the trapezium area
|
|
14
|
+
*
|
|
15
|
+
* WHY `linear` IS HERE. The four named processes are the ones with closed
|
|
16
|
+
* forms, but the cycles students are actually given are drawn on a p–V diagram
|
|
17
|
+
* with straight legs that are none of them. Without it, the commonest exercise
|
|
18
|
+
* in the topic ("complete the Q, W, ΔU table for A→B→C→A") cannot be expressed
|
|
19
|
+
* at all, and every lab has to compute its own trapezium.
|
|
20
|
+
*
|
|
21
|
+
* THE METHOD. Closed forms wherever one exists, because they are exact and they
|
|
22
|
+
* are what the answer is checked against. `linear` integrates ∫p dV by the
|
|
23
|
+
* trapezium rule over the sampled path, which is EXACT for a straight line
|
|
24
|
+
* rather than merely convergent: the integrand is a first-degree polynomial in
|
|
25
|
+
* V and the trapezium rule is exact to first degree. Q then comes from the
|
|
26
|
+
* first law rather than from a separate formula, which is the only way to keep
|
|
27
|
+
* the three quantities consistent on a path that has no heat-capacity of its
|
|
28
|
+
* own.
|
|
29
|
+
*
|
|
30
|
+
* UNITS: SI. Pressure in pascals, volume in m³, temperature in kelvin, energy
|
|
31
|
+
* in joules, entropy in J/K.
|
|
32
|
+
*/
|
|
33
|
+
type ProcessKind = 'isothermal' | 'adiabatic' | 'isobaric' | 'isochoric' | 'linear';
|
|
34
|
+
interface GasState {
|
|
35
|
+
/** Pressure, Pa. */
|
|
36
|
+
P: number;
|
|
37
|
+
/** Volume, m³. */
|
|
38
|
+
V: number;
|
|
39
|
+
/** Temperature, K. */
|
|
40
|
+
T: number;
|
|
41
|
+
/** Amount, mol. */
|
|
42
|
+
n: number;
|
|
43
|
+
}
|
|
44
|
+
interface ProcessResult {
|
|
45
|
+
kind: ProcessKind;
|
|
46
|
+
start: GasState;
|
|
47
|
+
end: GasState;
|
|
48
|
+
/** Sampled states from start to end, for drawing the p–V curve. */
|
|
49
|
+
path: GasState[];
|
|
50
|
+
/** Work done BY the gas, J ( = ∫p dV, the area under the p–V curve). */
|
|
51
|
+
W: number;
|
|
52
|
+
/** Heat added TO the gas, J. */
|
|
53
|
+
Q: number;
|
|
54
|
+
/** Change in internal energy, J ( = nCvΔT). */
|
|
55
|
+
dU: number;
|
|
56
|
+
/** Change in entropy, J/K. */
|
|
57
|
+
dS: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run one quasi-static process from `start` to a target.
|
|
61
|
+
*
|
|
62
|
+
* Give exactly one target coordinate the process can reach: a target volume for
|
|
63
|
+
* an isothermal or adiabatic expansion, a target temperature for isobaric or
|
|
64
|
+
* isochoric heating. `linear` is the exception and needs a full end state,
|
|
65
|
+
* since a straight line on the p–V diagram is fixed by its two ends and by
|
|
66
|
+
* nothing less.
|
|
67
|
+
*/
|
|
68
|
+
declare function runProcess(start: GasState, kind: ProcessKind, target: {
|
|
69
|
+
V?: number;
|
|
70
|
+
P?: number;
|
|
71
|
+
T?: number;
|
|
72
|
+
}, gamma?: number, samples?: number): ProcessResult;
|
|
73
|
+
/**
|
|
74
|
+
* Work done by the gas along an arbitrary sampled path, J, by the trapezium
|
|
75
|
+
* rule over ∫p dV.
|
|
76
|
+
*
|
|
77
|
+
* For a path that came from somewhere other than `runProcess`: a measured
|
|
78
|
+
* indicator diagram, a path a student dragged out by hand, a cycle assembled
|
|
79
|
+
* from points. The sign follows the direction of travel, so a loop traversed
|
|
80
|
+
* clockwise gives positive net work and anticlockwise gives negative, which is
|
|
81
|
+
* the engine-versus-refrigerator distinction and not a convention to be fixed
|
|
82
|
+
* up afterwards.
|
|
83
|
+
*/
|
|
84
|
+
declare function workAlongPathJ(path: readonly GasState[]): number;
|
|
85
|
+
/**
|
|
86
|
+
* The first law as a check rather than as a calculation: returns how far
|
|
87
|
+
* Q − W − ΔU is from zero, in joules.
|
|
88
|
+
*
|
|
89
|
+
* Exposed so a lab can SHOW conservation holding instead of asserting it in a
|
|
90
|
+
* test the student never sees. A number that is not zero here is a bug in the
|
|
91
|
+
* kernel, and it should be visible as one.
|
|
92
|
+
*/
|
|
93
|
+
declare function firstLawResidualJ(result: ProcessResult): number;
|
|
94
|
+
//#endregion
|
|
95
|
+
export { GasState, ProcessKind, ProcessResult, firstLawResidualJ, runProcess, workAlongPathJ };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { R, gammaMonatomic, molarHeatCapacities } from "./gas.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/thermo/processes.ts
|
|
4
|
+
/**
|
|
5
|
+
* Quasi-static processes on an ideal gas, and the first law along each.
|
|
6
|
+
*
|
|
7
|
+
* THE MODEL. One ideal gas, pV = nRT, with a heat-capacity ratio γ = Cp/Cv. The
|
|
8
|
+
* first law ΔU = Q − W holds on every leg, with the sign convention that W is
|
|
9
|
+
* work done BY the gas and Q is heat added TO it:
|
|
10
|
+
*
|
|
11
|
+
* isothermal T const pV = const W = nRT·ln(V₂/V₁) Q = W ΔU = 0
|
|
12
|
+
* adiabatic Q = 0 pVᵞ = const W = (p₁V₁−p₂V₂)/(γ−1) = −ΔU ΔS = 0
|
|
13
|
+
* isobaric p const V/T = const W = pΔV Q = nCpΔT
|
|
14
|
+
* isochoric V const p/T = const W = 0 Q = ΔU = nCvΔT
|
|
15
|
+
* linear a straight line on the p–V diagram; W is the trapezium area
|
|
16
|
+
*
|
|
17
|
+
* WHY `linear` IS HERE. The four named processes are the ones with closed
|
|
18
|
+
* forms, but the cycles students are actually given are drawn on a p–V diagram
|
|
19
|
+
* with straight legs that are none of them. Without it, the commonest exercise
|
|
20
|
+
* in the topic ("complete the Q, W, ΔU table for A→B→C→A") cannot be expressed
|
|
21
|
+
* at all, and every lab has to compute its own trapezium.
|
|
22
|
+
*
|
|
23
|
+
* THE METHOD. Closed forms wherever one exists, because they are exact and they
|
|
24
|
+
* are what the answer is checked against. `linear` integrates ∫p dV by the
|
|
25
|
+
* trapezium rule over the sampled path, which is EXACT for a straight line
|
|
26
|
+
* rather than merely convergent: the integrand is a first-degree polynomial in
|
|
27
|
+
* V and the trapezium rule is exact to first degree. Q then comes from the
|
|
28
|
+
* first law rather than from a separate formula, which is the only way to keep
|
|
29
|
+
* the three quantities consistent on a path that has no heat-capacity of its
|
|
30
|
+
* own.
|
|
31
|
+
*
|
|
32
|
+
* UNITS: SI. Pressure in pascals, volume in m³, temperature in kelvin, energy
|
|
33
|
+
* in joules, entropy in J/K.
|
|
34
|
+
*/
|
|
35
|
+
/** State completed from any two of (p,V,T) via pV = nRT. */
|
|
36
|
+
const fromPV = (P, V, n) => ({
|
|
37
|
+
P,
|
|
38
|
+
V,
|
|
39
|
+
n,
|
|
40
|
+
T: P * V / (n * R)
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Run one quasi-static process from `start` to a target.
|
|
44
|
+
*
|
|
45
|
+
* Give exactly one target coordinate the process can reach: a target volume for
|
|
46
|
+
* an isothermal or adiabatic expansion, a target temperature for isobaric or
|
|
47
|
+
* isochoric heating. `linear` is the exception and needs a full end state,
|
|
48
|
+
* since a straight line on the p–V diagram is fixed by its two ends and by
|
|
49
|
+
* nothing less.
|
|
50
|
+
*/
|
|
51
|
+
function runProcess(start, kind, target, gamma = gammaMonatomic, samples = 64) {
|
|
52
|
+
const { n } = start;
|
|
53
|
+
const { cv: Cv, cp: Cp } = molarHeatCapacities(gamma);
|
|
54
|
+
let end;
|
|
55
|
+
if (kind === "isothermal") {
|
|
56
|
+
const T = start.T;
|
|
57
|
+
const V2 = target.V ?? (target.P != null ? n * R * T / target.P : start.V);
|
|
58
|
+
end = fromPV(n * R * T / V2, V2, n);
|
|
59
|
+
} else if (kind === "adiabatic") {
|
|
60
|
+
const K = start.P * start.V ** gamma;
|
|
61
|
+
const V2 = target.V ?? (target.T != null ? start.V * (start.T / target.T) ** (1 / (gamma - 1)) : start.V);
|
|
62
|
+
end = fromPV(K / V2 ** gamma, V2, n);
|
|
63
|
+
} else if (kind === "isobaric") {
|
|
64
|
+
const P = start.P;
|
|
65
|
+
end = fromPV(P, target.V ?? (target.T != null ? n * R * target.T / P : start.V), n);
|
|
66
|
+
} else if (kind === "linear") {
|
|
67
|
+
if (target.P == null || target.V == null) throw new RangeError("A linear leg on the p–V diagram is fixed by its two ends, so it needs both a target pressure and a target volume.");
|
|
68
|
+
end = fromPV(target.P, target.V, n);
|
|
69
|
+
} else {
|
|
70
|
+
const V = start.V;
|
|
71
|
+
end = fromPV(target.P ?? (target.T != null ? n * R * target.T / V : start.P), V, n);
|
|
72
|
+
}
|
|
73
|
+
const path = [];
|
|
74
|
+
for (let i = 0; i <= samples; i++) {
|
|
75
|
+
const u = i / samples;
|
|
76
|
+
let s;
|
|
77
|
+
if (kind === "isochoric") s = fromPV(start.P + (end.P - start.P) * u, start.V, n);
|
|
78
|
+
else {
|
|
79
|
+
const V = start.V + (end.V - start.V) * u;
|
|
80
|
+
if (kind === "isothermal") s = fromPV(n * R * start.T / V, V, n);
|
|
81
|
+
else if (kind === "adiabatic") s = fromPV(start.P * start.V ** gamma / V ** gamma, V, n);
|
|
82
|
+
else if (kind === "linear") s = fromPV(start.P + (end.P - start.P) * u, V, n);
|
|
83
|
+
else s = fromPV(start.P, V, n);
|
|
84
|
+
}
|
|
85
|
+
path.push(s);
|
|
86
|
+
}
|
|
87
|
+
const dU = n * Cv * (end.T - start.T);
|
|
88
|
+
let W, Q, dS;
|
|
89
|
+
if (kind === "isothermal") {
|
|
90
|
+
W = n * R * start.T * Math.log(end.V / start.V);
|
|
91
|
+
Q = W;
|
|
92
|
+
dS = n * R * Math.log(end.V / start.V);
|
|
93
|
+
} else if (kind === "adiabatic") {
|
|
94
|
+
W = (start.P * start.V - end.P * end.V) / (gamma - 1);
|
|
95
|
+
Q = 0;
|
|
96
|
+
dS = 0;
|
|
97
|
+
} else if (kind === "isobaric") {
|
|
98
|
+
W = start.P * (end.V - start.V);
|
|
99
|
+
Q = n * Cp * (end.T - start.T);
|
|
100
|
+
dS = n * Cp * Math.log(end.T / start.T);
|
|
101
|
+
} else if (kind === "linear") {
|
|
102
|
+
W = .5 * (start.P + end.P) * (end.V - start.V);
|
|
103
|
+
Q = dU + W;
|
|
104
|
+
dS = n * Cv * Math.log(end.T / start.T) + n * R * Math.log(end.V / start.V);
|
|
105
|
+
} else {
|
|
106
|
+
W = 0;
|
|
107
|
+
Q = dU;
|
|
108
|
+
dS = n * Cv * Math.log(end.T / start.T);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
kind,
|
|
112
|
+
start,
|
|
113
|
+
end,
|
|
114
|
+
path,
|
|
115
|
+
W,
|
|
116
|
+
Q,
|
|
117
|
+
dU,
|
|
118
|
+
dS
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Work done by the gas along an arbitrary sampled path, J, by the trapezium
|
|
123
|
+
* rule over ∫p dV.
|
|
124
|
+
*
|
|
125
|
+
* For a path that came from somewhere other than `runProcess`: a measured
|
|
126
|
+
* indicator diagram, a path a student dragged out by hand, a cycle assembled
|
|
127
|
+
* from points. The sign follows the direction of travel, so a loop traversed
|
|
128
|
+
* clockwise gives positive net work and anticlockwise gives negative, which is
|
|
129
|
+
* the engine-versus-refrigerator distinction and not a convention to be fixed
|
|
130
|
+
* up afterwards.
|
|
131
|
+
*/
|
|
132
|
+
function workAlongPathJ(path) {
|
|
133
|
+
let total = 0;
|
|
134
|
+
for (let i = 1; i < path.length; i++) {
|
|
135
|
+
const a = path[i - 1];
|
|
136
|
+
const b = path[i];
|
|
137
|
+
total += .5 * (a.P + b.P) * (b.V - a.V);
|
|
138
|
+
}
|
|
139
|
+
return total;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The first law as a check rather than as a calculation: returns how far
|
|
143
|
+
* Q − W − ΔU is from zero, in joules.
|
|
144
|
+
*
|
|
145
|
+
* Exposed so a lab can SHOW conservation holding instead of asserting it in a
|
|
146
|
+
* test the student never sees. A number that is not zero here is a bug in the
|
|
147
|
+
* kernel, and it should be visible as one.
|
|
148
|
+
*/
|
|
149
|
+
function firstLawResidualJ(result) {
|
|
150
|
+
return result.Q - result.W - result.dU;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
export { firstLawResidualJ, runProcess, workAlongPathJ };
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
//#region src/thermo/temperature.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Thermometry: temperature scales, and the thermometric property that any
|
|
4
|
+
* thermometer actually measures.
|
|
5
|
+
*
|
|
6
|
+
* THE MODEL. A thermometer never measures temperature. It measures some other
|
|
7
|
+
* quantity X that varies with it: the length of a mercury column, the pressure
|
|
8
|
+
* of a fixed volume of gas, the resistance of a platinum wire, the emf across a
|
|
9
|
+
* junction of two metals. Assume X is LINEAR in temperature, pin it at two
|
|
10
|
+
* reproducible fixed points, and the scale follows:
|
|
11
|
+
*
|
|
12
|
+
* θ X − X_ice
|
|
13
|
+
* ───── = ───────────────────── (θ in °C)
|
|
14
|
+
* 100 X_steam − X_ice
|
|
15
|
+
*
|
|
16
|
+
* Every scale in the table below is the same statement with a different pair of
|
|
17
|
+
* numbers at the fixed points, which is why the textbook chain
|
|
18
|
+
*
|
|
19
|
+
* C/5 = (F−32)/9 = (K−273.15)/5 = (Rn−492)/9 = R/4
|
|
20
|
+
*
|
|
21
|
+
* holds: each term is the same fraction of the same interval.
|
|
22
|
+
*
|
|
23
|
+
* WHAT MAKES A SCALE. A scale is affine in thermodynamic temperature, so two
|
|
24
|
+
* numbers fix it: how many of its degrees span one kelvin, and what it reads at
|
|
25
|
+
* absolute zero. Ice and steam points are DERIVED from those here rather than
|
|
26
|
+
* stored beside them, because a stored pair can drift out of step with the
|
|
27
|
+
* conversion that is supposed to reproduce it.
|
|
28
|
+
*
|
|
29
|
+
* SCOPE. Linear thermometry only. A real platinum resistance thermometer is
|
|
30
|
+
* quadratic and a thermocouple is worse; both have their own functions below,
|
|
31
|
+
* and the difference between them and the linear assumption is the reason
|
|
32
|
+
* different thermometers disagree away from the fixed points.
|
|
33
|
+
*
|
|
34
|
+
* Units: temperatures carry their scale explicitly. Anything named `...K` is
|
|
35
|
+
* kelvin, `...C` is Celsius. The thermometric property X is unitless here
|
|
36
|
+
* because the ratio cancels it.
|
|
37
|
+
*/
|
|
38
|
+
type TemperatureScale = 'celsius' | 'fahrenheit' | 'kelvin' | 'rankine' | 'reaumur';
|
|
39
|
+
interface ScaleDefinition {
|
|
40
|
+
name: string;
|
|
41
|
+
/** The degree symbol as written, e.g. '°C', 'K'. */
|
|
42
|
+
symbol: string;
|
|
43
|
+
/** How many of this scale's degrees span one kelvin. */
|
|
44
|
+
degreesPerKelvin: number;
|
|
45
|
+
/** What this scale reads at absolute zero. */
|
|
46
|
+
absoluteZeroReading: number;
|
|
47
|
+
/** True for a scale whose zero IS absolute zero, so ratios of readings mean something. */
|
|
48
|
+
absolute: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The five scales, each defined by its slope against kelvin and its reading at
|
|
52
|
+
* absolute zero.
|
|
53
|
+
*
|
|
54
|
+
* Réaumur and Rankine are here because they appear in the fixed-point tables
|
|
55
|
+
* students are asked to complete, not because anyone uses them.
|
|
56
|
+
*/
|
|
57
|
+
declare const TEMPERATURE_SCALES: Record<TemperatureScale, ScaleDefinition>;
|
|
58
|
+
/** A reading on any scale, as thermodynamic temperature in kelvin. */
|
|
59
|
+
declare function toKelvin(reading: number, scale: TemperatureScale): number;
|
|
60
|
+
/** Thermodynamic temperature in kelvin, as a reading on any scale. */
|
|
61
|
+
declare function fromKelvin(kelvin: number, scale: TemperatureScale): number;
|
|
62
|
+
/**
|
|
63
|
+
* Convert a temperature READING between scales, offsets included.
|
|
64
|
+
*
|
|
65
|
+
* This is the one to use for "a fever of 102 °F is what in Celsius". It is the
|
|
66
|
+
* WRONG one for "a rise of 10 °F is what in Celsius" — see
|
|
67
|
+
* `convertTemperatureInterval`.
|
|
68
|
+
*/
|
|
69
|
+
declare function convertTemperature(value: number, from: TemperatureScale, to: TemperatureScale): number;
|
|
70
|
+
/**
|
|
71
|
+
* Convert a temperature DIFFERENCE between scales: slope only, no offset.
|
|
72
|
+
*
|
|
73
|
+
* Split out from `convertTemperature` because running a difference through the
|
|
74
|
+
* offset is the most common temperature mistake there is, and it is silent: a
|
|
75
|
+
* 10 °C rise comes back as 50 °F instead of 18 °F, and 50 is a perfectly
|
|
76
|
+
* plausible-looking number. Separate functions make the caller say which they
|
|
77
|
+
* meant.
|
|
78
|
+
*/
|
|
79
|
+
declare function convertTemperatureInterval(delta: number, from: TemperatureScale, to: TemperatureScale): number;
|
|
80
|
+
/** What a scale reads at the ice point, derived rather than tabulated. */
|
|
81
|
+
declare const icePointOn: (scale: TemperatureScale) => number;
|
|
82
|
+
/** What a scale reads at the steam point, derived rather than tabulated. */
|
|
83
|
+
declare const steamPointOn: (scale: TemperatureScale) => number;
|
|
84
|
+
/** The number of this scale's degrees between the ice and steam points. */
|
|
85
|
+
declare const fundamentalInterval: (scale: TemperatureScale) => number;
|
|
86
|
+
/**
|
|
87
|
+
* The reading at which two scales agree, or `null` when they never do.
|
|
88
|
+
*
|
|
89
|
+
* Answers "at what temperature do the Celsius and Fahrenheit thermometers show
|
|
90
|
+
* the same number" (−40) directly, instead of by setting up the equation by
|
|
91
|
+
* hand each time. Two scales with equal slope and different zeros are parallel
|
|
92
|
+
* and never meet, which is the `null`: Celsius and Kelvin never read alike.
|
|
93
|
+
*/
|
|
94
|
+
declare function scaleReadingsAgree(a: TemperatureScale, b: TemperatureScale): number | null;
|
|
95
|
+
interface FixedPointCalibration {
|
|
96
|
+
/** The thermometric property read at the unknown temperature. */
|
|
97
|
+
x: number;
|
|
98
|
+
/** The same property read in melting ice. */
|
|
99
|
+
xIce: number;
|
|
100
|
+
/** The same property read in steam at standard pressure. */
|
|
101
|
+
xSteam: number;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Temperature from any thermometric property, by linear interpolation between
|
|
105
|
+
* the two fixed points.
|
|
106
|
+
*
|
|
107
|
+
* Deliberately unitless in X: the ratio cancels it, so the SAME function reads
|
|
108
|
+
* a mercury column in centimetres, a gas pressure in N/m², a resistance in ohms
|
|
109
|
+
* and a thermocouple emf in millivolts. That cancellation is the physics, and
|
|
110
|
+
* writing one function per instrument would hide it.
|
|
111
|
+
*
|
|
112
|
+
* Throws when the two fixed points coincide, because a property that does not
|
|
113
|
+
* change between ice and steam is not a thermometric property and the
|
|
114
|
+
* interpolation would be a division by zero dressed up as a temperature.
|
|
115
|
+
*/
|
|
116
|
+
declare function thermometricTemperatureC({
|
|
117
|
+
x,
|
|
118
|
+
xIce,
|
|
119
|
+
xSteam
|
|
120
|
+
}: FixedPointCalibration): number;
|
|
121
|
+
/** The inverse: what the property reads at a given Celsius temperature. */
|
|
122
|
+
declare function thermometricValue(celsius: number, xIce: number, xSteam: number): number;
|
|
123
|
+
/**
|
|
124
|
+
* Temperature from a thermometer calibrated at the triple point alone, in
|
|
125
|
+
* kelvin: T = 273.16 · X / X_triple.
|
|
126
|
+
*
|
|
127
|
+
* This is the constant-volume gas thermometer's defining relation, and it needs
|
|
128
|
+
* ONE fixed point rather than two because it uses a property that is
|
|
129
|
+
* proportional to thermodynamic temperature rather than merely linear in it.
|
|
130
|
+
* Pressure at fixed volume extrapolates to zero at absolute zero, so the origin
|
|
131
|
+
* is the second point and does not have to be measured.
|
|
132
|
+
*
|
|
133
|
+
* Throws on a non-positive `xTriple`, and on a negative `x`: a gas pressure
|
|
134
|
+
* below zero is not a cold reading, it is a broken instrument.
|
|
135
|
+
*/
|
|
136
|
+
declare function triplePointTemperatureK(x: number, xTriple: number): number;
|
|
137
|
+
/**
|
|
138
|
+
* Resistance of a metal thermometer at θ °C, to second order:
|
|
139
|
+
*
|
|
140
|
+
* R_θ = R_0 · (1 + a·θ + b·θ²)
|
|
141
|
+
*
|
|
142
|
+
* Pass `b = 0` for the linear model. The quadratic term is why a platinum
|
|
143
|
+
* thermometer and a mercury one, both correct at 0 °C and 100 °C, disagree at
|
|
144
|
+
* 50 °C: the curvature is real, and the linear scale is the chord across it.
|
|
145
|
+
*/
|
|
146
|
+
declare function resistanceAtC(r0: number, a: number, theta: number, b?: number): number;
|
|
147
|
+
/**
|
|
148
|
+
* Thermocouple emf against the cold junction, in the standard quadratic form:
|
|
149
|
+
*
|
|
150
|
+
* E = a·θ + b·θ²
|
|
151
|
+
*
|
|
152
|
+
* Kept as a named function rather than inlined because the two temperatures
|
|
153
|
+
* that fall out of it, below, are the whole reason a thermocouple has a usable
|
|
154
|
+
* range at all.
|
|
155
|
+
*/
|
|
156
|
+
declare function thermocoupleEmf(theta: number, a: number, b: number): number;
|
|
157
|
+
/**
|
|
158
|
+
* The NEUTRAL temperature, where the emf peaks: θ_n = −a / 2b.
|
|
159
|
+
*
|
|
160
|
+
* Past it the emf falls again, so a single emf reading matches two
|
|
161
|
+
* temperatures and the thermocouple stops being a thermometer. That is the
|
|
162
|
+
* practical limit of the instrument, and it is a property of the metal pair
|
|
163
|
+
* rather than of the circuit.
|
|
164
|
+
*/
|
|
165
|
+
declare function thermocoupleNeutralTemperatureC(a: number, b: number): number;
|
|
166
|
+
/**
|
|
167
|
+
* The INVERSION temperature, where the emf returns to zero: θ_i = −a / b.
|
|
168
|
+
*
|
|
169
|
+
* Exactly twice the neutral temperature when the cold junction is at 0 °C,
|
|
170
|
+
* which is the check a student is usually asked to make.
|
|
171
|
+
*/
|
|
172
|
+
declare function thermocoupleInversionTemperatureC(a: number, b: number): number;
|
|
173
|
+
//#endregion
|
|
174
|
+
export { FixedPointCalibration, ScaleDefinition, TEMPERATURE_SCALES, TemperatureScale, convertTemperature, convertTemperatureInterval, fromKelvin, fundamentalInterval, icePointOn, resistanceAtC, scaleReadingsAgree, steamPointOn, thermocoupleEmf, thermocoupleInversionTemperatureC, thermocoupleNeutralTemperatureC, thermometricTemperatureC, thermometricValue, toKelvin, triplePointTemperatureK };
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { WATER_TRIPLE_POINT_K, ZERO_CELSIUS_K } from "../core/constants.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/thermo/temperature.ts
|
|
4
|
+
/**
|
|
5
|
+
* Thermometry: temperature scales, and the thermometric property that any
|
|
6
|
+
* thermometer actually measures.
|
|
7
|
+
*
|
|
8
|
+
* THE MODEL. A thermometer never measures temperature. It measures some other
|
|
9
|
+
* quantity X that varies with it: the length of a mercury column, the pressure
|
|
10
|
+
* of a fixed volume of gas, the resistance of a platinum wire, the emf across a
|
|
11
|
+
* junction of two metals. Assume X is LINEAR in temperature, pin it at two
|
|
12
|
+
* reproducible fixed points, and the scale follows:
|
|
13
|
+
*
|
|
14
|
+
* θ X − X_ice
|
|
15
|
+
* ───── = ───────────────────── (θ in °C)
|
|
16
|
+
* 100 X_steam − X_ice
|
|
17
|
+
*
|
|
18
|
+
* Every scale in the table below is the same statement with a different pair of
|
|
19
|
+
* numbers at the fixed points, which is why the textbook chain
|
|
20
|
+
*
|
|
21
|
+
* C/5 = (F−32)/9 = (K−273.15)/5 = (Rn−492)/9 = R/4
|
|
22
|
+
*
|
|
23
|
+
* holds: each term is the same fraction of the same interval.
|
|
24
|
+
*
|
|
25
|
+
* WHAT MAKES A SCALE. A scale is affine in thermodynamic temperature, so two
|
|
26
|
+
* numbers fix it: how many of its degrees span one kelvin, and what it reads at
|
|
27
|
+
* absolute zero. Ice and steam points are DERIVED from those here rather than
|
|
28
|
+
* stored beside them, because a stored pair can drift out of step with the
|
|
29
|
+
* conversion that is supposed to reproduce it.
|
|
30
|
+
*
|
|
31
|
+
* SCOPE. Linear thermometry only. A real platinum resistance thermometer is
|
|
32
|
+
* quadratic and a thermocouple is worse; both have their own functions below,
|
|
33
|
+
* and the difference between them and the linear assumption is the reason
|
|
34
|
+
* different thermometers disagree away from the fixed points.
|
|
35
|
+
*
|
|
36
|
+
* Units: temperatures carry their scale explicitly. Anything named `...K` is
|
|
37
|
+
* kelvin, `...C` is Celsius. The thermometric property X is unitless here
|
|
38
|
+
* because the ratio cancels it.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* The five scales, each defined by its slope against kelvin and its reading at
|
|
42
|
+
* absolute zero.
|
|
43
|
+
*
|
|
44
|
+
* Réaumur and Rankine are here because they appear in the fixed-point tables
|
|
45
|
+
* students are asked to complete, not because anyone uses them.
|
|
46
|
+
*/
|
|
47
|
+
const TEMPERATURE_SCALES = {
|
|
48
|
+
celsius: {
|
|
49
|
+
name: "Celsius",
|
|
50
|
+
symbol: "°C",
|
|
51
|
+
degreesPerKelvin: 1,
|
|
52
|
+
absoluteZeroReading: -ZERO_CELSIUS_K,
|
|
53
|
+
absolute: false
|
|
54
|
+
},
|
|
55
|
+
fahrenheit: {
|
|
56
|
+
name: "Fahrenheit",
|
|
57
|
+
symbol: "°F",
|
|
58
|
+
degreesPerKelvin: 1.8,
|
|
59
|
+
absoluteZeroReading: -459.67,
|
|
60
|
+
absolute: false
|
|
61
|
+
},
|
|
62
|
+
kelvin: {
|
|
63
|
+
name: "kelvin",
|
|
64
|
+
symbol: "K",
|
|
65
|
+
degreesPerKelvin: 1,
|
|
66
|
+
absoluteZeroReading: 0,
|
|
67
|
+
absolute: true
|
|
68
|
+
},
|
|
69
|
+
rankine: {
|
|
70
|
+
name: "Rankine",
|
|
71
|
+
symbol: "°Rn",
|
|
72
|
+
degreesPerKelvin: 1.8,
|
|
73
|
+
absoluteZeroReading: 0,
|
|
74
|
+
absolute: true
|
|
75
|
+
},
|
|
76
|
+
reaumur: {
|
|
77
|
+
name: "Réaumur",
|
|
78
|
+
symbol: "°R",
|
|
79
|
+
degreesPerKelvin: .8,
|
|
80
|
+
absoluteZeroReading: -218.52,
|
|
81
|
+
absolute: false
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const definitionFor = (scale) => {
|
|
85
|
+
const found = TEMPERATURE_SCALES[scale];
|
|
86
|
+
if (!found) throw new RangeError(`Unknown temperature scale "${String(scale)}".`);
|
|
87
|
+
return found;
|
|
88
|
+
};
|
|
89
|
+
const finite = (value, what) => {
|
|
90
|
+
if (!Number.isFinite(value)) throw new RangeError(`${what} must be a finite number.`);
|
|
91
|
+
return value;
|
|
92
|
+
};
|
|
93
|
+
/** A reading on any scale, as thermodynamic temperature in kelvin. */
|
|
94
|
+
function toKelvin(reading, scale) {
|
|
95
|
+
const s = definitionFor(scale);
|
|
96
|
+
return (finite(reading, "A temperature reading") - s.absoluteZeroReading) / s.degreesPerKelvin;
|
|
97
|
+
}
|
|
98
|
+
/** Thermodynamic temperature in kelvin, as a reading on any scale. */
|
|
99
|
+
function fromKelvin(kelvin, scale) {
|
|
100
|
+
const s = definitionFor(scale);
|
|
101
|
+
return finite(kelvin, "A temperature in kelvin") * s.degreesPerKelvin + s.absoluteZeroReading;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Convert a temperature READING between scales, offsets included.
|
|
105
|
+
*
|
|
106
|
+
* This is the one to use for "a fever of 102 °F is what in Celsius". It is the
|
|
107
|
+
* WRONG one for "a rise of 10 °F is what in Celsius" — see
|
|
108
|
+
* `convertTemperatureInterval`.
|
|
109
|
+
*/
|
|
110
|
+
function convertTemperature(value, from, to) {
|
|
111
|
+
return fromKelvin(toKelvin(value, from), to);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Convert a temperature DIFFERENCE between scales: slope only, no offset.
|
|
115
|
+
*
|
|
116
|
+
* Split out from `convertTemperature` because running a difference through the
|
|
117
|
+
* offset is the most common temperature mistake there is, and it is silent: a
|
|
118
|
+
* 10 °C rise comes back as 50 °F instead of 18 °F, and 50 is a perfectly
|
|
119
|
+
* plausible-looking number. Separate functions make the caller say which they
|
|
120
|
+
* meant.
|
|
121
|
+
*/
|
|
122
|
+
function convertTemperatureInterval(delta, from, to) {
|
|
123
|
+
return finite(delta, "A temperature interval") / definitionFor(from).degreesPerKelvin * definitionFor(to).degreesPerKelvin;
|
|
124
|
+
}
|
|
125
|
+
/** What a scale reads at the ice point, derived rather than tabulated. */
|
|
126
|
+
const icePointOn = (scale) => fromKelvin(ZERO_CELSIUS_K, scale);
|
|
127
|
+
/** What a scale reads at the steam point, derived rather than tabulated. */
|
|
128
|
+
const steamPointOn = (scale) => fromKelvin(ZERO_CELSIUS_K + 100, scale);
|
|
129
|
+
/** The number of this scale's degrees between the ice and steam points. */
|
|
130
|
+
const fundamentalInterval = (scale) => steamPointOn(scale) - icePointOn(scale);
|
|
131
|
+
/**
|
|
132
|
+
* The reading at which two scales agree, or `null` when they never do.
|
|
133
|
+
*
|
|
134
|
+
* Answers "at what temperature do the Celsius and Fahrenheit thermometers show
|
|
135
|
+
* the same number" (−40) directly, instead of by setting up the equation by
|
|
136
|
+
* hand each time. Two scales with equal slope and different zeros are parallel
|
|
137
|
+
* and never meet, which is the `null`: Celsius and Kelvin never read alike.
|
|
138
|
+
*/
|
|
139
|
+
function scaleReadingsAgree(a, b) {
|
|
140
|
+
const sa = definitionFor(a);
|
|
141
|
+
const sb = definitionFor(b);
|
|
142
|
+
const slopeGap = sa.degreesPerKelvin - sb.degreesPerKelvin;
|
|
143
|
+
if (slopeGap === 0) return null;
|
|
144
|
+
return fromKelvin((sb.absoluteZeroReading - sa.absoluteZeroReading) / slopeGap, a);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Temperature from any thermometric property, by linear interpolation between
|
|
148
|
+
* the two fixed points.
|
|
149
|
+
*
|
|
150
|
+
* Deliberately unitless in X: the ratio cancels it, so the SAME function reads
|
|
151
|
+
* a mercury column in centimetres, a gas pressure in N/m², a resistance in ohms
|
|
152
|
+
* and a thermocouple emf in millivolts. That cancellation is the physics, and
|
|
153
|
+
* writing one function per instrument would hide it.
|
|
154
|
+
*
|
|
155
|
+
* Throws when the two fixed points coincide, because a property that does not
|
|
156
|
+
* change between ice and steam is not a thermometric property and the
|
|
157
|
+
* interpolation would be a division by zero dressed up as a temperature.
|
|
158
|
+
*/
|
|
159
|
+
function thermometricTemperatureC({ x, xIce, xSteam }) {
|
|
160
|
+
const span = finite(xSteam, "The steam-point value") - finite(xIce, "The ice-point value");
|
|
161
|
+
if (span === 0) throw new RangeError("The ice-point and steam-point readings are equal, so this property does not vary with temperature.");
|
|
162
|
+
return (finite(x, "The measured value") - xIce) / span * 100;
|
|
163
|
+
}
|
|
164
|
+
/** The inverse: what the property reads at a given Celsius temperature. */
|
|
165
|
+
function thermometricValue(celsius, xIce, xSteam) {
|
|
166
|
+
return xIce + finite(celsius, "A temperature") / 100 * (xSteam - xIce);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Temperature from a thermometer calibrated at the triple point alone, in
|
|
170
|
+
* kelvin: T = 273.16 · X / X_triple.
|
|
171
|
+
*
|
|
172
|
+
* This is the constant-volume gas thermometer's defining relation, and it needs
|
|
173
|
+
* ONE fixed point rather than two because it uses a property that is
|
|
174
|
+
* proportional to thermodynamic temperature rather than merely linear in it.
|
|
175
|
+
* Pressure at fixed volume extrapolates to zero at absolute zero, so the origin
|
|
176
|
+
* is the second point and does not have to be measured.
|
|
177
|
+
*
|
|
178
|
+
* Throws on a non-positive `xTriple`, and on a negative `x`: a gas pressure
|
|
179
|
+
* below zero is not a cold reading, it is a broken instrument.
|
|
180
|
+
*/
|
|
181
|
+
function triplePointTemperatureK(x, xTriple) {
|
|
182
|
+
if (finite(xTriple, "The triple-point value") <= 0) throw new RangeError("The triple-point reading must be positive.");
|
|
183
|
+
if (finite(x, "The measured value") < 0) throw new RangeError("A property proportional to absolute temperature cannot be negative.");
|
|
184
|
+
return WATER_TRIPLE_POINT_K * x / xTriple;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Resistance of a metal thermometer at θ °C, to second order:
|
|
188
|
+
*
|
|
189
|
+
* R_θ = R_0 · (1 + a·θ + b·θ²)
|
|
190
|
+
*
|
|
191
|
+
* Pass `b = 0` for the linear model. The quadratic term is why a platinum
|
|
192
|
+
* thermometer and a mercury one, both correct at 0 °C and 100 °C, disagree at
|
|
193
|
+
* 50 °C: the curvature is real, and the linear scale is the chord across it.
|
|
194
|
+
*/
|
|
195
|
+
function resistanceAtC(r0, a, theta, b = 0) {
|
|
196
|
+
if (finite(r0, "The ice-point resistance") <= 0) throw new RangeError("The ice-point resistance must be positive.");
|
|
197
|
+
return r0 * (1 + a * finite(theta, "A temperature") + b * theta * theta);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Thermocouple emf against the cold junction, in the standard quadratic form:
|
|
201
|
+
*
|
|
202
|
+
* E = a·θ + b·θ²
|
|
203
|
+
*
|
|
204
|
+
* Kept as a named function rather than inlined because the two temperatures
|
|
205
|
+
* that fall out of it, below, are the whole reason a thermocouple has a usable
|
|
206
|
+
* range at all.
|
|
207
|
+
*/
|
|
208
|
+
function thermocoupleEmf(theta, a, b) {
|
|
209
|
+
const t = finite(theta, "A temperature");
|
|
210
|
+
return a * t + finite(b, "The quadratic coefficient") * t * t;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* The NEUTRAL temperature, where the emf peaks: θ_n = −a / 2b.
|
|
214
|
+
*
|
|
215
|
+
* Past it the emf falls again, so a single emf reading matches two
|
|
216
|
+
* temperatures and the thermocouple stops being a thermometer. That is the
|
|
217
|
+
* practical limit of the instrument, and it is a property of the metal pair
|
|
218
|
+
* rather than of the circuit.
|
|
219
|
+
*/
|
|
220
|
+
function thermocoupleNeutralTemperatureC(a, b) {
|
|
221
|
+
if (finite(b, "The quadratic coefficient") === 0) throw new RangeError("With no quadratic term the emf never turns, so there is no neutral temperature.");
|
|
222
|
+
return -a / (2 * b);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* The INVERSION temperature, where the emf returns to zero: θ_i = −a / b.
|
|
226
|
+
*
|
|
227
|
+
* Exactly twice the neutral temperature when the cold junction is at 0 °C,
|
|
228
|
+
* which is the check a student is usually asked to make.
|
|
229
|
+
*/
|
|
230
|
+
function thermocoupleInversionTemperatureC(a, b) {
|
|
231
|
+
if (finite(b, "The quadratic coefficient") === 0) throw new RangeError("With no quadratic term the emf never returns to zero.");
|
|
232
|
+
return -a / b;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
//#endregion
|
|
236
|
+
export { TEMPERATURE_SCALES, convertTemperature, convertTemperatureInterval, fromKelvin, fundamentalInterval, icePointOn, resistanceAtC, scaleReadingsAgree, steamPointOn, thermocoupleEmf, thermocoupleInversionTemperatureC, thermocoupleNeutralTemperatureC, thermometricTemperatureC, thermometricValue, toKelvin, triplePointTemperatureK };
|