physics-simulations

A collection of physics simulations
git clone https://git.ashermorgan.net/physics-simulations/
Log | Files | Refs | README

commit c67aafe3de02f141cdf453095bac2c9b67015112
parent d712e0cd68c330e2cba2e672fb8eb1fc9997ed51
Author: AsherMorgan <59518073+AsherMorgan@users.noreply.github.com>
Date:   Sun, 28 Mar 2021 19:15:25 -0700

Add simple pendulum simulation

Diffstat:
Mindex.html | 1+
Asimulations/simple-pendulum.html | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asimulations/simple-pendulum.js | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msimulations/spring-mass-system.html | 2+-
4 files changed, 159 insertions(+), 1 deletion(-)

diff --git a/index.html b/index.html @@ -23,6 +23,7 @@ <li><a title="Circular Motion" href="simulations/circular-motion.html">Circular Motion</a></li> <li><a title="Horizontal Motion" href="simulations/horizontal-motion.html">Horizontal Motion</a></li> <li><a title="Projectile Motion" href="simulations/projectile-motion.html">Projectile Motion</a></li> + <li><a title="Simple Pendulum" href="simulations/simple-pendulum.html">Simple Pendulum</a></li> <li><a title="Spring-Mass System" href="simulations/spring-mass-system.html">Spring-Mass System</a></li> </ul> </body> diff --git a/simulations/simple-pendulum.html b/simulations/simple-pendulum.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <title>Simple Pendulum Simulation</title> + <meta name="Description" content="Simple pendulum physics simulation and calculator"> + <meta name="viewport" content="width=device-width"> + <link rel="icon" type="image/png" href="../images/favicon-32.png"> + <link rel="apple-touch-icon" href="../images/favicon-180.png"> + <script src="https://cdn.jsdelivr.net/npm/vue@3.0.6"></script> + <link rel="stylesheet" href="styles.css"> + <script src="simple-pendulum.js"></script> + </head> + <body onload="createApp()"> + <div id="app"> + <header> + <a title="Home" href="../" class="icon"><img alt="" src="../images/home.svg"></a> + <h1>Simple Pendulum</h1> + </header> + + <noscript> + <p>This simulation requires JavaScript</p> + </noscript> + + <div id="input" hidden> + <section> + <label for="radiusInput"><b>Radius:</b> {{ radius.toFixed(1) }} m</label> + <input type="range" min="1" max="10" step="0.1" v-model.number="radius" @input="reset" @dblclick="radius=5" :disabled="active" id="radiusInput"> + </section> + <section> + <label for="angleInput"><b>Initial Angle:</b> {{ initialAngle.toFixed(0) }}<sup>o</sup></label> + <input type="range" min="-45" max="45" step="1" v-model.number="initialAngle" @input="reset" @dblclick="initialAngle=0" :disabled="active" id="angleInput"> + </section> + <section> + <label for="gravityInput"><b>Gravity:</b> {{ gravity.toFixed(1) }} m/s<sup>2</sup></label> + <input type="range" min="0.1" max="10" step="0.1" v-model.number="gravity" @input="reset" @dblclick="gravity=9.8" :disabled="active" id="gravityInput"> + </section> + </div> + + <div id="output" hidden> + <div id="simControls"> + <button @click="toggle" class="icon" :title="active ? 'Pause' : (time === 0 ? 'Start' : 'Resume')"> + <img alt="" :src="active ? '../images/pause.svg' : '../images/play.svg'"> + </button> + <button @click="update" class="icon" title="Step Forward" :disabled="active"> + <img alt="" src="../images/step-forward.svg"> + </button> + <button @click="reset" class="icon" title="Reset" :disabled="time === 0"> + <img alt="" src="../images/reset.svg"> + </button> + </div> + <svg width="400px" viewBox="-8 -3 16 16"> + <!-- String --> + <circle cx="0" c1="0" r="0.1" fill="#808080"></circle> + <line x1="0" y1="0" :x2="position.x" :y2="-position.y" stroke="#808080" stroke-width="0.2"></line> + + <!-- Box --> + <rect x="-2" y="-0.5" width="4" height="0.5" fill="#000000"></rect> + + <!-- Mass --> + <circle :cx="position.x" :cy="-position.y" r="0.5" fill="#ff0000"></circle> + </svg> + </div> + + <div id="data" hidden> + <label><b>Time:</b> {{ time.toFixed(2) }} s</label> + <label><b>Period:</b> {{ period.toFixed(2) }} s</label> + <label><b>Angle:</b> {{ angle.toFixed(0) }}<sup>o</sup></label> + <label><b>Acceleration:</b> {{ acceleration.toFixed(2) }} m/s<sup>2</sup></label> + </div> + </div> + </body> +</html> diff --git a/simulations/simple-pendulum.js b/simulations/simple-pendulum.js @@ -0,0 +1,84 @@ +const App = { + data: function() { + return { + radius: 5, // The radius of the pendulum (m) + initialAngle: 5, // The initial angle of the pendulum (degrees) + gravity: 9.8, // The acceleration due to gravity (m/s/s) + time: 0, // The time (s) + active: false, // Whether the simulation is active + refreshRate: 0.01, // The simulation refresh rate (s) + intervalId: null, // The value returned by setInterval + } + }, + computed: { + /** + * The period of the pendulum + */ + period: function() { + if (this.initialAngle === 0) return 0; + else return 2 * Math.PI * Math.sqrt(this.radius / this.gravity); + }, + + /** + * The angle of the pendulum + */ + angle: function() { + if (this.initialAngle === 0) return 0; + else return this.initialAngle * Math.cos(this.time * 2 * Math.PI / this.period); + }, + + /** + * The position of the pendulum mass + */ + position: function() { + return { + x: Math.sin(this.angle * 2 * Math.PI / 360) * this.radius, + y: -Math.cos(this.angle * 2 * Math.PI / 360) * this.radius, + }; + }, + + /** + * The acceleration of the pendulum mass + */ + acceleration: function() { + return -Math.sin(this.angle * 2 * Math.PI / 360) * this.gravity; + }, + }, + methods: { + /** + * Toggle whether the simulation is active + */ + toggle: function() { + this.active = !this.active; + if (this.active) this.intervalID = setInterval(this.update, this.refreshRate * 1000); + else clearInterval(this.intervalID); + }, + + /** + * Reset the simulation + */ + reset: function() { + this.time = 0; + }, + + /** + * Update the simulation output + */ + update: function() { + this.time += this.refreshRate; + }, + }, +} + + + +// Create Vue app +function createApp() { + // Create app + Vue.createApp(App).mount("#app"); + + // Unhide app divs + document.getElementById("input").hidden = false; + document.getElementById("output").hidden = false; + document.getElementById("data").hidden = false; +} diff --git a/simulations/spring-mass-system.html b/simulations/spring-mass-system.html @@ -28,7 +28,7 @@ <input type="range" min="0.1" max="10" step="0.1" v-model.number="mass" @input="reset" @dblclick="mass=5" :disabled="active" id="massInput"> </section> <section> - <label for="initialPositionInput"><b>Position:</b> {{ initialPosition.toFixed(1) }} m</label> + <label for="initialPositionInput"><b>Initial Position:</b> {{ initialPosition.toFixed(1) }} m</label> <input type="range" min="-10" max="10" step="0.1" v-model.number="initialPosition" @input="reset" @dblclick="initialPosition=0" :disabled="active" id="initialPositionInput"> </section> <section>