Marketplace › From Ordinate 2D
Resonance curve of a driven oscillator
Step the driving frequency up and measure the amplitude: the resonance curve against theory.
Use in Ordinate 2DOpens in the Script tab: it runs when you press Run. Free, no account needed.
"""Resonance: drive a mass on a spring at one frequency after another and measure how far it swings.
A force F₀ sin 2πft pushes a 1 kg mass on a k = 36 N/m spring with a little damping. Every 10 s the driving frequency steps up;
the amplitude is read over the last 2 s of each step (when the start-up has died away) and written to the table next to
the theory A = F₀ / √((k − mω²)² + (cω)²). Chart amplitude against f for the resonance curve, peaking near f₀ = 0.95 Hz.
Runs in the studio (Script tab → Run) and locally: python3 resonance_sweep.py
"""
import math
import studio as s
K, M, C, F0 = 36.0, 1.0, 0.8, 2.0
FREQS = [0.4, 0.6, 0.8, 0.9, 1.0, 1.1, 1.3, 1.6] # Hz
STEP_TIME, MEASURE = 10.0, 2.0
s.clear()
s.gravity = (0, -9.81)
floor = s.ground(0, width=14, friction=0)
wall = s.box(-4.4, 0.75, 0.2, 1.5, static=True, name="Wall", color="#8b939b")
mass = s.box(-1.8, 0.21, 0.6, 0.42, mass=M, friction=0, restitution=0, name="Mass", color="#4f8ff7")
s.spring(wall, mass, K, C, rest=2.5, at_a=(-4.3, 0.21), at_b=(-2.1, 0.21), name="Spring")
index, lo, hi = 0, 1e9, -1e9
@s.on_step
def drive(t, dt):
global index, lo, hi
k = int(t // STEP_TIME)
if k >= len(FREQS):
s.stop()
return
f = FREQS[k]
mass.force = (F0 * math.sin(2 * math.pi * f * t), 0)
if t - k * STEP_TIME >= STEP_TIME - MEASURE:
lo, hi = min(lo, mass.x), max(hi, mass.x)
if t - k * STEP_TIME >= STEP_TIME - dt and hi > lo:
w = 2 * math.pi * f
theory = F0 / math.hypot(K - M * w * w, C * w)
s.record(f=f, amplitude=(hi - lo) / 2, theory=theory)
print(f"f = {f:.2f} Hz: amplitude {(hi - lo) / 2:.3f} m (theory {theory:.3f} m)")
lo, hi = 1e9, -1e9
s.run(STEP_TIME * len(FREQS))