feat: initial release
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Command pendulum computes the exact period of a simple pendulum at
|
||||
// large amplitude through the complete elliptic integral of the first
|
||||
// kind, and shows how far the small-angle formula drifts once the
|
||||
// release angle stops being small. The period is
|
||||
//
|
||||
// T = 4·sqrt(L/g)·K(sin²(θ₀/2)),
|
||||
//
|
||||
// where K is EllipticK with the m = k² parameter convention.
|
||||
//
|
||||
// Usage: go run ./examples/pendulum
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"sourcedock.dev/petrbalvin/tensor"
|
||||
)
|
||||
|
||||
// kComplete evaluates EllipticK at a single parameter.
|
||||
func kComplete(m float64) float64 {
|
||||
arr, err := tensor.FromFloats([]float64{m}, 1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
k, err := tensor.EllipticK(arr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
v, _ := tensor.FloatAt(k, 0)
|
||||
return v
|
||||
}
|
||||
|
||||
func main() {
|
||||
const (
|
||||
length = 1.0 // metres
|
||||
grav = 9.80665
|
||||
)
|
||||
small := 2 * math.Pi * math.Sqrt(length/grav)
|
||||
|
||||
fmt.Println("release angle exact period small-angle period drift")
|
||||
for _, deg := range []float64{5, 15, 30, 45, 60, 90, 120, 170} {
|
||||
theta := deg * math.Pi / 180
|
||||
m := math.Sin(theta/2) * math.Sin(theta/2)
|
||||
period := 4 * math.Sqrt(length/grav) * kComplete(m)
|
||||
drift := (period/small - 1) * 100
|
||||
fmt.Printf("%10.0f° %12.6f s %14.6f s %+6.2f %%\n",
|
||||
deg, period, small, drift)
|
||||
}
|
||||
|
||||
// The inverse problem: which release angle doubles the small-angle
|
||||
// period? Bisection on the angle, the period being monotone in it.
|
||||
target := 2 * small
|
||||
lo, hi := 0.0, math.Pi
|
||||
angle := 0.0
|
||||
for range 80 {
|
||||
mid := (lo + hi) / 2
|
||||
m := math.Sin(mid/2) * math.Sin(mid/2)
|
||||
if 4*math.Sqrt(length/grav)*kComplete(m) < target {
|
||||
lo = mid
|
||||
} else {
|
||||
hi = mid
|
||||
}
|
||||
angle = mid
|
||||
}
|
||||
fmt.Printf("\na release angle of %.2f° doubles the period (%.4f s)\n",
|
||||
angle*180/math.Pi, target)
|
||||
}
|
||||
Reference in New Issue
Block a user