Ordinate 2D Marketplace Community Open the studio

Marketplace › From Ordinate 2D

Resonance curve of a driven oscillator

Script by Ordinate 2D ✓ · Oscillations and waves

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))

table forces from a script spring experiment