@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,98 @@
|
|
|
1
|
+
import { Worked } from "../../core/worked.mjs";
|
|
2
|
+
import { G_EARTH } from "../kinematics/free-fall.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/physics/dynamics/forces.d.ts
|
|
5
|
+
/** A force, stored as components so adding is addition. */
|
|
6
|
+
interface Force {
|
|
7
|
+
readonly label: string;
|
|
8
|
+
readonly x: number;
|
|
9
|
+
readonly y: number;
|
|
10
|
+
}
|
|
11
|
+
/** `force('push', 20, 30)`: 20 N at 30° above the horizontal. */
|
|
12
|
+
declare function force(label: string, magnitude: number, angleDeg: number): Force;
|
|
13
|
+
/** A force given directly by its components, for one already resolved. */
|
|
14
|
+
declare const forceXY: (label: string, x: number, y: number) => Force;
|
|
15
|
+
/** The weight of a mass: `mg`, straight down. */
|
|
16
|
+
declare const weight: (mass: number, g?: number) => Force;
|
|
17
|
+
interface Resultant {
|
|
18
|
+
readonly x: number;
|
|
19
|
+
readonly y: number;
|
|
20
|
+
readonly magnitude: number;
|
|
21
|
+
/** Above the horizontal, degrees. */
|
|
22
|
+
readonly angleDeg: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Add forces by adding their components.
|
|
26
|
+
*
|
|
27
|
+
* Worth stating plainly because it is the thing that makes force problems tractable and it is
|
|
28
|
+
* routinely obscured: there is no special rule for three forces or for forces at awkward angles.
|
|
29
|
+
* You resolve, you add the two columns, and you are done.
|
|
30
|
+
*/
|
|
31
|
+
declare function resultant(forces: readonly Force[]): Resultant;
|
|
32
|
+
/**
|
|
33
|
+
* Is this set of forces in equilibrium?
|
|
34
|
+
*
|
|
35
|
+
* The tolerance is relative to the largest force present, not absolute. A 1 mN imbalance is nothing
|
|
36
|
+
* among meganewtons and is everything among micronewtons, and a fixed epsilon gets one of those
|
|
37
|
+
* two cases wrong.
|
|
38
|
+
*/
|
|
39
|
+
declare function isBalanced(forces: readonly Force[], tolerance?: number): boolean;
|
|
40
|
+
/** The worked resultant, set out as the two columns a mark scheme wants to see. */
|
|
41
|
+
declare function resultantSteps(forces: readonly Force[], sf?: number): Worked;
|
|
42
|
+
/**
|
|
43
|
+
* Lami's theorem: three forces in equilibrium satisfy `P/sin α = Q/sin β = R/sin γ`, where each
|
|
44
|
+
* angle is the one OPPOSITE its force, meaning the angle between the other two.
|
|
45
|
+
*
|
|
46
|
+
* The "opposite" is the whole theorem and is where it goes wrong, so the parameter names say it.
|
|
47
|
+
* Given two forces and the angles, the third follows.
|
|
48
|
+
*
|
|
49
|
+
* It is not a new law. Three forces in equilibrium form a closed triangle, and Lami is the sine
|
|
50
|
+
* rule for that triangle. Knowing that is worth more than knowing the formula, because the triangle
|
|
51
|
+
* also tells you the DIRECTION, which the formula does not.
|
|
52
|
+
*/
|
|
53
|
+
declare function lami(known: {
|
|
54
|
+
force: number;
|
|
55
|
+
oppositeAngleDeg: number;
|
|
56
|
+
}, wantedOppositeAngleDeg: number, sf?: number): {
|
|
57
|
+
value: number;
|
|
58
|
+
worked: Worked;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* A weight held by a string and pulled sideways: the tension and the angle the string makes.
|
|
62
|
+
*
|
|
63
|
+
* Their standard picture, and the reason it is here rather than left to `resultant` is that the
|
|
64
|
+
* answer people want is the ANGLE, which comes out of the ratio rather than out of the sum.
|
|
65
|
+
*/
|
|
66
|
+
declare function stringWithSideForce(mass: number, sideForce: number, g?: number, sf?: number): {
|
|
67
|
+
tension: number;
|
|
68
|
+
angleFromVerticalDeg: number;
|
|
69
|
+
worked: Worked;
|
|
70
|
+
};
|
|
71
|
+
interface LiftResult {
|
|
72
|
+
/** The push of the floor on the body: what a scale in the lift would read, in newtons. */
|
|
73
|
+
readonly reaction: number;
|
|
74
|
+
/** The unchanged, actual weight. */
|
|
75
|
+
readonly trueWeight: number;
|
|
76
|
+
/** `reaction / trueWeight`. Above 1 is heavy, below 1 is light, 0 is free fall. */
|
|
77
|
+
readonly factor: number;
|
|
78
|
+
readonly worked: Worked;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* What the floor of an accelerating lift pushes back with.
|
|
82
|
+
*
|
|
83
|
+
* `acceleration` is SIGNED: positive is upwards, whatever the lift is currently doing. That is the
|
|
84
|
+
* whole simplification. A lift moving up and slowing down has a downward acceleration and the
|
|
85
|
+
* passenger feels light, which is the case the two printed rules `g + f` and `g − f` leave students
|
|
86
|
+
* unable to handle, because they are indexed on the direction of travel rather than on the
|
|
87
|
+
* direction of the acceleration.
|
|
88
|
+
*/
|
|
89
|
+
declare function apparentWeight(mass: number, acceleration: number, g?: number, sf?: number): LiftResult;
|
|
90
|
+
/**
|
|
91
|
+
* The acceleration a body must have for the supporting force to be a given value.
|
|
92
|
+
*
|
|
93
|
+
* The inverse question, and a real one: a rope that can take 306 N holding a 45 kg boy means he has
|
|
94
|
+
* to slide DOWN with at least a certain acceleration, or the rope breaks.
|
|
95
|
+
*/
|
|
96
|
+
declare function accelerationForSupport(mass: number, support: number, g?: number): number;
|
|
97
|
+
//#endregion
|
|
98
|
+
export { Force, LiftResult, Resultant, accelerationForSupport, apparentWeight, force, forceXY, isBalanced, lami, resultant, resultantSteps, stringWithSideForce, weight };
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { calc, texSigFigs } from "../../core/worked.mjs";
|
|
2
|
+
import { compose, resolve, toDegrees, toRadians } from "../vectors.mjs";
|
|
3
|
+
import { G_EARTH } from "../kinematics/free-fall.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/physics/dynamics/forces.ts
|
|
6
|
+
/**
|
|
7
|
+
* Forces as vectors: adding them up, recognising balance, and the lift.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here is new physics. It is `vectors` with the bookkeeping that force problems need, kept
|
|
10
|
+
* separate because the questions asked of a set of forces are specific: what is the resultant, is
|
|
11
|
+
* it zero, and if the body is accelerating, what does the floor push back with.
|
|
12
|
+
*
|
|
13
|
+
* ONE IDEA RUNS THROUGH ALL OF IT. A body's weight never changes when a lift accelerates. What
|
|
14
|
+
* changes is the REACTION, the push of the floor on the feet, and that is what a scale reads and
|
|
15
|
+
* what a person feels. Textbooks print `a = g + f` and `a = g − f` as two rules for two cases, and
|
|
16
|
+
* students then cannot say which to use when the lift is moving up but slowing down. There is one
|
|
17
|
+
* rule, `R − W = ma` with `a` signed, and the two printed cases are it with the sign filled in.
|
|
18
|
+
*
|
|
19
|
+
* Pure: no React, no pixels.
|
|
20
|
+
*/
|
|
21
|
+
/** `force('push', 20, 30)`: 20 N at 30° above the horizontal. */
|
|
22
|
+
function force(label, magnitude, angleDeg) {
|
|
23
|
+
const { x, y } = resolve(magnitude, angleDeg);
|
|
24
|
+
return {
|
|
25
|
+
label,
|
|
26
|
+
x,
|
|
27
|
+
y
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** A force given directly by its components, for one already resolved. */
|
|
31
|
+
const forceXY = (label, x, y) => ({
|
|
32
|
+
label,
|
|
33
|
+
x,
|
|
34
|
+
y
|
|
35
|
+
});
|
|
36
|
+
/** The weight of a mass: `mg`, straight down. */
|
|
37
|
+
const weight = (mass, g = G_EARTH) => ({
|
|
38
|
+
label: "weight",
|
|
39
|
+
x: 0,
|
|
40
|
+
y: -mass * g
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Add forces by adding their components.
|
|
44
|
+
*
|
|
45
|
+
* Worth stating plainly because it is the thing that makes force problems tractable and it is
|
|
46
|
+
* routinely obscured: there is no special rule for three forces or for forces at awkward angles.
|
|
47
|
+
* You resolve, you add the two columns, and you are done.
|
|
48
|
+
*/
|
|
49
|
+
function resultant(forces) {
|
|
50
|
+
let x = 0;
|
|
51
|
+
let y = 0;
|
|
52
|
+
for (const f of forces) {
|
|
53
|
+
x += f.x;
|
|
54
|
+
y += f.y;
|
|
55
|
+
}
|
|
56
|
+
const polar = compose(x, y);
|
|
57
|
+
return {
|
|
58
|
+
x,
|
|
59
|
+
y,
|
|
60
|
+
magnitude: polar.magnitude,
|
|
61
|
+
angleDeg: polar.angleDeg
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Is this set of forces in equilibrium?
|
|
66
|
+
*
|
|
67
|
+
* The tolerance is relative to the largest force present, not absolute. A 1 mN imbalance is nothing
|
|
68
|
+
* among meganewtons and is everything among micronewtons, and a fixed epsilon gets one of those
|
|
69
|
+
* two cases wrong.
|
|
70
|
+
*/
|
|
71
|
+
function isBalanced(forces, tolerance = 1e-9) {
|
|
72
|
+
const r = resultant(forces);
|
|
73
|
+
const largest = forces.reduce((m, f) => Math.max(m, Math.hypot(f.x, f.y)), 0);
|
|
74
|
+
return r.magnitude <= Math.max(largest, 1) * tolerance;
|
|
75
|
+
}
|
|
76
|
+
/** The worked resultant, set out as the two columns a mark scheme wants to see. */
|
|
77
|
+
function resultantSteps(forces, sf = 3) {
|
|
78
|
+
const r = resultant(forces);
|
|
79
|
+
const w = calc().step("F_x = \\sum F\\cos\\theta, \\quad F_y = \\sum F\\sin\\theta", "resolve every force into the same two directions, then add each column");
|
|
80
|
+
for (const f of forces) w.step(`${f.label}: (${texSigFigs(f.x, sf)},\\; ${texSigFigs(f.y, sf)})\\ \\mathrm{N}`);
|
|
81
|
+
w.step(`\\sum F = (${texSigFigs(r.x, sf)},\\; ${texSigFigs(r.y, sf)})\\ \\mathrm{N}`, "the two totals");
|
|
82
|
+
w.step(`|F| = \\sqrt{F_x^2 + F_y^2} = ${texSigFigs(r.magnitude, sf)}\\ \\mathrm{N}`, `at ${texSigFigs(r.angleDeg, sf)}° to the horizontal`);
|
|
83
|
+
return w.done(r.magnitude);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Lami's theorem: three forces in equilibrium satisfy `P/sin α = Q/sin β = R/sin γ`, where each
|
|
87
|
+
* angle is the one OPPOSITE its force, meaning the angle between the other two.
|
|
88
|
+
*
|
|
89
|
+
* The "opposite" is the whole theorem and is where it goes wrong, so the parameter names say it.
|
|
90
|
+
* Given two forces and the angles, the third follows.
|
|
91
|
+
*
|
|
92
|
+
* It is not a new law. Three forces in equilibrium form a closed triangle, and Lami is the sine
|
|
93
|
+
* rule for that triangle. Knowing that is worth more than knowing the formula, because the triangle
|
|
94
|
+
* also tells you the DIRECTION, which the formula does not.
|
|
95
|
+
*/
|
|
96
|
+
function lami(known, wantedOppositeAngleDeg, sf = 3) {
|
|
97
|
+
const sinKnown = Math.sin(toRadians(known.oppositeAngleDeg));
|
|
98
|
+
if (Math.abs(sinKnown) < 1e-12) throw new Error("Lami needs the angle opposite the known force, and that angle cannot be 0° or 180°: the three forces would be parallel and could not close into a triangle.");
|
|
99
|
+
const value = known.force * Math.sin(toRadians(wantedOppositeAngleDeg)) / sinKnown;
|
|
100
|
+
return {
|
|
101
|
+
value,
|
|
102
|
+
worked: calc().step("\\frac{P}{\\sin\\alpha} = \\frac{Q}{\\sin\\beta} = \\frac{R}{\\sin\\gamma}", "each angle is the one BETWEEN THE OTHER TWO forces, not the one at the force itself").step(`Q = P\\,\\frac{\\sin\\beta}{\\sin\\alpha} = ${texSigFigs(known.force, sf)} \\times \\frac{\\sin ${texSigFigs(wantedOppositeAngleDeg, sf)}^\\circ}{\\sin ${texSigFigs(known.oppositeAngleDeg, sf)}^\\circ}`).step(`Q = ${texSigFigs(value, sf)}\\ \\mathrm{N}`, "it is the sine rule for the triangle the three forces close into").done(value)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A weight held by a string and pulled sideways: the tension and the angle the string makes.
|
|
107
|
+
*
|
|
108
|
+
* Their standard picture, and the reason it is here rather than left to `resultant` is that the
|
|
109
|
+
* answer people want is the ANGLE, which comes out of the ratio rather than out of the sum.
|
|
110
|
+
*/
|
|
111
|
+
function stringWithSideForce(mass, sideForce, g = G_EARTH, sf = 3) {
|
|
112
|
+
const w = mass * g;
|
|
113
|
+
const tension = Math.hypot(w, sideForce);
|
|
114
|
+
const angle = toDegrees(Math.atan2(sideForce, w));
|
|
115
|
+
return {
|
|
116
|
+
tension,
|
|
117
|
+
angleFromVerticalDeg: angle,
|
|
118
|
+
worked: calc().step("T\\cos\\theta = mg, \\quad T\\sin\\theta = F", "the string must hold the weight up AND balance the sideways pull").step(`\\tan\\theta = \\frac{F}{mg} = \\frac{${texSigFigs(sideForce, sf)}}{${texSigFigs(w, sf)}}`, "dividing kills T, which is why the angle comes first").step(`\\theta = ${texSigFigs(angle, sf)}^\\circ`, "measured from the vertical").step(`T = \\sqrt{(mg)^2 + F^2} = ${texSigFigs(tension, sf)}\\ \\mathrm{N}`).done(tension)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* What the floor of an accelerating lift pushes back with.
|
|
123
|
+
*
|
|
124
|
+
* `acceleration` is SIGNED: positive is upwards, whatever the lift is currently doing. That is the
|
|
125
|
+
* whole simplification. A lift moving up and slowing down has a downward acceleration and the
|
|
126
|
+
* passenger feels light, which is the case the two printed rules `g + f` and `g − f` leave students
|
|
127
|
+
* unable to handle, because they are indexed on the direction of travel rather than on the
|
|
128
|
+
* direction of the acceleration.
|
|
129
|
+
*/
|
|
130
|
+
function apparentWeight(mass, acceleration, g = G_EARTH, sf = 3) {
|
|
131
|
+
const trueWeight = mass * g;
|
|
132
|
+
const reaction = mass * (g + acceleration);
|
|
133
|
+
if (reaction < 0) throw new Error(`A downward acceleration of ${-acceleration} m/s² is greater than g, so the floor cannot pull the body down. It leaves the floor rather than pressing on it with a negative force.`);
|
|
134
|
+
const worked = calc().step("R - W = ma", "one equation, with a signed upwards. The two rules printed for \"going up\" and \"going down\" are this with the sign already filled in").step(`R = m(g + a) = ${texSigFigs(mass, sf)}(${texSigFigs(g, sf)} + ${texSigFigs(acceleration, sf)})`).step(`R = ${texSigFigs(reaction, sf)}\\ \\mathrm{N}`, acceleration > 0 ? "more than the weight: accelerating upwards, so the floor must both hold the body up and speed it up" : acceleration < 0 ? "less than the weight: accelerating downwards, so the floor holds up less than all of it" : "exactly the weight: no acceleration, so the lift being in motion changes nothing").step(`W = mg = ${texSigFigs(trueWeight, sf)}\\ \\mathrm{N}`, "the weight itself never changed. Only the reaction did, and that is what a scale reads").done(reaction);
|
|
135
|
+
return {
|
|
136
|
+
reaction,
|
|
137
|
+
trueWeight,
|
|
138
|
+
factor: reaction / trueWeight,
|
|
139
|
+
worked
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The acceleration a body must have for the supporting force to be a given value.
|
|
144
|
+
*
|
|
145
|
+
* The inverse question, and a real one: a rope that can take 306 N holding a 45 kg boy means he has
|
|
146
|
+
* to slide DOWN with at least a certain acceleration, or the rope breaks.
|
|
147
|
+
*/
|
|
148
|
+
function accelerationForSupport(mass, support, g = G_EARTH) {
|
|
149
|
+
return support / mass - g;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//#endregion
|
|
153
|
+
export { accelerationForSupport, apparentWeight, force, forceXY, isBalanced, lami, resultant, resultantSteps, stringWithSideForce, weight };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Worked } from "../../core/worked.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/physics/dynamics/friction.d.ts
|
|
4
|
+
interface AppliedForce {
|
|
5
|
+
readonly magnitude: number;
|
|
6
|
+
/**
|
|
7
|
+
* Above the SURFACE, in degrees, so 0 is along the slope. Positive lifts the body away from the
|
|
8
|
+
* surface (a pull), negative presses it in (a push). Measured from the surface rather than from
|
|
9
|
+
* the horizontal because it is the surface that friction cares about.
|
|
10
|
+
*/
|
|
11
|
+
readonly angleDeg: number;
|
|
12
|
+
}
|
|
13
|
+
interface FrictionSetup {
|
|
14
|
+
readonly mass: number;
|
|
15
|
+
/** Coefficient of STATIC friction: sets the limit before it moves. */
|
|
16
|
+
readonly muStatic: number;
|
|
17
|
+
/** Coefficient of KINETIC friction. Defaults to `muStatic`; in reality it is usually smaller. */
|
|
18
|
+
readonly muKinetic?: number;
|
|
19
|
+
/** Slope angle above the horizontal. Zero is a flat surface. */
|
|
20
|
+
readonly inclineDeg?: number;
|
|
21
|
+
readonly applied?: AppliedForce;
|
|
22
|
+
readonly g?: number;
|
|
23
|
+
}
|
|
24
|
+
interface FrictionResult {
|
|
25
|
+
/** The push of the surface, perpendicular to it. Not `mg` unless the surface is flat and nothing pulls. */
|
|
26
|
+
readonly normal: number;
|
|
27
|
+
/** The force along the slope trying to move it: gravity's component plus any applied force. */
|
|
28
|
+
readonly driving: number;
|
|
29
|
+
/** `μs × N`: the most friction that is available before it slips. */
|
|
30
|
+
readonly limiting: number;
|
|
31
|
+
/** Whether the driving force beat the limit. */
|
|
32
|
+
readonly moves: boolean;
|
|
33
|
+
/** The friction that is ACTUALLY acting, which equals `driving` while it is still. */
|
|
34
|
+
readonly friction: number;
|
|
35
|
+
/** Along the slope, positive in the direction `driving` points. Zero while it is still. */
|
|
36
|
+
readonly acceleration: number;
|
|
37
|
+
readonly worked: Worked;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Work out whether it moves, and then how fast it picks up speed.
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* frictionOn({ mass: 4, muStatic: 0.10, inclineDeg: 30 }); // a = 4.05 m/s²
|
|
44
|
+
* frictionOn({ mass: 4, muStatic: 0.80, inclineDeg: 30 }); // still: 0.8 > tan 30°
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function frictionOn(setup: FrictionSetup, sf?: number): FrictionResult;
|
|
48
|
+
/**
|
|
49
|
+
* The angle of friction, `λ = arctan μ`, which is the same number as the angle of repose.
|
|
50
|
+
*
|
|
51
|
+
* They are given two names and taught in two places, and they are one fact: tilt a surface until a
|
|
52
|
+
* body just slips, and `mg sin θ = μ mg cos θ`, so `tan θ = μ` and the mass cancels. A steel block
|
|
53
|
+
* and a feather of the same material slip at the same angle, which is a good thing to make a
|
|
54
|
+
* learner predict before they see it.
|
|
55
|
+
*/
|
|
56
|
+
declare function angleOfFriction(mu: number, sf?: number): {
|
|
57
|
+
degrees: number;
|
|
58
|
+
worked: Worked;
|
|
59
|
+
};
|
|
60
|
+
/** The angle of repose IS the angle of friction. Named separately because the syllabus is. */
|
|
61
|
+
declare const angleOfRepose: typeof angleOfFriction;
|
|
62
|
+
/** `38.66°` as `38° 40'`, because that is how the answer is printed in this market's papers. */
|
|
63
|
+
declare function degreesAndMinutes(degrees: number): string;
|
|
64
|
+
/**
|
|
65
|
+
* Which is easier, pulling or pushing at the same angle and force?
|
|
66
|
+
*
|
|
67
|
+
* Returns both so a lab can put them side by side. The answer is always pulling, and the reason is
|
|
68
|
+
* the normal force rather than anything about the direction of travel, which is why asking a
|
|
69
|
+
* learner to predict it is a good question.
|
|
70
|
+
*/
|
|
71
|
+
declare function pullVersusPush(setup: Omit<FrictionSetup, 'applied'>, magnitude: number, angleDeg: number): {
|
|
72
|
+
pull: FrictionResult;
|
|
73
|
+
push: FrictionResult;
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { AppliedForce, FrictionResult, FrictionSetup, angleOfFriction, angleOfRepose, degreesAndMinutes, frictionOn, pullVersusPush };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { calc, texSigFigs } from "../../core/worked.mjs";
|
|
2
|
+
import { toDegrees, toRadians } from "../vectors.mjs";
|
|
3
|
+
import { G_EARTH } from "../kinematics/free-fall.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/physics/dynamics/friction.ts
|
|
6
|
+
/**
|
|
7
|
+
* Friction, including the decision every friction question turns on and most solutions skip.
|
|
8
|
+
*
|
|
9
|
+
* STATIC FRICTION IS A RANGE, NOT A VALUE. `F ≤ μsR` is an inequality, and friction takes whatever
|
|
10
|
+
* value it needs to keep the body still, up to that limit. `F = μR` is only true at the instant of
|
|
11
|
+
* slipping. A block pushed with 3 N that needs 3 N to stay put experiences 3 N of friction, not
|
|
12
|
+
* `μsR`, and a solution that writes `μsR` there has computed the wrong number and will usually
|
|
13
|
+
* still get a plausible-looking answer.
|
|
14
|
+
*
|
|
15
|
+
* So this kernel does the decision FIRST and the arithmetic second: work out what is driving the
|
|
16
|
+
* body, work out the largest friction available, compare them, and only then compute. That order
|
|
17
|
+
* is the method, and {@link frictionOn} reports the comparison as part of its result so a lesson
|
|
18
|
+
* can show it and a lab can visualise it as a bar that fills up and then gives way.
|
|
19
|
+
*
|
|
20
|
+
* THE OTHER THING THAT GETS MISSED: a force applied at an angle changes the NORMAL force, and so
|
|
21
|
+
* changes friction. Pulling upwards at an angle lightens the body and helps twice over; pushing
|
|
22
|
+
* downwards at an angle presses it into the surface and fights itself. This is why a suitcase is
|
|
23
|
+
* easier to pull than to push, and it falls straight out of the equations rather than needing to be
|
|
24
|
+
* remembered separately.
|
|
25
|
+
*
|
|
26
|
+
* Pure: no React, no pixels.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Work out whether it moves, and then how fast it picks up speed.
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* frictionOn({ mass: 4, muStatic: 0.10, inclineDeg: 30 }); // a = 4.05 m/s²
|
|
33
|
+
* frictionOn({ mass: 4, muStatic: 0.80, inclineDeg: 30 }); // still: 0.8 > tan 30°
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function frictionOn(setup, sf = 3) {
|
|
37
|
+
const g = setup.g ?? 9.8;
|
|
38
|
+
const muKinetic = setup.muKinetic ?? setup.muStatic;
|
|
39
|
+
const slope = toRadians(setup.inclineDeg ?? 0);
|
|
40
|
+
const weight = setup.mass * g;
|
|
41
|
+
const applied = setup.applied;
|
|
42
|
+
const phi = toRadians(applied?.angleDeg ?? 0);
|
|
43
|
+
const appliedAlong = applied ? applied.magnitude * Math.cos(phi) : 0;
|
|
44
|
+
const appliedAway = applied ? applied.magnitude * Math.sin(phi) : 0;
|
|
45
|
+
const normal = weight * Math.cos(slope) - appliedAway;
|
|
46
|
+
if (normal <= 0) throw new Error(`The applied force lifts the body clear of the surface (normal force would be ${normal.toPrecision(3)} N). There is no friction because there is no contact; this is a projectile question now.`);
|
|
47
|
+
const driving = weight * Math.sin(slope) + appliedAlong;
|
|
48
|
+
const limiting = setup.muStatic * normal;
|
|
49
|
+
const moves = Math.abs(driving) > limiting;
|
|
50
|
+
const kinetic = muKinetic * normal;
|
|
51
|
+
const friction = moves ? kinetic : Math.abs(driving);
|
|
52
|
+
const acceleration = moves ? (Math.abs(driving) - kinetic) / setup.mass : 0;
|
|
53
|
+
const direction = driving < 0 ? -1 : 1;
|
|
54
|
+
const w = calc().step("R = mg\\cos\\theta" + (applied ? " - F\\sin\\phi" : ""), applied ? "the normal force first, because friction depends on it and the applied force changes it" : "the normal force first, because friction depends on it").step(`R = ${texSigFigs(normal, sf)}\\ \\mathrm{N}`).step("F_{\\text{max}} = \\mu_s R", "the MOST friction available. Static friction is an inequality, F ≤ μsR, not an equation").step(`F_{\\text{max}} = ${texSigFigs(setup.muStatic, sf)} \\times ${texSigFigs(normal, sf)} = ${texSigFigs(limiting, sf)}\\ \\mathrm{N}`).step(`\\text{driving} = ${texSigFigs(Math.abs(driving), sf)}\\ \\mathrm{N} \\;${moves ? ">" : "\\leq"}\\; ${texSigFigs(limiting, sf)}\\ \\mathrm{N}`, moves ? "the drive beats the limit, so it slips and friction drops to its kinetic value" : "the limit is not reached, so friction is exactly as large as it needs to be and no larger");
|
|
55
|
+
if (moves) {
|
|
56
|
+
w.step(`ma = ${texSigFigs(Math.abs(driving), sf)} - \\mu_k R = ${texSigFigs(Math.abs(driving), sf)} - ${texSigFigs(kinetic, sf)}`);
|
|
57
|
+
w.step(`a = ${texSigFigs(acceleration * direction, sf)}\\ \\mathrm{m\\,s^{-2}}`, `to ${sf} significant figures`);
|
|
58
|
+
} else w.step(`f = ${texSigFigs(friction, sf)}\\ \\mathrm{N}, \\quad a = 0`, "friction matches the drive exactly. Writing μsR here would be the wrong number");
|
|
59
|
+
return {
|
|
60
|
+
normal,
|
|
61
|
+
driving,
|
|
62
|
+
limiting,
|
|
63
|
+
moves,
|
|
64
|
+
friction,
|
|
65
|
+
acceleration: acceleration * direction,
|
|
66
|
+
worked: w.done(acceleration * direction)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The angle of friction, `λ = arctan μ`, which is the same number as the angle of repose.
|
|
71
|
+
*
|
|
72
|
+
* They are given two names and taught in two places, and they are one fact: tilt a surface until a
|
|
73
|
+
* body just slips, and `mg sin θ = μ mg cos θ`, so `tan θ = μ` and the mass cancels. A steel block
|
|
74
|
+
* and a feather of the same material slip at the same angle, which is a good thing to make a
|
|
75
|
+
* learner predict before they see it.
|
|
76
|
+
*/
|
|
77
|
+
function angleOfFriction(mu, sf = 3) {
|
|
78
|
+
const degrees = toDegrees(Math.atan(mu));
|
|
79
|
+
return {
|
|
80
|
+
degrees,
|
|
81
|
+
worked: calc().step("mg\\sin\\theta = \\mu\\, mg\\cos\\theta", "at the angle where it is just about to slip").step("\\tan\\theta = \\mu", "the mass cancels, so the angle does not depend on how heavy it is").step(`\\theta = \\arctan ${texSigFigs(mu, sf)} = ${texSigFigs(degrees, sf)}^\\circ`, `which is ${degreesAndMinutes(degrees)}`).done(degrees)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** The angle of repose IS the angle of friction. Named separately because the syllabus is. */
|
|
85
|
+
const angleOfRepose = angleOfFriction;
|
|
86
|
+
/** `38.66°` as `38° 40'`, because that is how the answer is printed in this market's papers. */
|
|
87
|
+
function degreesAndMinutes(degrees) {
|
|
88
|
+
const whole = Math.floor(degrees);
|
|
89
|
+
const minutes = Math.round((degrees - whole) * 60);
|
|
90
|
+
return minutes === 60 ? `${whole + 1}° 0'` : `${whole}° ${minutes}'`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Which is easier, pulling or pushing at the same angle and force?
|
|
94
|
+
*
|
|
95
|
+
* Returns both so a lab can put them side by side. The answer is always pulling, and the reason is
|
|
96
|
+
* the normal force rather than anything about the direction of travel, which is why asking a
|
|
97
|
+
* learner to predict it is a good question.
|
|
98
|
+
*/
|
|
99
|
+
function pullVersusPush(setup, magnitude, angleDeg) {
|
|
100
|
+
return {
|
|
101
|
+
pull: frictionOn({
|
|
102
|
+
...setup,
|
|
103
|
+
applied: {
|
|
104
|
+
magnitude,
|
|
105
|
+
angleDeg: Math.abs(angleDeg)
|
|
106
|
+
}
|
|
107
|
+
}),
|
|
108
|
+
push: frictionOn({
|
|
109
|
+
...setup,
|
|
110
|
+
applied: {
|
|
111
|
+
magnitude,
|
|
112
|
+
angleDeg: -Math.abs(angleDeg)
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
export { angleOfFriction, angleOfRepose, degreesAndMinutes, frictionOn, pullVersusPush };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Worked } from "../../core/worked.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/physics/dynamics/system.d.ts
|
|
4
|
+
interface LinkedBody {
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly mass: number;
|
|
7
|
+
/**
|
|
8
|
+
* The force along this body's direction of motion that does NOT come from a string, signed so
|
|
9
|
+
* that positive drives the system the way you have chosen to call forwards.
|
|
10
|
+
*
|
|
11
|
+
* A hanging mass pulling the system along has `drive = +mg`. A hanging mass on the other side of
|
|
12
|
+
* a pulley, being lifted, has `drive = -mg`. A block on a level table being pushed has
|
|
13
|
+
* `drive = +F`. That single signed number is the whole difference between the textbook's separate
|
|
14
|
+
* cases.
|
|
15
|
+
*/
|
|
16
|
+
readonly drive: number;
|
|
17
|
+
/** A resisting force, always opposing motion whichever way it goes. Friction, drag, a brake. */
|
|
18
|
+
readonly resist?: number;
|
|
19
|
+
}
|
|
20
|
+
interface SystemResult {
|
|
21
|
+
/** Positive in the direction you called forwards. */
|
|
22
|
+
readonly acceleration: number;
|
|
23
|
+
readonly moving: boolean;
|
|
24
|
+
readonly totalMass: number;
|
|
25
|
+
readonly totalDrive: number;
|
|
26
|
+
readonly totalResist: number;
|
|
27
|
+
/**
|
|
28
|
+
* The tension in each link: `tensions[i]` joins `bodies[i]` to `bodies[i+1]`, so there is one
|
|
29
|
+
* fewer than there are bodies.
|
|
30
|
+
*
|
|
31
|
+
* Null when the system does not move. That is not a gap, it is the truth: with several bodies
|
|
32
|
+
* held still by friction, how much friction each one contributes is not determined by the
|
|
33
|
+
* equations of motion, and a single number here would be an invention. A stuck system is
|
|
34
|
+
* analysed one body at a time.
|
|
35
|
+
*/
|
|
36
|
+
readonly tensions: readonly number[] | null;
|
|
37
|
+
readonly worked: Worked;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Solve a chain of bodies joined by inextensible strings.
|
|
41
|
+
*
|
|
42
|
+
* Order matters: `bodies[0]` is at the back and `bodies[n-1]` at the front, in the direction you
|
|
43
|
+
* called forwards, because that is what decides which side of each string is which.
|
|
44
|
+
*/
|
|
45
|
+
declare function linkedSystem(bodies: readonly LinkedBody[], sf?: number): SystemResult;
|
|
46
|
+
interface AtwoodResult extends SystemResult {
|
|
47
|
+
/** The single tension in the string. */
|
|
48
|
+
readonly tension: number;
|
|
49
|
+
/**
|
|
50
|
+
* What the pulley's support has to hold, which is `2T` and NOT the combined weight.
|
|
51
|
+
*
|
|
52
|
+
* It is less, because the system is accelerating: some of the weight is going into the motion
|
|
53
|
+
* rather than into the support. A good prediction question, because almost everyone guesses
|
|
54
|
+
* `(m₁ + m₂)g` first.
|
|
55
|
+
*/
|
|
56
|
+
readonly pulleyLoad: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Two masses over a frictionless pulley.
|
|
60
|
+
*
|
|
61
|
+
* Not a special case, and deliberately implemented by delegating rather than by its own formula:
|
|
62
|
+
* forwards is "the heavier one descends", so gravity drives one body and hinders the other, and
|
|
63
|
+
* that is the only declaration needed. If this had its own `(m₁−m₂)g/(m₁+m₂)` written out, that
|
|
64
|
+
* formula could drift away from the general solver and nothing would notice.
|
|
65
|
+
*/
|
|
66
|
+
declare function atwood(m1: number, m2: number, g?: number, sf?: number): AtwoodResult;
|
|
67
|
+
//#endregion
|
|
68
|
+
export { AtwoodResult, LinkedBody, SystemResult, atwood, linkedSystem };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { calc, texSigFigs } from "../../core/worked.mjs";
|
|
2
|
+
import { G_EARTH } from "../kinematics/free-fall.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/physics/dynamics/system.ts
|
|
5
|
+
/**
|
|
6
|
+
* Bodies joined by strings: one acceleration, and the tension in every link.
|
|
7
|
+
*
|
|
8
|
+
* THE METHOD IS THE POINT, and it is one trick used twice.
|
|
9
|
+
*
|
|
10
|
+
* First, add the equations for all the bodies together. Every tension appears twice with opposite
|
|
11
|
+
* signs, because the string pulls the body in front backwards exactly as hard as it pulls the body
|
|
12
|
+
* behind forwards, so they all cancel and what is left is
|
|
13
|
+
*
|
|
14
|
+
* a = (total driving force) / (total mass)
|
|
15
|
+
*
|
|
16
|
+
* with no tensions in it at all. That is why the acceleration of a loaded train is easy and the
|
|
17
|
+
* coupling forces are not.
|
|
18
|
+
*
|
|
19
|
+
* Second, to get one tension, draw a line through the system at that string and write the equation
|
|
20
|
+
* for everything on one side of the line. Only that one tension crosses the line, so it is the only
|
|
21
|
+
* unknown left.
|
|
22
|
+
*
|
|
23
|
+
* WHAT THIS COVERS, from one declaration: blocks in a row being pushed, a train and its carriages,
|
|
24
|
+
* a mass on a table pulled by a hanging mass, and an Atwood machine. Those are four separate
|
|
25
|
+
* "types" in a textbook, and the only thing that differs between them is which bodies have gravity
|
|
26
|
+
* helping and which have it hindering. A body's `drive` says so, and the rest is identical.
|
|
27
|
+
*
|
|
28
|
+
* Pure: no React, no pixels.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Solve a chain of bodies joined by inextensible strings.
|
|
32
|
+
*
|
|
33
|
+
* Order matters: `bodies[0]` is at the back and `bodies[n-1]` at the front, in the direction you
|
|
34
|
+
* called forwards, because that is what decides which side of each string is which.
|
|
35
|
+
*/
|
|
36
|
+
function linkedSystem(bodies, sf = 3) {
|
|
37
|
+
if (bodies.length === 0) throw new Error("A system needs at least one body.");
|
|
38
|
+
const totalMass = bodies.reduce((m, b) => m + b.mass, 0);
|
|
39
|
+
if (totalMass <= 0) throw new Error("Total mass must be positive.");
|
|
40
|
+
const totalDrive = bodies.reduce((f, b) => f + b.drive, 0);
|
|
41
|
+
const totalResist = bodies.reduce((f, b) => f + Math.abs(b.resist ?? 0), 0);
|
|
42
|
+
const moving = Math.abs(totalDrive) > totalResist;
|
|
43
|
+
const direction = totalDrive < 0 ? -1 : 1;
|
|
44
|
+
const acceleration = moving ? direction * (Math.abs(totalDrive) - totalResist) / totalMass : 0;
|
|
45
|
+
const w = calc().step("a = \\frac{\\sum F}{\\sum m}", "add every body’s equation: each tension appears twice with opposite signs and cancels").step(`a = \\frac{${texSigFigs(totalDrive, sf)}${totalResist ? ` - ${texSigFigs(totalResist, sf)}` : ""}}{${texSigFigs(totalMass, sf)}}`, bodies.map((b) => `${b.label} ${texSigFigs(b.drive, sf)} N`).join(", "));
|
|
46
|
+
if (!moving) {
|
|
47
|
+
/**
|
|
48
|
+
* A stationary system's tensions are determinate ONLY when nothing is resisting.
|
|
49
|
+
*
|
|
50
|
+
* With friction in it, how much each surface contributes is not fixed by the equations of
|
|
51
|
+
* motion: two blocks can share the load any number of ways and every split balances. Reporting
|
|
52
|
+
* a number there would be an invention, so it stays null.
|
|
53
|
+
*
|
|
54
|
+
* With no friction, "not moving" means the drives cancel, and each cut still has exactly one
|
|
55
|
+
* unknown crossing it. Two equal masses over a pulley are the everyday case, and refusing to
|
|
56
|
+
* give their `T = mg` would push the special case out to every caller.
|
|
57
|
+
*/
|
|
58
|
+
const determinate = totalResist === 0;
|
|
59
|
+
const held = determinate ? bodies.slice(0, -1).map((_, i) => {
|
|
60
|
+
const ahead = bodies.slice(i + 1);
|
|
61
|
+
return Math.abs(-ahead.reduce((f, b) => f + b.drive, 0));
|
|
62
|
+
}) : null;
|
|
63
|
+
w.step("\\text{driving} \\leq \\text{resisting} \\;\\Rightarrow\\; a = 0", determinate ? "it does not move, so each body is in balance and the string simply holds the load" : "it does not move, and with friction sharing the load the tensions need a body-by-body analysis rather than this one");
|
|
64
|
+
return {
|
|
65
|
+
acceleration: 0,
|
|
66
|
+
moving: false,
|
|
67
|
+
totalMass,
|
|
68
|
+
totalDrive,
|
|
69
|
+
totalResist,
|
|
70
|
+
tensions: held,
|
|
71
|
+
worked: w.done(0)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
w.step(`a = ${texSigFigs(acceleration, sf)}\\ \\mathrm{m\\,s^{-2}}`, "the same for every body, because the string does not stretch");
|
|
75
|
+
const tensions = [];
|
|
76
|
+
for (let i = 0; i < bodies.length - 1; i++) {
|
|
77
|
+
const ahead = bodies.slice(i + 1);
|
|
78
|
+
const massAhead = ahead.reduce((m, b) => m + b.mass, 0);
|
|
79
|
+
const driveAhead = ahead.reduce((f, b) => f + b.drive, 0);
|
|
80
|
+
const resistAhead = ahead.reduce((f, b) => f + Math.abs(b.resist ?? 0), 0);
|
|
81
|
+
const signed = massAhead * acceleration - driveAhead + direction * resistAhead;
|
|
82
|
+
const tension = Math.abs(signed);
|
|
83
|
+
tensions.push(tension);
|
|
84
|
+
w.step(`T_{${i + 1}} = ${texSigFigs(massAhead, sf)}a - ${texSigFigs(driveAhead, sf)} = ${texSigFigs(tension, sf)}\\ \\mathrm{N}`, `cut the string between ${bodies[i].label} and ${bodies[i + 1].label}, then use only what is beyond the cut: only this one tension crosses it${signed < 0 ? `, and it pulls ${bodies[i + 1].label} backwards` : ""}`);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
acceleration,
|
|
88
|
+
moving: true,
|
|
89
|
+
totalMass,
|
|
90
|
+
totalDrive,
|
|
91
|
+
totalResist,
|
|
92
|
+
tensions,
|
|
93
|
+
worked: w.done(acceleration)
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Two masses over a frictionless pulley.
|
|
98
|
+
*
|
|
99
|
+
* Not a special case, and deliberately implemented by delegating rather than by its own formula:
|
|
100
|
+
* forwards is "the heavier one descends", so gravity drives one body and hinders the other, and
|
|
101
|
+
* that is the only declaration needed. If this had its own `(m₁−m₂)g/(m₁+m₂)` written out, that
|
|
102
|
+
* formula could drift away from the general solver and nothing would notice.
|
|
103
|
+
*/
|
|
104
|
+
function atwood(m1, m2, g = G_EARTH, sf = 3) {
|
|
105
|
+
const heavy = Math.max(m1, m2);
|
|
106
|
+
const light = Math.min(m1, m2);
|
|
107
|
+
const result = linkedSystem([{
|
|
108
|
+
label: `descending mass ${heavy} kg`,
|
|
109
|
+
mass: heavy,
|
|
110
|
+
drive: heavy * g
|
|
111
|
+
}, {
|
|
112
|
+
label: `rising mass ${light} kg`,
|
|
113
|
+
mass: light,
|
|
114
|
+
drive: -light * g
|
|
115
|
+
}], sf);
|
|
116
|
+
const tension = result.tensions?.[0] ?? light * g;
|
|
117
|
+
return {
|
|
118
|
+
...result,
|
|
119
|
+
tension,
|
|
120
|
+
pulleyLoad: 2 * tension
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
export { atwood, linkedSystem };
|