physics-simulations

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

commit d712e0cd68c330e2cba2e672fb8eb1fc9997ed51
parent 9879bf0f9746feaed7498528b206bdb6a36ea947
Author: AsherMorgan <59518073+AsherMorgan@users.noreply.github.com>
Date:   Sun, 28 Mar 2021 17:44:05 -0700

Add spring-mass system simulation

Diffstat:
Mindex.html | 1+
Asimulations/spring-mass-system.html | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asimulations/spring-mass-system.js | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 166 insertions(+), 0 deletions(-)

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="Spring-Mass System" href="simulations/spring-mass-system.html">Spring-Mass System</a></li> </ul> </body> </html> diff --git a/simulations/spring-mass-system.html b/simulations/spring-mass-system.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <title>Spring-Mass System Simulation</title> + <meta name="Description" content="Spring-Mass system 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="spring-mass-system.js"></script> + </head> + <body onload="createApp()"> + <div id="app"> + <header> + <a title="Home" href="../" class="icon"><img alt="" src="../images/home.svg"></a> + <h1>Spring-Mass System</h1> + </header> + + <noscript> + <p>This simulation requires JavaScript</p> + </noscript> + + <div id="input" hidden> + <section> + <label for="massInput"><b>Mass:</b> {{ mass.toFixed(1) }} Kg</label> + <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> + <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> + <label for="stiffnessInput"><b>Stiffness (k):</b> {{ stiffness.toFixed(0) }} N/m</label> + <input type="range" min="1" max="100" step="1" v-model.number="stiffness" @input="reset" @dblclick="stiffness=5" :disabled="active" id="stiffnessInput"> + </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="800px" viewBox="-11 0 22 4"> + <!-- Point of equilibrium --> + <line x1="0" y1="0" :x2="0" y2="4" stroke="#808080" stroke-width="0.05" stroke-dasharray="0.1,0.1"></line> + + <!-- Spring --> + <line x1="-11" y1="2" :x2="position" y2="2" stroke="#404040" stroke-width="0.1"></line> + <rect x="-11" y="1" width="0.25" height="2" fill="#000000"></rect> + + <!-- Mass --> + <circle :cx="position" cy="2" :r="0.05*mass+0.1" 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>Amplitude:</b> {{ Math.abs(initialPosition) }} m</label> + <label><b>Position:</b> {{ position.toFixed(2) }} m</label> + <label><b>Velocity:</b> {{ velocity.toFixed(2) }} m/s</label> + <label><b>Force:</b> {{ force.toFixed(2) }} N</label> + <label><b>Acceleration:</b> {{ acceleration.toFixed(2) }} m/s<sup>2</sup></label> + </div> + </div> + </body> +</html> diff --git a/simulations/spring-mass-system.js b/simulations/spring-mass-system.js @@ -0,0 +1,89 @@ +const App = { + data: function() { + return { + mass: 5, // The mass of the object (Kg) + initialPosition: 5, // The object's initial position (m) + stiffness: 5, // The spring stiffness (N/m) + 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 object + */ + period: function() { + if (this.initialPosition === 0) return 0; + else return 2 * Math.PI * Math.sqrt(this.mass / this.stiffness); + }, + + /** + * The position of the object + */ + position: function() { + if (this.initialPosition === 0) return 0; + else return this.initialPosition * Math.cos(this.time * 2 * Math.PI / this.period); + }, + + /** + * The velocity of the object + */ + velocity: function() { + if (this.initialPosition === 0) return 0; + else return -1 * this.initialPosition * Math.sin(this.time * 2 * Math.PI / this.period) * 2 * Math.PI / this.period; + }, + + /** + * The spring force + */ + force: function() { + return -1 * this.stiffness * this.position; + }, + + /** + * The acceleration of the object + */ + acceleration: function() { + return this.force / this.mass; + }, + }, + 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; +}