|
| 1 | ++++ |
| 2 | +bibfile = "mechphys.json" |
| 3 | ++++ |
| 4 | + |
| 5 | +The **simple harmonic oscillator** (SHO) captures the core oscillatory behavior of [[waves]], without any spatial dimensions to bother with. It can be seen as the 0-dimensional version of a wave, where the force that drives the oscillation comes not from neighbors, but from the position (height) of the wave itself. As such, it provides a potentially interesting role in the mechanics of [[stochastic particles]] because it can be entirely localized to one discrete grid cell within the [[cellular automaton]] framework. Thus, a particle in this view can be considered to be a simple harmonic oscillator that periodically jumps between cells. |
| 6 | + |
| 7 | +The basic equations from [[waves]] for the SHO are: |
| 8 | + |
| 9 | +{id="eq_force" title="restoring force"} |
| 10 | +$$ |
| 11 | +f = -c^2 y^t |
| 12 | +$$ |
| 13 | + |
| 14 | +where $c$ is the basic rate update constant, analogous to the speed of light in waves, which determines the effective strength of the restoring force, and thus the oscillation rate. The _t_ suffix indicates the time step (only for variables that require integration over time). Everything else from this point onward is the same, in the basic Newtonian physics framework of acceleration, velocity, and position: |
| 15 | + |
| 16 | +{id="eq_a" title="acceleration"} |
| 17 | +$$ |
| 18 | +a = \frac{f}{m} |
| 19 | +$$ |
| 20 | + |
| 21 | +{id="eq_" title="new velocity"} |
| 22 | +$$ |
| 23 | +v^{t+1} = v^t + a |
| 24 | +$$ |
| 25 | + |
| 26 | +{id="eq_" title="new state"} |
| 27 | +$$ |
| 28 | +y^{t+1} = y^t + v^{t+1} |
| 29 | +$$ |
| 30 | + |
| 31 | +{id="sim_sho" title="Simple harmonic oscillator" collapsed="true"} |
| 32 | +```Goal |
| 33 | +ip := 1.0 |
| 34 | +c := 0.2 |
| 35 | +mass := 0.5 |
| 36 | +csq := c * c |
| 37 | +
|
| 38 | +var massStr, cStr, msgStr string |
| 39 | +
|
| 40 | +## |
| 41 | +totalTime := 100 |
| 42 | +sp := zeros(totalTime) |
| 43 | +sv := zeros(totalTime) |
| 44 | +pE := zeros(totalTime) |
| 45 | +kE := zeros(totalTime) |
| 46 | +tE := zeros(totalTime) |
| 47 | +## |
| 48 | +
|
| 49 | +func valUpdate() { |
| 50 | + massStr = fmt.Sprintf("mass: %4.1f", mass) |
| 51 | + cStr = fmt.Sprintf("c: %4.1f", c) |
| 52 | + csq = c * c |
| 53 | + ## |
| 54 | + mf := array(mass) |
| 55 | + cf := array(csq) |
| 56 | + p := array(ip) |
| 57 | + pp := array(ip) |
| 58 | + pv := array(0.0) |
| 59 | + mv := array(0.0) |
| 60 | + v := array(0.0) |
| 61 | + pot := array(0.0) |
| 62 | + kin := array(0,0) |
| 63 | + ## |
| 64 | + for t := range 100 { |
| 65 | + ## |
| 66 | + pv = 1.0 * v |
| 67 | + pp = 1.0 * p |
| 68 | + v = pv - (cf * pp) / mf |
| 69 | + p = pp + v |
| 70 | + |
| 71 | + mv = 0.5 * (v + pv) // midway |
| 72 | + pot = 0.5 * pp * pp |
| 73 | + kin = (mv * mv * mf) / (2.0 * cf) |
| 74 | + |
| 75 | + sp[t] = p |
| 76 | + sv[t] = v |
| 77 | + pE[t] = pot |
| 78 | + kE[t] = kin |
| 79 | + tE[t] = pot + kin |
| 80 | + ## |
| 81 | + } |
| 82 | + msgStr = fmt.Sprintf("<b>Total E: %7.3g </b>", tE.Float(99)) |
| 83 | +} |
| 84 | +
|
| 85 | +valUpdate() |
| 86 | +
|
| 87 | +plotStyler := func(s *plot.Style) { |
| 88 | + s.Plot.XAxis.Label = "Time" |
| 89 | + s.Plot.XAxis.Range.SetMax(100).SetMin(0) |
| 90 | +} |
| 91 | +plot.SetStyler(sp, plotStyler) |
| 92 | +
|
| 93 | +fig1, pw := lab.NewPlotWidget(b) |
| 94 | +pl := plots.NewLine(fig1, sp) |
| 95 | +vl := plots.NewLine(fig1, sv) |
| 96 | +pEl := plots.NewLine(fig1, pE) |
| 97 | +kEl := plots.NewLine(fig1, kE) |
| 98 | +tEl := plots.NewLine(fig1, tE) |
| 99 | +fig1.Legend.Add("p", pl) |
| 100 | +fig1.Legend.Add("v", vl) |
| 101 | +fig1.Legend.Add("pE", pEl) |
| 102 | +fig1.Legend.Add("kE", kEl) |
| 103 | +fig1.Legend.Add("tE", tEl) |
| 104 | +
|
| 105 | +msgTx := core.NewText(b) |
| 106 | +msgTx.Styler(func(s *styles.Style) { |
| 107 | + s.Min.X.Ch(80) // clean rendering with variable width content |
| 108 | +}) |
| 109 | +core.Bind(&msgStr, msgTx) |
| 110 | +
|
| 111 | +func updt() { |
| 112 | + valUpdate() |
| 113 | + pl.SetData(sp) |
| 114 | + vl.SetData(sv) |
| 115 | + pEl.SetData(pE) |
| 116 | + kEl.SetData(kE) |
| 117 | + tEl.SetData(tE) |
| 118 | + msgTx.UpdateRender() |
| 119 | + pw.NeedsRender() |
| 120 | +} |
| 121 | +
|
| 122 | +func addSlider(label *string, val *float64, mnVal, mxVal float32) { |
| 123 | + tx := core.NewText(b) |
| 124 | + tx.Styler(func(s *styles.Style) { |
| 125 | + s.Min.X.Ch(40) // clean rendering with variable width content |
| 126 | + }) |
| 127 | + core.Bind(label, tx) |
| 128 | + sld := core.NewSlider(b).SetMin(mnVal).SetMax(mxVal).SetEnforceStep(true) |
| 129 | + if mxVal > 10 { |
| 130 | + sld.SetStep(10) |
| 131 | + } else { |
| 132 | + sld.SetStep(0.1) |
| 133 | + } |
| 134 | + sld.SendChangeOnInput() |
| 135 | + sld.OnChange(func(e events.Event) { |
| 136 | + updt() |
| 137 | + tx.UpdateRender() |
| 138 | + }) |
| 139 | + core.Bind(val, sld) |
| 140 | +} |
| 141 | +
|
| 142 | +addSlider(&massStr, &mass, 0.1, 1.0) |
| 143 | +addSlider(&cStr, &c, 0.1, 1.0) |
| 144 | +``` |
| 145 | + |
| 146 | +The equivalent of the wavelength for the SHO is the _period_, in time, for the cycle to repeat. |
| 147 | + |
0 commit comments