Pages

Thursday, June 27, 2024

Hysteresis in a simple V-shaped spring-mass system Simulation by Clause and GPT4o

 

Spring-Mass_Hysteresis_Simulation/
source code Spring-Mass_Hysteresis_Simulation.zip

Exploring Hysteresis with a V-Shaped Spring-Mass System Simulation

Understanding complex physical phenomena can be made easier and more engaging through interactive simulations. Today, we delve into the hysteresis effect using a V-shaped spring-mass system simulation, inspired by the work of Christopher Ong. This simulation allows you to visualize how hysteresis occurs in such a system, illustrating the energy loss typically observed due to this phenomenon.

What is Hysteresis?

Hysteresis is a phenomenon where the state of a system depends not only on its current conditions but also on its history. In other words, the path of deformation and recovery of the system differs, leading to energy dissipation, usually in the form of heat. This is commonly seen in magnetic materials, elastic hysteresis in rubbers, and mechanical systems like the one we are exploring here.

The Simulation

This simulation models a V-shaped spring-mass system, where the mass is connected to two springs anchored at fixed points. By adjusting various parameters, you can see how the system behaves under different conditions and observe the hysteresis effect in action.

Features of the Simulation

  1. External Force Adjustment: Apply an upward force to the mass to see how it affects the system.
  2. Spring Natural Length: Change the natural length of the springs to see how the system's equilibrium changes.
  3. Mass: Adjust the mass of the object to observe how inertia influences the system's behavior.
  4. Damping Factor: Modify the damping factor to see how energy dissipation affects the system.
  5. Gravity: Change the gravity to simulate different gravitational environments.

How to Use the Simulation

  • Play/Pause: Start or pause the simulation.
  • Step: Advance the simulation step by step to observe gradual changes.
  • Reset: Reset all parameters to their default values.

The controls are intuitive and allow for a hands-on approach to learning about hysteresis.

Description of the Simulation

This simulation demonstrates the hysteresis effect in a V-shaped spring-mass system based on the work of Christopher Ong. For more details, you can refer to the original paper.

Hysteresis occurs when the path of deformation and recovery of the spring-mass system differ, leading to energy loss typically as heat. The simulation models the forces acting on the mass, including spring forces, damping, external force, and gravity.

Created by weelookang@gmail.com using Claude (initial code) and GPT-4 (finishing the code).

Visual Representation

Code Implementation

Here's a snippet of the code that powers the simulation. Feel free to explore and modify it to suit your learning needs.

