@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,180 @@
|
|
|
1
|
+
import { calc, texSigFigs } from "../../core/worked.mjs";
|
|
2
|
+
import { G_EARTH } from "../kinematics/free-fall.mjs";
|
|
3
|
+
import { sweep } from "../integral-sweep.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/physics/energy/centre-of-mass.ts
|
|
6
|
+
/**
|
|
7
|
+
* Work on things that are not point masses: stacks of bricks, hanging chains, a well full of water.
|
|
8
|
+
*
|
|
9
|
+
* ONE IDEA COVERS ALL OF THEM, and it is the idea that makes this family stop being a set of tricks:
|
|
10
|
+
*
|
|
11
|
+
* **The work done against gravity on an extended body is `mg` times the rise of its CENTRE OF
|
|
12
|
+
* MASS.** Not the rise of its top, not the rise of its bottom, and not the distance anything
|
|
13
|
+
* travelled along the floor.
|
|
14
|
+
*
|
|
15
|
+
* Once that is in place, every question below is the same question. Standing a brick on its end
|
|
16
|
+
* raises its centre from half its thickness to half its length. Stacking eight bricks raises each
|
|
17
|
+
* one by a different amount and you add them. Hauling a chain up a well raises its centre by half
|
|
18
|
+
* the depth while the bucket on the end rises the whole depth, so they are counted separately.
|
|
19
|
+
* Emptying a tank raises each layer by a different amount, so the sum becomes an integral, and the
|
|
20
|
+
* integral is just the centre of mass again with the arithmetic done properly.
|
|
21
|
+
*
|
|
22
|
+
* THE FACTOR OF TWO. Nearly every wrong answer in this family is out by a factor close to two, and
|
|
23
|
+
* it is always the same mistake: using the full depth where the centre of mass only moved half of
|
|
24
|
+
* it. It is worth being caught by that once, deliberately, which is why {@link columnDrain} reports
|
|
25
|
+
* the naive answer alongside the right one.
|
|
26
|
+
*
|
|
27
|
+
* Pure: no React, no pixels.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* The general statement: work against gravity is `mg` times the rise of the centre of mass.
|
|
31
|
+
*
|
|
32
|
+
* Everything else in this file is this function with the two heights worked out for a particular
|
|
33
|
+
* shape. Having it exist separately is the point, because it is what a learner should reach for when
|
|
34
|
+
* they meet a shape nobody has tabulated.
|
|
35
|
+
*/
|
|
36
|
+
function centreOfMassLift(mass, fromHeight, toHeight, g = G_EARTH, sf = 4) {
|
|
37
|
+
const rise = toHeight - fromHeight;
|
|
38
|
+
const value = mass * g * rise;
|
|
39
|
+
return {
|
|
40
|
+
rise,
|
|
41
|
+
value,
|
|
42
|
+
worked: calc().step("W = mg\\,\\Delta \\bar{h}", "the rise of the CENTRE OF MASS. Not of the top of the object, and not of the bottom").step(`\\Delta \\bar{h} = ${texSigFigs(toHeight, sf)} - ${texSigFigs(fromHeight, sf)} = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`W = ${texSigFigs(mass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(rise, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).done(value)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Standing a uniform block on a different face: the brick question.
|
|
47
|
+
*
|
|
48
|
+
* A uniform body's centre of mass sits at the middle, so lying on a face it is half the THICKNESS
|
|
49
|
+
* above the table, and stood on end it is half the LENGTH. The rise is half the difference, and the
|
|
50
|
+
* other two dimensions never enter, which surprises people who were carefully multiplying all three.
|
|
51
|
+
*/
|
|
52
|
+
function standBlockOnEnd(mass, lyingDimension, standingDimension, g = G_EARTH, sf = 4) {
|
|
53
|
+
const from = lyingDimension / 2;
|
|
54
|
+
const to = standingDimension / 2;
|
|
55
|
+
const lift = centreOfMassLift(mass, from, to, g, sf);
|
|
56
|
+
const worked = calc().step("\\bar{h} = \\tfrac{1}{2} \\times (\\text{height of the face it is resting on})", "a uniform block has its centre of mass exactly in the middle, so it sits half its current height above the table").step(`\\bar{h}_{\\text{before}} = \\frac{${texSigFigs(lyingDimension, sf)}}{2} = ${texSigFigs(from, sf)}\\ \\mathrm{m}, \\quad \\bar{h}_{\\text{after}} = \\frac{${texSigFigs(standingDimension, sf)}}{2} = ${texSigFigs(to, sf)}\\ \\mathrm{m}`).step(`\\Delta\\bar{h} = ${texSigFigs(lift.rise, sf)}\\ \\mathrm{m}`, "the third dimension never appears. Tipping a brick does not care how wide it is").step(`W = mg\\,\\Delta\\bar{h} = ${texSigFigs(lift.value, sf)}\\ \\mathrm{J}`).done(lift.value);
|
|
57
|
+
return {
|
|
58
|
+
rise: lift.rise,
|
|
59
|
+
value: lift.value,
|
|
60
|
+
worked
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Tipping a hinged rod (or a hinged plank) through an angle from the vertical.
|
|
65
|
+
*
|
|
66
|
+
* The centre of mass of a uniform rod is at its midpoint, so it traces a circle of radius `l/2`, and
|
|
67
|
+
* the rise is `(l/2)(1 − cos θ)`: the pendulum geometry again, with the length halved because the
|
|
68
|
+
* mass is spread rather than hanging at the end. That reuse is worth naming out loud, because a
|
|
69
|
+
* learner who sees the same `(1 − cos θ)` in a swing and in a toppling rod has genuinely learned the
|
|
70
|
+
* geometry rather than two formulas.
|
|
71
|
+
*/
|
|
72
|
+
function tiltRod(mass, length, angleFromVerticalDeg, g = G_EARTH, sf = 4) {
|
|
73
|
+
const rad = angleFromVerticalDeg * Math.PI / 180;
|
|
74
|
+
const rise = length / 2 * (1 - Math.cos(rad));
|
|
75
|
+
const value = mass * g * rise;
|
|
76
|
+
return {
|
|
77
|
+
rise,
|
|
78
|
+
value,
|
|
79
|
+
worked: calc().step("\\bar{h} = \\frac{l}{2}", "a uniform rod carries its centre of mass at the midpoint, so that is the only point whose height matters").step("\\Delta\\bar{h} = \\frac{l}{2}(1 - \\cos\\theta)", "the same (1 - cos theta) as a pendulum, with l/2 in place of l because the mass sits at the middle, not at the end").step(`\\Delta\\bar{h} = \\frac{${texSigFigs(length, sf)}}{2}(1 - \\cos ${texSigFigs(angleFromVerticalDeg, sf)}^\\circ) = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`W = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).done(value)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Building a column out of `count` identical bricks that all start lying on the ground.
|
|
84
|
+
*
|
|
85
|
+
* DERIVED, NOT QUOTED. The textbook prints `W = ⁿC₂ mgh` and a binomial coefficient appearing in a
|
|
86
|
+
* mechanics problem looks like a conjuring trick. It is not: the bottom brick does not move, the
|
|
87
|
+
* next rises `h`, the next `2h`, and adding `0 + 1 + 2 + ... + (n−1)` gives `n(n−1)/2`, which is the
|
|
88
|
+
* triangle number and which happens to equal `ⁿC₂`. The coefficient is a coincidence of arithmetic,
|
|
89
|
+
* not a combinatorial insight, and saying so is more honest than letting it look profound.
|
|
90
|
+
*
|
|
91
|
+
* `height` is the thickness of one brick, which is how far each brick sits above the one below it.
|
|
92
|
+
*/
|
|
93
|
+
function stackColumn(count, massEach, height, g = G_EARTH, sf = 4) {
|
|
94
|
+
if (!Number.isInteger(count) || count < 1) throw new Error("A stack is built from a whole number of bricks, and at least one.");
|
|
95
|
+
const rises = Array.from({ length: count }, (_, i) => i * height);
|
|
96
|
+
const triangleNumber = count * (count - 1) / 2;
|
|
97
|
+
const value = massEach * g * height * triangleNumber;
|
|
98
|
+
return {
|
|
99
|
+
value,
|
|
100
|
+
rises,
|
|
101
|
+
triangleNumber,
|
|
102
|
+
worked: calc().step("\\text{brick } k \\text{ rises } (k-1)h", "they all start on the ground. The bottom one never moves; the second climbs one brick; the third climbs two").step(`W = mgh\\left(0 + 1 + 2 + \\ldots + ${count - 1}\\right)`, "add up what each brick cost. Nothing clever has happened yet").step(`0 + 1 + \\ldots + (n-1) = \\frac{n(n-1)}{2} = \\frac{${count} \\times ${count - 1}}{2} = ${texSigFigs(triangleNumber, sf)}`, "the triangle number. It also equals nC2, which is why the book prints a binomial coefficient, but there is no counting argument here").step(`W = ${texSigFigs(massEach, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(height, sf)} \\times ${texSigFigs(triangleNumber, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).step(`\\text{check: } \\bar{h} \\text{ rose from } \\frac{h}{2} \\text{ to } \\frac{nh}{2}`, "the same answer falls out of the centre of mass alone, which is the faster route once you trust it").done(value)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Hauling a chain up a well, with a load on the end.
|
|
107
|
+
*
|
|
108
|
+
* Two contributions and they rise by different amounts, which is the entire question. The load on
|
|
109
|
+
* the end travels the full depth. The chain's centre of mass starts halfway down and finishes at the
|
|
110
|
+
* top, so it rises only HALF the depth. Treating the chain as though all of it climbed the full
|
|
111
|
+
* depth doubles its share, and the resulting answer is wrong by an amount that depends on how heavy
|
|
112
|
+
* the chain is relative to the load, which is why it can pass unnoticed.
|
|
113
|
+
*/
|
|
114
|
+
function chainLift(depth, chainMassPerMetre, loadMass, g = G_EARTH, sf = 4) {
|
|
115
|
+
const chainMass = chainMassPerMetre * depth;
|
|
116
|
+
const chainWork = chainMass * g * (depth / 2);
|
|
117
|
+
const loadWork = loadMass * g * depth;
|
|
118
|
+
const value = chainWork + loadWork;
|
|
119
|
+
return {
|
|
120
|
+
chainWork,
|
|
121
|
+
loadWork,
|
|
122
|
+
value,
|
|
123
|
+
chainMass,
|
|
124
|
+
worked: calc().step("W = W_{\\text{chain}} + W_{\\text{load}}", "two things are being raised and they do not rise by the same amount, so they are counted separately").step(`m_{\\text{chain}} = ${texSigFigs(chainMassPerMetre, sf)} \\times ${texSigFigs(depth, sf)} = ${texSigFigs(chainMass, sf)}\\ \\mathrm{kg}`).step(`W_{\\text{chain}} = m_{\\text{chain}}\\,g\\,\\frac{l}{2} = ${texSigFigs(chainMass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(depth / 2, sf)} = ${texSigFigs(chainWork, sf)}\\ \\mathrm{J}`, "HALF the depth: the chain hangs from the top, so its centre of mass starts at the midpoint and ends at the rim").step(`W_{\\text{load}} = ${texSigFigs(loadMass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(depth, sf)} = ${texSigFigs(loadWork, sf)}\\ \\mathrm{J}`, "the full depth: the load is a single lump on the end and every part of it makes the whole journey").step(`W = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).done(value)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Pumping every drop of liquid out over the rim of an upright container.
|
|
129
|
+
*
|
|
130
|
+
* The layer at height `y` has to rise `(H − y)`, so the work is `∫ ρgA(H − y) dy` over whatever is
|
|
131
|
+
* actually in there. The integral is performed symbolically by the shared integrator, so the sweep
|
|
132
|
+
* this returns can be animated as layers leaving one at a time while the running total fills, and
|
|
133
|
+
* the number on the meter is the real antiderivative rather than a sum of rectangles.
|
|
134
|
+
*
|
|
135
|
+
* `fillFraction` is how full it is, measured from the BOTTOM. The mean lift comes out as
|
|
136
|
+
* `H(1 − f/2)`, which is worth reading twice: a FULL tank has the lowest mean lift of all, `H/2`,
|
|
137
|
+
* because most of its water is near the bottom where there is a lot of water and the top layers cost
|
|
138
|
+
* almost nothing. A quarter-full tank lifts its water `7H/8` on average, because all of it is at the
|
|
139
|
+
* bottom and all of it has nearly the whole height to travel. The emptier the tank, the harder each
|
|
140
|
+
* kilogram is to get out.
|
|
141
|
+
*/
|
|
142
|
+
function columnDrain(height, crossSection, fillFraction = 1, density = 1e3, g = G_EARTH, sf = 4) {
|
|
143
|
+
if (fillFraction <= 0 || fillFraction > 1) throw new Error("The fill fraction is how full the container is, measured from the bottom, and lies between 0 and 1.");
|
|
144
|
+
const filled = height * fillFraction;
|
|
145
|
+
const mass = density * crossSection * filled;
|
|
146
|
+
const s = sweep({
|
|
147
|
+
element: "rho*g*A*(H - y)",
|
|
148
|
+
variable: "y",
|
|
149
|
+
from: "0",
|
|
150
|
+
to: "filled"
|
|
151
|
+
}, {
|
|
152
|
+
rho: density,
|
|
153
|
+
g,
|
|
154
|
+
A: crossSection,
|
|
155
|
+
H: height,
|
|
156
|
+
filled
|
|
157
|
+
});
|
|
158
|
+
const value = s.total;
|
|
159
|
+
const meanLift = mass === 0 ? 0 : value / (mass * g);
|
|
160
|
+
const naiveValue = mass * g * height;
|
|
161
|
+
return {
|
|
162
|
+
mass,
|
|
163
|
+
meanLift,
|
|
164
|
+
value,
|
|
165
|
+
naiveValue,
|
|
166
|
+
sweep: s,
|
|
167
|
+
worked: calc().step("dm = \\rho A\\,dy", "slice the liquid into thin horizontal layers. Each layer is its own little lifting problem").step("dW = dm\\,g(H - y) = \\rho g A (H - y)\\,dy", "the layer at height y still has (H - y) to climb before it clears the rim").step(`W = \\int_{0}^{${texSigFigs(filled, sf)}} \\rho g A (H - y)\\,dy = ${texSigFigs(value, sf)}\\ \\mathrm{J}`, "add up every layer. The lower layers dominate, because there is just as much of them and they travel further").step(`\\bar{h} = \\frac{W}{mg} = ${texSigFigs(meanLift, sf)}\\ \\mathrm{m} = H\\left(1 - \\frac{f}{2}\\right)`, "the mean lift, which is the height the centre of mass of the liquid rose").step(`\\text{using } H \\text{ for every drop would give } ${texSigFigs(naiveValue, sf)}\\ \\mathrm{J}`, `a factor of ${texSigFigs(naiveValue / (value || 1), 3)} too big. This is the standard wrong answer in this family`).done(value)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* The mean lift alone, for feeding into {@link pumpPower}.
|
|
172
|
+
*
|
|
173
|
+
* A well being pumped dry is the `fillFraction = 1` case, where the mean lift is half the depth. It
|
|
174
|
+
* is its own named function because that is the number a power question needs and because writing
|
|
175
|
+
* `depth / 2` inline in a pump calculation is how the reasoning gets lost.
|
|
176
|
+
*/
|
|
177
|
+
const meanLiftToRim = (height, fillFraction = 1) => height * (1 - fillFraction / 2);
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
export { centreOfMassLift, chainLift, columnDrain, meanLiftToRim, stackColumn, standBlockOnEnd, tiltRod };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Worked } from "../../core/worked.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/physics/energy/conservation.d.ts
|
|
4
|
+
interface Station {
|
|
5
|
+
readonly label: string;
|
|
6
|
+
/** Height above the chosen reference level, metres. */
|
|
7
|
+
readonly height: number;
|
|
8
|
+
/** Speed at this station, metres per second. */
|
|
9
|
+
readonly speed: number;
|
|
10
|
+
}
|
|
11
|
+
interface Rung {
|
|
12
|
+
readonly label: string;
|
|
13
|
+
readonly kinetic: number;
|
|
14
|
+
readonly potential: number;
|
|
15
|
+
readonly total: number;
|
|
16
|
+
/** Mechanical energy lost since the PREVIOUS station. Zero at the first, and never negative. */
|
|
17
|
+
readonly lostSincePrevious: number;
|
|
18
|
+
}
|
|
19
|
+
interface Ladder {
|
|
20
|
+
readonly rungs: readonly Rung[];
|
|
21
|
+
readonly totalLost: number;
|
|
22
|
+
/** True when the total held to within tolerance across every station. */
|
|
23
|
+
readonly conserved: boolean;
|
|
24
|
+
readonly worked: Worked;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Track the two piles of energy across a journey.
|
|
28
|
+
*
|
|
29
|
+
* The tolerance is relative to the largest total, for the same reason it is in `isBalanced`: a
|
|
30
|
+
* shortfall of a millijoule is nothing in a roller coaster and is everything in a pendulum swinging
|
|
31
|
+
* in a lecture demonstration.
|
|
32
|
+
*/
|
|
33
|
+
declare function energyLadder(mass: number, stations: readonly Station[], g?: number, sf?: number): Ladder;
|
|
34
|
+
/**
|
|
35
|
+
* The speed reached after falling through a height, from energy: `v = √(2gh)`.
|
|
36
|
+
*
|
|
37
|
+
* The mass cancels, which is the point and is the same fact that makes a feather and a hammer land
|
|
38
|
+
* together on the Moon. The path does not appear at all, which is the harder and more useful point:
|
|
39
|
+
* this is the speed at the bottom of a slide, a curved ramp, or a swing, not only of a vertical drop.
|
|
40
|
+
*/
|
|
41
|
+
declare function speedAfterDrop(height: number, g?: number, sf?: number): Worked;
|
|
42
|
+
/** The height a body of known kinetic energy fell from: the drop run backwards. */
|
|
43
|
+
declare function dropForKinetic(mass: number, kinetic: number, g?: number, sf?: number): Worked;
|
|
44
|
+
/**
|
|
45
|
+
* Where on a fall the potential and kinetic energies stand in a given ratio.
|
|
46
|
+
*
|
|
47
|
+
* Their Example-19 asks where the potential energy is twice the kinetic during a 300 m fall, and it
|
|
48
|
+
* is a good question because the mass and `g` both cancel and the answer is a pure fraction of the
|
|
49
|
+
* height. `ratio` is potential-to-kinetic, so 2 means "potential is twice kinetic".
|
|
50
|
+
*
|
|
51
|
+
* Returns the height ABOVE THE GROUND, which is what such a question asks for, rather than the
|
|
52
|
+
* distance fallen, which is what the algebra naturally produces. Confusing the two is the trap.
|
|
53
|
+
*/
|
|
54
|
+
declare function heightWherePotentialIs(dropFrom: number, ratio: number, sf?: number): {
|
|
55
|
+
readonly heightAboveGround: number;
|
|
56
|
+
readonly distanceFallen: number;
|
|
57
|
+
readonly worked: Worked;
|
|
58
|
+
};
|
|
59
|
+
interface SwingResult {
|
|
60
|
+
/** How far the bob rose: `l(1 − cos θ)`. */
|
|
61
|
+
readonly rise: number;
|
|
62
|
+
/** Speed at the lowest point. */
|
|
63
|
+
readonly speed: number;
|
|
64
|
+
/** Horizontal distance of the bob from the vertical through the pivot, at the extreme. */
|
|
65
|
+
readonly offset: number;
|
|
66
|
+
readonly worked: Worked;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A pendulum released from an angle: how high the bob started, and how fast it passes the bottom.
|
|
70
|
+
*
|
|
71
|
+
* `h = l(1 − cos θ)` is the only real content, and it is geometry rather than physics. The bob hangs
|
|
72
|
+
* `l cos θ` below the pivot at the extreme and `l` below it at the bottom, so it fell the difference.
|
|
73
|
+
* Learners who memorise `l(1 − cos θ)` without that picture reliably write `l sin θ`, which is the
|
|
74
|
+
* sideways offset and is also returned here so the two can be seen side by side and never confused
|
|
75
|
+
* again.
|
|
76
|
+
*/
|
|
77
|
+
declare function pendulumSwing(length: number, releaseAngleDeg: number, g?: number, sf?: number): SwingResult;
|
|
78
|
+
/** The angle a pendulum must be released from to pass the bottom at a stated speed. */
|
|
79
|
+
declare function releaseAngleForSpeed(length: number, speed: number, g?: number, sf?: number): Worked;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { Ladder, Rung, Station, SwingResult, dropForKinetic, energyLadder, heightWherePotentialIs, pendulumSwing, releaseAngleForSpeed, speedAfterDrop };
|
|
@@ -0,0 +1,129 @@
|
|
|
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/energy/conservation.ts
|
|
6
|
+
/**
|
|
7
|
+
* Conservation of mechanical energy: the accountant's view of motion.
|
|
8
|
+
*
|
|
9
|
+
* Everything here could be done with SUVAT instead, and for a straight drop it would be no harder.
|
|
10
|
+
* The reason to reach for energy is that energy DOES NOT CARE ABOUT THE PATH. A bead on a wire, a
|
|
11
|
+
* pendulum bob, a ball down a curved slide: the speed at the bottom depends on the drop and on
|
|
12
|
+
* nothing else, and no kinematic equation will tell you that because the acceleration is changing
|
|
13
|
+
* direction the whole way down. That is the aha, and it is why a pendulum is the standard first
|
|
14
|
+
* example rather than a dropped stone.
|
|
15
|
+
*
|
|
16
|
+
* THE ENERGY LADDER is the model this module returns. A journey is a list of stations; at each one
|
|
17
|
+
* the energy is split between a kinetic pile and a potential pile, and if the total shrinks from one
|
|
18
|
+
* station to the next, that shortfall went somewhere and can be named. Setting a problem out this
|
|
19
|
+
* way turns "where did the energy go" from a rhetorical question into a column you can read.
|
|
20
|
+
*
|
|
21
|
+
* Pure: no React, no pixels.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Track the two piles of energy across a journey.
|
|
25
|
+
*
|
|
26
|
+
* The tolerance is relative to the largest total, for the same reason it is in `isBalanced`: a
|
|
27
|
+
* shortfall of a millijoule is nothing in a roller coaster and is everything in a pendulum swinging
|
|
28
|
+
* in a lecture demonstration.
|
|
29
|
+
*/
|
|
30
|
+
function energyLadder(mass, stations, g = G_EARTH, sf = 3) {
|
|
31
|
+
if (stations.length === 0) throw new Error("A ladder with no stations describes no journey.");
|
|
32
|
+
const rungs = [];
|
|
33
|
+
let previousTotal = null;
|
|
34
|
+
for (const s of stations) {
|
|
35
|
+
const kinetic = .5 * mass * s.speed * s.speed;
|
|
36
|
+
const potential = mass * g * s.height;
|
|
37
|
+
const total = kinetic + potential;
|
|
38
|
+
const lostSincePrevious = previousTotal === null ? 0 : Math.max(0, previousTotal - total);
|
|
39
|
+
rungs.push({
|
|
40
|
+
label: s.label,
|
|
41
|
+
kinetic,
|
|
42
|
+
potential,
|
|
43
|
+
total,
|
|
44
|
+
lostSincePrevious
|
|
45
|
+
});
|
|
46
|
+
previousTotal = total;
|
|
47
|
+
}
|
|
48
|
+
const largest = rungs.reduce((m, r) => Math.max(m, Math.abs(r.total)), 0);
|
|
49
|
+
const totalLost = rungs.reduce((sum, r) => sum + r.lostSincePrevious, 0);
|
|
50
|
+
const conserved = totalLost <= Math.max(largest, 1) * 1e-9;
|
|
51
|
+
const w = calc().step("E_k + E_p = \\text{constant}", "true only when nothing takes energy out. Any shortfall between two stations is the measure of what did");
|
|
52
|
+
for (const r of rungs) w.step(`\\text{${r.label}}: E_k = ${texSigFigs(r.kinetic, sf)},\\ E_p = ${texSigFigs(r.potential, sf)},\\ \\text{total} = ${texSigFigs(r.total, sf)}\\ \\mathrm{J}`, r.lostSincePrevious > 0 ? `${texSigFigs(r.lostSincePrevious, sf)} J went missing since the last station` : void 0);
|
|
53
|
+
w.step(conserved ? "\\text{total unchanged throughout}" : `\\text{lost} = ${texSigFigs(totalLost, sf)}\\ \\mathrm{J}`, conserved ? "mechanical energy was conserved, so the journey was smooth and nothing was pushed" : "this did not vanish. It became heat, sound, or deformation, and naming which is part of the answer");
|
|
54
|
+
return {
|
|
55
|
+
rungs,
|
|
56
|
+
totalLost,
|
|
57
|
+
conserved,
|
|
58
|
+
worked: w.done(totalLost)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The speed reached after falling through a height, from energy: `v = √(2gh)`.
|
|
63
|
+
*
|
|
64
|
+
* The mass cancels, which is the point and is the same fact that makes a feather and a hammer land
|
|
65
|
+
* together on the Moon. The path does not appear at all, which is the harder and more useful point:
|
|
66
|
+
* this is the speed at the bottom of a slide, a curved ramp, or a swing, not only of a vertical drop.
|
|
67
|
+
*/
|
|
68
|
+
function speedAfterDrop(height, g = G_EARTH, sf = 3) {
|
|
69
|
+
if (height < 0) throw new Error("A negative drop is a rise, and a body does not gain speed rising.");
|
|
70
|
+
const value = Math.sqrt(2 * g * height);
|
|
71
|
+
return calc().step("mgh = \\tfrac{1}{2}mv^2", "all the potential energy given up becomes kinetic energy").step("v = \\sqrt{2gh}", "the mass cancels from both sides, so a heavy body and a light one arrive at the same speed").step(`v = \\sqrt{2 \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(height, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{m\\,s^{-1}}`, "and the shape of the path never entered the working, so this is the speed at the bottom of any smooth route down").done(value);
|
|
72
|
+
}
|
|
73
|
+
/** The height a body of known kinetic energy fell from: the drop run backwards. */
|
|
74
|
+
function dropForKinetic(mass, kinetic, g = G_EARTH, sf = 3) {
|
|
75
|
+
const value = kinetic / (mass * g);
|
|
76
|
+
return calc().step("mgh = E_k \\Rightarrow h = \\frac{E_k}{mg}").step(`h = \\frac{${texSigFigs(kinetic, sf)}}{${texSigFigs(mass, sf)} \\times ${texSigFigs(g, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{m}`).done(value);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Where on a fall the potential and kinetic energies stand in a given ratio.
|
|
80
|
+
*
|
|
81
|
+
* Their Example-19 asks where the potential energy is twice the kinetic during a 300 m fall, and it
|
|
82
|
+
* is a good question because the mass and `g` both cancel and the answer is a pure fraction of the
|
|
83
|
+
* height. `ratio` is potential-to-kinetic, so 2 means "potential is twice kinetic".
|
|
84
|
+
*
|
|
85
|
+
* Returns the height ABOVE THE GROUND, which is what such a question asks for, rather than the
|
|
86
|
+
* distance fallen, which is what the algebra naturally produces. Confusing the two is the trap.
|
|
87
|
+
*/
|
|
88
|
+
function heightWherePotentialIs(dropFrom, ratio, sf = 3) {
|
|
89
|
+
if (ratio <= 0) throw new Error("A ratio of potential to kinetic energy must be positive during a fall.");
|
|
90
|
+
const distanceFallen = dropFrom / (ratio + 1);
|
|
91
|
+
const heightAboveGround = dropFrom - distanceFallen;
|
|
92
|
+
return {
|
|
93
|
+
heightAboveGround,
|
|
94
|
+
distanceFallen,
|
|
95
|
+
worked: calc().step("E_k = mgx, \\quad E_p = mg(h - x)", "after falling x, the energy given up is mgx and what is left of the store is mg(h - x)").step(`\\frac{E_p}{E_k} = \\frac{h - x}{x} = ${texSigFigs(ratio, sf)}`, "the mass and g cancel, so the answer is a pure fraction of the height and holds for any body").step(`x = \\frac{h}{${texSigFigs(ratio, sf)} + 1} = \\frac{${texSigFigs(dropFrom, sf)}}{${texSigFigs(ratio + 1, sf)}} = ${texSigFigs(distanceFallen, sf)}\\ \\mathrm{m}`, "this is the distance FALLEN").step(`h - x = ${texSigFigs(heightAboveGround, sf)}\\ \\mathrm{m}`, "and this is the height above the ground, which is what the question asked for. Stopping one line early is the trap").done(heightAboveGround)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A pendulum released from an angle: how high the bob started, and how fast it passes the bottom.
|
|
100
|
+
*
|
|
101
|
+
* `h = l(1 − cos θ)` is the only real content, and it is geometry rather than physics. The bob hangs
|
|
102
|
+
* `l cos θ` below the pivot at the extreme and `l` below it at the bottom, so it fell the difference.
|
|
103
|
+
* Learners who memorise `l(1 − cos θ)` without that picture reliably write `l sin θ`, which is the
|
|
104
|
+
* sideways offset and is also returned here so the two can be seen side by side and never confused
|
|
105
|
+
* again.
|
|
106
|
+
*/
|
|
107
|
+
function pendulumSwing(length, releaseAngleDeg, g = G_EARTH, sf = 4) {
|
|
108
|
+
const rad = toRadians(releaseAngleDeg);
|
|
109
|
+
const rise = length * (1 - Math.cos(rad));
|
|
110
|
+
const offset = length * Math.sin(rad);
|
|
111
|
+
const speed = Math.sqrt(2 * g * rise);
|
|
112
|
+
return {
|
|
113
|
+
rise,
|
|
114
|
+
speed,
|
|
115
|
+
offset,
|
|
116
|
+
worked: calc().step("h = l - l\\cos\\theta = l(1 - \\cos\\theta)", "at the extreme the bob hangs l cos theta below the pivot; at the bottom it hangs l below. It fell the difference").step(`h = ${texSigFigs(length, sf)}(1 - \\cos ${texSigFigs(releaseAngleDeg, sf)}^\\circ) = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`l\\sin\\theta = ${texSigFigs(offset, sf)}\\ \\mathrm{m}`, "the SIDEWAYS offset, not the rise. Writing this into mgh is the standard slip").step("mgh = \\tfrac{1}{2}mv^2 \\Rightarrow v = \\sqrt{2gl(1 - \\cos\\theta)}", "the string tension does no work: it is always perpendicular to the motion, so it never appears").step(`v = ${texSigFigs(speed, sf)}\\ \\mathrm{m\\,s^{-1}}`, "at the lowest point of the swing").done(speed)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** The angle a pendulum must be released from to pass the bottom at a stated speed. */
|
|
120
|
+
function releaseAngleForSpeed(length, speed, g = G_EARTH, sf = 3) {
|
|
121
|
+
const rise = speed * speed / (2 * g);
|
|
122
|
+
const cos = 1 - rise / length;
|
|
123
|
+
if (cos < -1) throw new Error(`Reaching ${speed} m/s needs a drop of ${rise.toPrecision(3)} m, but a pendulum of length ${length} m can only ever drop ${(2 * length).toPrecision(3)} m, from straight up.`);
|
|
124
|
+
const value = toDegrees(Math.acos(cos));
|
|
125
|
+
return calc().step("h = \\frac{v^2}{2g}", "the drop the speed implies").step(`h = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`\\cos\\theta = 1 - \\frac{h}{l} = 1 - \\frac{${texSigFigs(rise, sf)}}{${texSigFigs(length, sf)}} = ${texSigFigs(cos, sf)}`).step(`\\theta = ${texSigFigs(value, sf)}^\\circ`, "measured from the downward vertical").done(value);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//#endregion
|
|
129
|
+
export { dropForKinetic, energyLadder, heightWherePotentialIs, pendulumSwing, releaseAngleForSpeed, speedAfterDrop };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Worked } from "../../core/worked.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/physics/energy/power.d.ts
|
|
4
|
+
/** Mechanical (imperial) horsepower, 550 ft lb per second. What "h.p." means in a physics paper. */
|
|
5
|
+
declare const HORSEPOWER = 745.699872;
|
|
6
|
+
/** Metric horsepower (PS, cv), the one used in European car brochures. Not what exams mean. */
|
|
7
|
+
declare const HORSEPOWER_METRIC = 735.49875;
|
|
8
|
+
/** Watts to horsepower. */
|
|
9
|
+
declare const toHorsepower: (watts: number, unit?: number) => number;
|
|
10
|
+
/** `P = W/t`. */
|
|
11
|
+
declare function power(work: number, time: number, sf?: number): Worked;
|
|
12
|
+
/**
|
|
13
|
+
* `P = Fv`, the steady-speed form.
|
|
14
|
+
*
|
|
15
|
+
* Derived in the first step rather than quoted, because the derivation is the whole reason a learner
|
|
16
|
+
* can choose between the two forms instead of guessing.
|
|
17
|
+
*/
|
|
18
|
+
declare function powerFromForceSpeed(force: number, speed: number, sf?: number): Worked;
|
|
19
|
+
/** The steady speed a stated power can sustain against a stated resisting force: `v = P/F`. */
|
|
20
|
+
declare function speedFromPower(availablePower: number, resistance: number, sf?: number): Worked;
|
|
21
|
+
interface EfficiencyResult {
|
|
22
|
+
/** As a fraction from 0 to 1. */
|
|
23
|
+
readonly fraction: number;
|
|
24
|
+
readonly percent: number;
|
|
25
|
+
/** Power (or energy) that did not do the wanted job. */
|
|
26
|
+
readonly wasted: number;
|
|
27
|
+
readonly worked: Worked;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Useful out over total in.
|
|
31
|
+
*
|
|
32
|
+
* The trap is not the arithmetic, it is which way up. "A motor is 90 per cent efficient and lifts
|
|
33
|
+
* water at 7.2 m" means the LIFTING is the 90 per cent and the electrical supply is the 100 per
|
|
34
|
+
* cent, so the useful output is `0.9 × input`, and dividing instead of multiplying gives an answer
|
|
35
|
+
* that is wrong by a factor of 1.23 and looks entirely reasonable.
|
|
36
|
+
*/
|
|
37
|
+
declare function efficiency(usefulOutput: number, totalInput: number, sf?: number): EfficiencyResult;
|
|
38
|
+
/**
|
|
39
|
+
* Stages in series: the efficiencies MULTIPLY.
|
|
40
|
+
*
|
|
41
|
+
* An 80 per cent motor driving a 50 per cent crane is 40 per cent overall, not 65 and not 130. Each
|
|
42
|
+
* stage takes its cut of whatever reached it, which is why a long chain of quite good machines can
|
|
43
|
+
* still be dreadful end to end.
|
|
44
|
+
*/
|
|
45
|
+
declare function chainEfficiency(stages: readonly number[], sf?: number): EfficiencyResult;
|
|
46
|
+
/** Useful output power from an input and an efficiency: the direction most questions need. */
|
|
47
|
+
declare function usefulOutput(inputPower: number, efficiencyFraction: number, sf?: number): Worked;
|
|
48
|
+
interface LiftingPower {
|
|
49
|
+
/** The force the machine must exert, newtons. */
|
|
50
|
+
readonly force: number;
|
|
51
|
+
/** Power at the load, before any efficiency is applied. */
|
|
52
|
+
readonly usefulPower: number;
|
|
53
|
+
/** Power the supply must deliver once the efficiency is taken into account. */
|
|
54
|
+
readonly inputPower: number;
|
|
55
|
+
readonly horsepower: number;
|
|
56
|
+
readonly worked: Worked;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A hoist or a lift cage raising a load at a steady speed, against a stated friction.
|
|
60
|
+
*
|
|
61
|
+
* Their Example-29, and the reason it is a good question is that it is `P = Fv` with a force that
|
|
62
|
+
* has to be ASSEMBLED first: the weight of the cage, the weight of the load, and the friction, all
|
|
63
|
+
* of which the motor must overcome at once. Getting the power right is easy; getting the force right
|
|
64
|
+
* is where the question lives.
|
|
65
|
+
*/
|
|
66
|
+
declare function hoistPower(cageMass: number, loadMass: number, speed: number, friction?: number, g?: number, efficiencyFraction?: number, sf?: number): LiftingPower;
|
|
67
|
+
/**
|
|
68
|
+
* Pumping a mass of liquid through a mean lift, in a stated time.
|
|
69
|
+
*
|
|
70
|
+
* `meanLift` is deliberately a parameter and not computed from a depth, because THE MEAN LIFT IS THE
|
|
71
|
+
* WHOLE DIFFICULTY and it depends on the shape of what is being emptied. Pumping from a tank at a
|
|
72
|
+
* fixed level lifts every kilogram the same distance. Emptying a well lifts the top layer barely at
|
|
73
|
+
* all and the bottom layer the full depth, so the mean is the depth to the centre of mass of the
|
|
74
|
+
* water, which for a uniform column is half the depth. Getting that wrong is a factor of two, and it
|
|
75
|
+
* is the single most common error in this family of questions.
|
|
76
|
+
*
|
|
77
|
+
* `centreOfMassLift` and `columnDrain` in `centre-of-mass.ts` compute that mean for the standard
|
|
78
|
+
* shapes, and feed it here.
|
|
79
|
+
*/
|
|
80
|
+
declare function pumpPower(mass: number, meanLift: number, time: number, g?: number, efficiencyFraction?: number, sf?: number): LiftingPower;
|
|
81
|
+
/**
|
|
82
|
+
* How much a machine of stated input power and efficiency can raise in a given time.
|
|
83
|
+
*
|
|
84
|
+
* Their Example-27 inverted into the form the question actually asks: kilograms per minute, given
|
|
85
|
+
* the motor rating. Worth having as its own function because the rearrangement puts `g` and `h` in
|
|
86
|
+
* the denominator, and a learner who rearranges under pressure tends to leave one of them upstairs.
|
|
87
|
+
*/
|
|
88
|
+
declare function massRaisedInTime(inputPower: number, efficiencyFraction: number, height: number, time: number, g?: number, sf?: number): Worked;
|
|
89
|
+
//#endregion
|
|
90
|
+
export { EfficiencyResult, HORSEPOWER, HORSEPOWER_METRIC, LiftingPower, chainEfficiency, efficiency, hoistPower, massRaisedInTime, power, powerFromForceSpeed, pumpPower, speedFromPower, toHorsepower, usefulOutput };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { calc, texSigFigs } from "../../core/worked.mjs";
|
|
2
|
+
import { G_EARTH } from "../kinematics/free-fall.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/physics/energy/power.ts
|
|
5
|
+
/**
|
|
6
|
+
* Power: the rate, not the amount, and the confusion that costs the most marks in this chapter.
|
|
7
|
+
*
|
|
8
|
+
* WORK AND POWER ARE NOT THE SAME KIND OF THING and a surprising number of wrong answers come from
|
|
9
|
+
* treating them as interchangeable. Carrying a load up four flights of stairs is the same WORK
|
|
10
|
+
* whether you stroll or sprint; sprinting is more POWER. A question that gives a time is almost
|
|
11
|
+
* always a power question, and a question that does not give a time cannot be one.
|
|
12
|
+
*
|
|
13
|
+
* THE TWO FORMS ARE THE SAME FORM.
|
|
14
|
+
*
|
|
15
|
+
* `P = W/t` and `P = Fv` look like separate facts and are one line apart: `W = Fd`, so
|
|
16
|
+
* `P = Fd/t = Fv`. Knowing that, the choice between them stops being a memory problem and becomes
|
|
17
|
+
* a question of which quantity you were handed. Given a time, use the first; given a steady speed,
|
|
18
|
+
* use the second.
|
|
19
|
+
*
|
|
20
|
+
* `P = Fv` also carries the answer to "why does a car have a top speed". At constant speed the
|
|
21
|
+
* engine's force exactly balances the resistance, and since `P = Fv` with `P` capped, the speed can
|
|
22
|
+
* only rise until the resistance has eaten the whole power budget.
|
|
23
|
+
*
|
|
24
|
+
* ABOUT HORSEPOWER. It is not an SI unit and there are two of them, which is exactly the sort of
|
|
25
|
+
* detail that turns a correct method into a wrong number. Both are defined here with their sizes,
|
|
26
|
+
* and {@link HORSEPOWER} is the mechanical one at 745.7 W, because that is the one every exam board
|
|
27
|
+
* in this market means when it prints "h.p.".
|
|
28
|
+
*
|
|
29
|
+
* Pure: no React, no pixels.
|
|
30
|
+
*/
|
|
31
|
+
/** Mechanical (imperial) horsepower, 550 ft lb per second. What "h.p." means in a physics paper. */
|
|
32
|
+
const HORSEPOWER = 745.699872;
|
|
33
|
+
/** Metric horsepower (PS, cv), the one used in European car brochures. Not what exams mean. */
|
|
34
|
+
const HORSEPOWER_METRIC = 735.49875;
|
|
35
|
+
/** Watts to horsepower. */
|
|
36
|
+
const toHorsepower = (watts, unit = HORSEPOWER) => watts / unit;
|
|
37
|
+
/** `P = W/t`. */
|
|
38
|
+
function power(work, time, sf = 3) {
|
|
39
|
+
if (time <= 0) throw new Error("Power is work per unit time, and no time means no rate to report.");
|
|
40
|
+
const value = work / time;
|
|
41
|
+
return calc().step("P = \\frac{W}{t}", "power is a RATE. The same work done in half the time is twice the power").step(`P = \\frac{${texSigFigs(work, sf)}}{${texSigFigs(time, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{W}`).step(`= ${texSigFigs(toHorsepower(value), sf)}\\ \\mathrm{h.p.}`, "one horsepower is 745.7 W. Metric horsepower is 735.5 W, and picking the wrong one is worth about one per cent").done(value);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* `P = Fv`, the steady-speed form.
|
|
45
|
+
*
|
|
46
|
+
* Derived in the first step rather than quoted, because the derivation is the whole reason a learner
|
|
47
|
+
* can choose between the two forms instead of guessing.
|
|
48
|
+
*/
|
|
49
|
+
function powerFromForceSpeed(force, speed, sf = 3) {
|
|
50
|
+
const value = force * speed;
|
|
51
|
+
return calc().step("P = \\frac{W}{t} = \\frac{Fd}{t} = F\\frac{d}{t} = Fv", "not a second formula. It is P = W/t with W = Fd substituted and d/t recognised as the speed").step(`P = ${texSigFigs(force, sf)} \\times ${texSigFigs(speed, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{W}`).done(value);
|
|
52
|
+
}
|
|
53
|
+
/** The steady speed a stated power can sustain against a stated resisting force: `v = P/F`. */
|
|
54
|
+
function speedFromPower(availablePower, resistance, sf = 3) {
|
|
55
|
+
if (resistance <= 0) throw new Error("With no resistance the speed is not limited by the power, so it has no steady value.");
|
|
56
|
+
const value = availablePower / resistance;
|
|
57
|
+
return calc().step("P = Fv \\Rightarrow v = \\frac{P}{F}", "at a steady speed the driving force exactly balances the resistance, so F is the resistance").step(`v = \\frac{${texSigFigs(availablePower, sf)}}{${texSigFigs(resistance, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{m\\,s^{-1}}`, "this is the top speed: the resistance has absorbed the entire power budget, so nothing is left to accelerate with").done(value);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Useful out over total in.
|
|
61
|
+
*
|
|
62
|
+
* The trap is not the arithmetic, it is which way up. "A motor is 90 per cent efficient and lifts
|
|
63
|
+
* water at 7.2 m" means the LIFTING is the 90 per cent and the electrical supply is the 100 per
|
|
64
|
+
* cent, so the useful output is `0.9 × input`, and dividing instead of multiplying gives an answer
|
|
65
|
+
* that is wrong by a factor of 1.23 and looks entirely reasonable.
|
|
66
|
+
*/
|
|
67
|
+
function efficiency(usefulOutput, totalInput, sf = 3) {
|
|
68
|
+
if (totalInput <= 0) throw new Error("Efficiency compares output with input, and there was no input.");
|
|
69
|
+
if (usefulOutput > totalInput) throw new Error(`A useful output of ${usefulOutput} cannot exceed an input of ${totalInput}. An efficiency above 100 per cent means the two have been divided the wrong way round, or a loss has been counted as an output.`);
|
|
70
|
+
const fraction = usefulOutput / totalInput;
|
|
71
|
+
const wasted = totalInput - usefulOutput;
|
|
72
|
+
const worked = calc().step("\\eta = \\frac{\\text{useful output}}{\\text{total input}}", "always a fraction below 1. If you get more than 1, the division is upside down").step(`\\eta = \\frac{${texSigFigs(usefulOutput, sf)}}{${texSigFigs(totalInput, sf)}} = ${texSigFigs(fraction, sf)} = ${texSigFigs(fraction * 100, sf)}\\%`).step(`\\text{wasted} = ${texSigFigs(wasted, sf)}`, "mostly heat. It is not destroyed, it is just no longer doing the job you wanted").done(fraction);
|
|
73
|
+
return {
|
|
74
|
+
fraction,
|
|
75
|
+
percent: fraction * 100,
|
|
76
|
+
wasted,
|
|
77
|
+
worked
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Stages in series: the efficiencies MULTIPLY.
|
|
82
|
+
*
|
|
83
|
+
* An 80 per cent motor driving a 50 per cent crane is 40 per cent overall, not 65 and not 130. Each
|
|
84
|
+
* stage takes its cut of whatever reached it, which is why a long chain of quite good machines can
|
|
85
|
+
* still be dreadful end to end.
|
|
86
|
+
*/
|
|
87
|
+
function chainEfficiency(stages, sf = 3) {
|
|
88
|
+
if (stages.length === 0) throw new Error("A chain with no stages has nothing to be efficient at.");
|
|
89
|
+
const fraction = stages.reduce((product, s) => product * s, 1);
|
|
90
|
+
const worked = calc().step("\\eta_{\\text{total}} = \\eta_1 \\times \\eta_2 \\times \\ldots", "each stage takes its cut of what reached it, so the fractions multiply. They never add and never average").step(`\\eta = ${stages.map((s) => texSigFigs(s, sf)).join(" \\times ")} = ${texSigFigs(fraction, sf)} = ${texSigFigs(fraction * 100, sf)}\\%`).done(fraction);
|
|
91
|
+
return {
|
|
92
|
+
fraction,
|
|
93
|
+
percent: fraction * 100,
|
|
94
|
+
wasted: 1 - fraction,
|
|
95
|
+
worked
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** Useful output power from an input and an efficiency: the direction most questions need. */
|
|
99
|
+
function usefulOutput(inputPower, efficiencyFraction, sf = 3) {
|
|
100
|
+
const value = inputPower * efficiencyFraction;
|
|
101
|
+
return calc().step("P_{\\text{out}} = \\eta P_{\\text{in}}", "the efficiency MULTIPLIES the input. Dividing gives more out than in, which is the giveaway").step(`P_{\\text{out}} = ${texSigFigs(efficiencyFraction, sf)} \\times ${texSigFigs(inputPower, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{W}`).done(value);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A hoist or a lift cage raising a load at a steady speed, against a stated friction.
|
|
105
|
+
*
|
|
106
|
+
* Their Example-29, and the reason it is a good question is that it is `P = Fv` with a force that
|
|
107
|
+
* has to be ASSEMBLED first: the weight of the cage, the weight of the load, and the friction, all
|
|
108
|
+
* of which the motor must overcome at once. Getting the power right is easy; getting the force right
|
|
109
|
+
* is where the question lives.
|
|
110
|
+
*/
|
|
111
|
+
function hoistPower(cageMass, loadMass, speed, friction = 0, g = G_EARTH, efficiencyFraction = 1, sf = 4) {
|
|
112
|
+
const force = (cageMass + loadMass) * g + friction;
|
|
113
|
+
const usefulPowerValue = force * speed;
|
|
114
|
+
const inputPower = usefulPowerValue / efficiencyFraction;
|
|
115
|
+
const worked = calc().step("F = (m_{\\text{cage}} + m_{\\text{load}})g + f", "the motor holds up everything it is carrying AND beats the friction. Assembling this force is the actual question").step(`F = (${texSigFigs(cageMass, sf)} + ${texSigFigs(loadMass, sf)}) \\times ${texSigFigs(g, sf)} + ${texSigFigs(friction, sf)} = ${texSigFigs(force, sf)}\\ \\mathrm{N}`).step(`P = Fv = ${texSigFigs(force, sf)} \\times ${texSigFigs(speed, sf)} = ${texSigFigs(usefulPowerValue, sf)}\\ \\mathrm{W}`, "steady speed, so there is no acceleration term and the force is exactly what is resisting");
|
|
116
|
+
if (efficiencyFraction !== 1) worked.step(`P_{\\text{in}} = \\frac{P}{\\eta} = ${texSigFigs(inputPower, sf)}\\ \\mathrm{W}`, "the supply must deliver more than the load receives, because some is lost on the way");
|
|
117
|
+
return {
|
|
118
|
+
force,
|
|
119
|
+
usefulPower: usefulPowerValue,
|
|
120
|
+
inputPower,
|
|
121
|
+
horsepower: toHorsepower(inputPower),
|
|
122
|
+
worked: worked.done(inputPower)
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Pumping a mass of liquid through a mean lift, in a stated time.
|
|
127
|
+
*
|
|
128
|
+
* `meanLift` is deliberately a parameter and not computed from a depth, because THE MEAN LIFT IS THE
|
|
129
|
+
* WHOLE DIFFICULTY and it depends on the shape of what is being emptied. Pumping from a tank at a
|
|
130
|
+
* fixed level lifts every kilogram the same distance. Emptying a well lifts the top layer barely at
|
|
131
|
+
* all and the bottom layer the full depth, so the mean is the depth to the centre of mass of the
|
|
132
|
+
* water, which for a uniform column is half the depth. Getting that wrong is a factor of two, and it
|
|
133
|
+
* is the single most common error in this family of questions.
|
|
134
|
+
*
|
|
135
|
+
* `centreOfMassLift` and `columnDrain` in `centre-of-mass.ts` compute that mean for the standard
|
|
136
|
+
* shapes, and feed it here.
|
|
137
|
+
*/
|
|
138
|
+
function pumpPower(mass, meanLift, time, g = G_EARTH, efficiencyFraction = 1, sf = 4) {
|
|
139
|
+
if (time <= 0) throw new Error("Power is a rate, so the pumping has to take some time.");
|
|
140
|
+
const force = mass * g;
|
|
141
|
+
const work = force * meanLift;
|
|
142
|
+
const usefulPowerValue = work / time;
|
|
143
|
+
const inputPower = usefulPowerValue / efficiencyFraction;
|
|
144
|
+
const worked = calc().step("W = mg\\bar{h}", "h-bar is the MEAN lift, the distance the centre of mass of the liquid rose. Not the depth, unless every drop rose the same amount").step(`W = ${texSigFigs(mass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(meanLift, sf)} = ${texSigFigs(work, sf)}\\ \\mathrm{J}`).step(`P = \\frac{W}{t} = \\frac{${texSigFigs(work, sf)}}{${texSigFigs(time, sf)}} = ${texSigFigs(usefulPowerValue, sf)}\\ \\mathrm{W}`).step(`= ${texSigFigs(toHorsepower(inputPower), sf)}\\ \\mathrm{h.p.}`, "dividing by 745.7 W. Using the depth instead of the mean lift here would double the answer").done(inputPower);
|
|
145
|
+
return {
|
|
146
|
+
force,
|
|
147
|
+
usefulPower: usefulPowerValue,
|
|
148
|
+
inputPower,
|
|
149
|
+
horsepower: toHorsepower(inputPower),
|
|
150
|
+
worked
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* How much a machine of stated input power and efficiency can raise in a given time.
|
|
155
|
+
*
|
|
156
|
+
* Their Example-27 inverted into the form the question actually asks: kilograms per minute, given
|
|
157
|
+
* the motor rating. Worth having as its own function because the rearrangement puts `g` and `h` in
|
|
158
|
+
* the denominator, and a learner who rearranges under pressure tends to leave one of them upstairs.
|
|
159
|
+
*/
|
|
160
|
+
function massRaisedInTime(inputPower, efficiencyFraction, height, time, g = G_EARTH, sf = 4) {
|
|
161
|
+
const useful = inputPower * efficiencyFraction;
|
|
162
|
+
const value = useful * time / (g * height);
|
|
163
|
+
return calc().step("P_{\\text{useful}} = \\eta P_{\\text{in}} = \\frac{mgh}{t}", "only the useful share of the supply ends up in the load. The rest is lost in the machine").step(`P_{\\text{useful}} = ${texSigFigs(efficiencyFraction, sf)} \\times ${texSigFigs(inputPower, sf)} = ${texSigFigs(useful, sf)}\\ \\mathrm{W}`).step("m = \\frac{\\eta P_{\\text{in}} t}{gh}", "both g and h belong in the denominator. Dropping either is the usual rearrangement slip").step(`m = \\frac{${texSigFigs(useful, sf)} \\times ${texSigFigs(time, sf)}}{${texSigFigs(g, sf)} \\times ${texSigFigs(height, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{kg}`).done(value);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//#endregion
|
|
167
|
+
export { HORSEPOWER, HORSEPOWER_METRIC, chainEfficiency, efficiency, hoistPower, massRaisedInTime, power, powerFromForceSpeed, pumpPower, speedFromPower, toHorsepower, usefulOutput };
|