html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Spring-Mass Hysteresis Simulation</title> <style> /* Styling for the body, container, and canvas */ body { font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; height: 100vh; margin: 0; background-color: #f0f0f0; } .container { background-color: rgb(110, 100, 100); padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); width: 100%; box-sizing: border-box; position: relative; } canvas { border: 1px solid #ddd; width: 100%; height: 60vh; } .controls { display: flex; align-items: center; flex-wrap: wrap; justify-content: center; margin-bottom: 10px; } .controls h1 { margin: 0; margin-right: 20px; font-size: 1.5em; color: white; flex: 1 100%; text-align: center; } button { margin-right: 5px; margin-top: 5px; display: inline-block; } .slider-container { margin-bottom: 10px; flex: 1 100%; text-align: center; } .slider-container label { display: inline-block; width: 150px; } .slider-container input { width: 50%; } .value-display { display: inline-block; width: 50px; text-align: right; } #info { position: relative; text-align: center; color: white; margin-bottom: 10px; } #footer { margin-top: 10px; color: rgb(110, 100, 100); text-align: center; } #description { color: rgb(110, 100, 100); text-align: center; margin-top: 10px; margin-bottom: 10px; } @media (max-width: 768px) { .slider-container label { width: auto; display: block; margin-bottom: 5px; } .slider-container input { width: 100%; } .controls { flex-direction: column; } } </style> </head> <body> <div class="container"> <!-- Control buttons for play/pause, step, and reset --> <div class="controls"> <h1>Spring-Mass Hysteresis Simulation</h1> <div> <button id="playPauseBtn">Play</button> <button id="stepBtn">Step</button> <button id="resetBtn">Reset</button> </div> </div> <!-- Slider for adjusting external force --> <div class="slider-container"> <label for="forceSlider">External Force (Upward):</label> <input type="range" id="forceSlider" min="-40" max="40" step="1" value="0"> <span>Force: <span id="forceValue" class="value-display">0</span></span> </div> <!-- Slider for adjusting spring natural length --> <div class="slider-container"> <label for="lengthSlider">Spring Natural Length:</label> <input type="range" id="lengthSlider" min="50" max="150" step="1" value="100"> <span>Length: <span id="lengthValue" class="value-display">100</span></span> </div> <!-- Additional sliders --> <div class="slider-container"> <label for="massSlider">Mass:</label> <input type="range" id="massSlider" min="0.5" max="5" step="0.1" value="1"> <span>Mass: <span id="massValue" class="value-display">1</span></span> </div> <div class="slider-container"> <label for="dampingSlider">Damping Factor:</label> <input type="range" id="dampingSlider" min="0" max="1" step="0.01" value="0.1"> <span>Damping: <span id="dampingValue" class="value-display">0.1</span></span> </div> <div class="slider-container"> <label for="gravitySlider">Gravity:</label> <input type="range" id="gravitySlider" min="-9.81" max="9.81" step="0.1" value="-9.81"> <span>Gravity: <span id="gravityValue" class="value-display">-9.81</span></span> </div> <!-- Canvas for drawing the simulation --> <canvas id="simCanvas"></canvas> <!-- Info section to display time and mass position --> <div id="info">Time: 0.00s | Mass Position: (0.00, 0.00)</div> </div> <!-- Description of the simulation --> <div id="description"> <p>This simulation demonstrates the hysteresis effect in a V-shaped spring-mass system based on the work of Christopher Ong. For more details, you can refer to the <a href="https://pubs.aip.org/aapt/ajp/article-abstract/89/7/663/1056905/Hysteresis-in-a-simple-V-shaped-spring-mass-system?redirectedFrom=fulltext" target="_blank">original paper</a>.</p> <p>Hysteresis occurs when the path of deformation and recovery of the spring-mass system differ, leading to energy loss typically as heat.</p> <p>The simulation models the forces acting on the mass, including spring forces, damping, external force, and gravity.</p> </div> <!-- Footer for credits --> <div id="footer"> Created by weelookang@gmail.com using Claude (initial code) and GPT-4 (finishing the code) </div> <!-- Google Analytics and Ads scripts --> <script async="true" src="https://www.googletagmanager.com/gtag/js?id=G-S9EWRY1CPJ"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-S9EWRY1CPJ'); </script> <script data-ad-client="ca-pub-0121577198857509" async="true" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script> // Get references to HTML elements const canvas = document.getElementById('simCanvas'); const ctx = canvas.getContext('2d'); const playPauseBtn = document.getElementById('playPauseBtn'); const stepBtn = document.getElementById('stepBtn'); const resetBtn = document.getElementById('resetBtn'); const forceSlider = document.getElementById('forceSlider'); const forceValue = document.getElementById('forceValue'); const lengthSlider = document.getElementById('lengthSlider'); const lengthValue = document.getElementById('lengthValue'); const massSlider = document.getElementById('massSlider'); const massValue = document.getElementById('massValue'); const dampingSlider = document.getElementById('dampingSlider'); const dampingValue = document.getElementById('dampingValue'); const gravitySlider = document.getElementById('gravitySlider'); const gravityValue = document.getElementById('gravityValue'); const info = document.getElementById('info'); let isPlaying = false; // Variable to track if the simulation is playing let externalForce = 0; // External force acting on the mass let massPosition = { x: 0, y: 0 }; // Position of the mass let massVelocity = { x: 0, y: 0 }; // Velocity of the mass let time = 0; // Simulation time // Constants for the spring and mass system const k = 0.5; // Spring constant let m = 1; // Mass let L0 = 100; // Natural length of springs let dampingFactor = 0.1; // Damping factor for the system let gravity = -9.81; // Gravitational acceleration const dt = 0.1; // Time step for the simulation // Function to resize canvas dimensions function resizeCanvas() { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; drawSystem(); } // Function to draw an arrow on the canvas function drawArrow(fromx, fromy, tox, toy, color) { const headlen = 10; // Length of arrowhead in pixels const dx = tox - fromx; // Change in x const dy = toy - fromy; // Change in y const angle = Math.atan2(dy, dx); // Angle of the arrow ctx.strokeStyle = color; // Set arrow color ctx.beginPath(); ctx.moveTo(fromx, fromy); ctx.lineTo(tox, toy); ctx.lineTo(tox - headlen * Math.cos(angle - Math.PI / 6), toy - headlen * Math.sin(angle - Math.PI / 6)); ctx.moveTo(tox, toy); ctx.lineTo(tox - headlen * Math.cos(angle + Math.PI / 6), toy - headlen * Math.sin(angle + Math.PI / 6)); ctx.stroke(); } // Function to draw a spring between two points function drawSpring(x1, y1, x2, y2, naturalLength, segments = 20) { const dx = x2 - x1; // Change in x const dy = y2 - y1; // Change in y const length = Math.sqrt(dx * dx + dy * dy); // Length of the spring const angle = Math.atan2(dy, dx); // Angle of the spring ctx.save(); // Save the current context state ctx.translate(x1, y1); // Translate the context to the starting point of the spring ctx.rotate(angle); // Rotate the context to align with the spring const segmentLength = length / segments; // Length of each segment const amplitude = segmentLength / 2; // Amplitude of the zigzag ctx.beginPath(); ctx.moveTo(0, 0); for (let i = 1; i <= segments; i++) { const x = i * segmentLength; const y = (i % 2 === 0 ? 1 : -1) * amplitude; ctx.lineTo(x, y); } // Set the color based on spring length if (length < naturalLength) { ctx.strokeStyle = 'orange'; // Compression } else { ctx.strokeStyle = 'yellow'; // Extension } ctx.stroke(); ctx.restore(); // Restore the previous context state } // Function to draw the entire system function drawSystem() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas const centerX = canvas.width / 2; // Center x-coordinate const centerY = canvas.height / 2; // Center y-coordinate // Draw left spring drawSpring(centerX - 100, centerY - 100, centerX + massPosition.x, centerY + massPosition.y, L0); // Draw right spring drawSpring(centerX + 100, centerY - 100, centerX + massPosition.x, centerY + massPosition.y, L0); // Draw the mass ctx.beginPath(); ctx.arc(centerX + massPosition.x, centerY + massPosition.y, 10, 0, 2 * Math.PI); ctx.fillStyle = '#f00'; ctx.fill(); // Draw anchor points ctx.beginPath(); ctx.arc(centerX - 100, centerY - 100, 5, 0, 2 * Math.PI); ctx.arc(centerX + 100, centerY - 100, 5, 0, 2 * Math.PI); ctx.fillStyle = '#00f'; ctx.fill(); // Draw the external force vector if any if (externalForce !== 0) { const forceScale = 5; // Scale factor for force visualization drawArrow( centerX + massPosition.x, centerY + massPosition.y, centerX + massPosition.x, centerY + massPosition.y - externalForce * forceScale, 'purple' ); } } // Function to update the position of the mass function updatePosition() { const dx1 = massPosition.x + 100; // Distance from left spring anchor const dy1 = massPosition.y + 100; // Distance from left spring anchor const dx2 = massPosition.x - 100; // Distance from right spring anchor const dy2 = massPosition.y + 100; // Distance from right spring anchor const L1 = Math.sqrt(dx1 * dx1 + dy1 * dy1); // Length of left spring const L2 = Math.sqrt(dx2 * dx2 + dy2 * dy2); // Length of right spring const Fx1 = -k * (L1 - L0) * dx1 / L1; // Force by left spring in x const Fy1 = -k * (L1 - L0) * dy1 / L1; // Force by left spring in y const Fx2 = -k * (L2 - L0) * dx2 / L2; // Force by right spring in x const Fy2 = -k * (L2 - L0) * dy2 / L2; // Force by right spring in y const Fx = Fx1 + Fx2; // Total force in x const Fy = Fy1 + Fy2 - externalForce - m * gravity; // Total force in y, include external force and gravity const ax = Fx / m - dampingFactor * massVelocity.x; // Acceleration in x const ay = Fy / m - dampingFactor * massVelocity.y; // Acceleration in y massVelocity.x += ax * dt; // Update velocity in x massVelocity.y += ay * dt; // Update velocity in y massPosition.x += massVelocity.x * dt; // Update position in x massPosition.y += massVelocity.y * dt; // Update position in y time += dt; // Increment time drawSystem(); // Redraw the system updateInfo(); // Update the info display } // Function to update the information display function updateInfo() { info.textContent = `Time: ${time.toFixed(2)}s | Mass Position: (${massPosition.x.toFixed(2)}, ${massPosition.y.toFixed(2)})`; } // Function to toggle the simulation play/pause state function toggleSimulation() { isPlaying = !isPlaying; playPauseBtn.textContent = isPlaying ? 'Pause' : 'Play'; if (isPlaying) { simulationLoop(); } } // Simulation loop to update the position continuously function simulationLoop() { if (isPlaying) { updatePosition(); requestAnimationFrame(simulationLoop); } } // Function to perform a single step of the simulation function step() { isPlaying = false; playPauseBtn.textContent = 'Play'; updatePosition(); } // Function to reset the simulation to its initial state function reset() { isPlaying = false; playPauseBtn.textContent = 'Play'; massPosition = { x: 0, y: 0 }; massVelocity = { x: 0, y: 0 }; time = 0; externalForce = 0; forceSlider.value = 0; forceValue.textContent = '0'; L0 = 100; lengthSlider.value = 100; lengthValue.textContent = '100'; m = 1; massSlider.value = 1; massValue.textContent = '1'; dampingFactor = 0.1; dampingSlider.value = 0.1; dampingValue.textContent = '0.1'; gravity = -9.81; gravitySlider.value = -9.81; gravityValue.textContent = '-9.81'; drawSystem(); updateInfo(); } // Event listeners for the buttons and sliders playPauseBtn.addEventListener('click', toggleSimulation); stepBtn.addEventListener('click', step); resetBtn.addEventListener('click', reset); forceSlider.addEventListener('input', () => { externalForce = parseFloat(forceSlider.value); forceValue.textContent = externalForce.toFixed(1); drawSystem(); }); lengthSlider.addEventListener('input', () => { L0 = parseFloat(lengthSlider.value); lengthValue.textContent = L0.toFixed(0); drawSystem(); }); massSlider.addEventListener('input', () => { m = parseFloat(massSlider.value); massValue.textContent = m.toFixed(1); drawSystem(); }); dampingSlider.addEventListener('input', () => { dampingFactor = parseFloat(dampingSlider.value); dampingValue.textContent = dampingFactor.toFixed(2); drawSystem(); }); gravitySlider.addEventListener('input', () => { gravity = parseFloat(gravitySlider.value); gravityValue.textContent = gravity.toFixed(2); drawSystem(); }); // Initial draw and info update drawSystem(); updateInfo(); // Resize canvas when window is resized window.addEventListener('resize', resizeCanvas); resizeCanvas(); // Initial resize to set canvas dimensions </script> </body> </html>

Activities to Try

  1. Observe Hysteresis: Apply an external force and vary it to see how the system’s path differs during loading and unloading.
  2. Damping Effects: Adjust the damping factor and observe how quickly the system returns to equilibrium. Note how energy dissipation changes with different damping values.
  3. Mass Variation: Change the mass and see how inertia affects the system’s response to external forces and damping.
  4. Gravity Simulation: Experiment with different gravity values to simulate the system on different planets or in a microgravity environment.

Conclusion

Interactive simulations like this provide a powerful tool for visualizing and understanding complex physical phenomena. By adjusting parameters and observing outcomes, you gain a deeper insight into concepts like hysteresis and the dynamics of spring-mass systems. Explore the simulation, modify the code, and share your findings!

Feel free to reach out with any questions or feedback on the simulation. Happy learning!


No comments:

Post a Comment