calculate_damped_oscillation
Compute position and velocity of a damped harmonic oscillator at a given time, and classify the damping regime as underdamped, critically damped, or overdamped.
Instructions
Calculate damped oscillation with friction/resistance.
Real oscillators lose energy over time due to damping (air resistance,
friction). Three regimes: underdamped, critically damped, overdamped.
Args:
mass: Mass in kg
spring_constant: k in N/m
damping_coefficient: b in kg/s (damping strength)
time: Time t in seconds
initial_position: Initial position in meters (default 1.0)
initial_velocity: Initial velocity in m/s (default 0.0)
Returns:
Dict containing:
- position: x(t) in meters
- velocity: v(t) in m/s
- damping_ratio: ζ (zeta) = b/(2√(mk))
- regime: "underdamped", "critically_damped", or "overdamped"
Damping regimes:
- ζ < 1: Underdamped (oscillates, gradually decays)
- ζ = 1: Critically damped (returns fastest without oscillating)
- ζ > 1: Overdamped (slow return, no oscillation)
Example - Car suspension:
result = await calculate_damped_oscillation(
mass=300, # kg (quarter car mass)
spring_constant=20000, # N/m
damping_coefficient=2000, # kg/s
time=1.0
)
# Should be slightly underdamped for comfortInput Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mass | Yes | ||
| spring_constant | Yes | ||
| damping_coefficient | Yes | ||
| time | Yes | ||
| initial_position | No | ||
| initial_velocity | No |
Implementation Reference
- Core implementation of the damped oscillation calculator. Takes a DampedOscillationRequest, computes position and velocity for three regimes (underdamped, critically_damped, overdamped) based on damping ratio ζ = b/(2√(mk)), and returns a DampedOscillationResponse.
def calculate_damped_oscillation(request: DampedOscillationRequest) -> DampedOscillationResponse: """Calculate damped oscillation with damping coefficient. Damping ratio: ζ = b / (2√(mk)) - ζ < 1: Underdamped (oscillates) - ζ = 1: Critically damped (returns to equilibrium fastest) - ζ > 1: Overdamped (slow return, no oscillation) Args: request: Damped oscillation request Returns: Position, velocity, damping ratio, and regime """ m = request.mass k = request.spring_constant b = request.damping_coefficient x0 = request.initial_position v0 = request.initial_velocity t = request.time omega0 = math.sqrt(k / m) # Natural frequency zeta = b / (2.0 * math.sqrt(m * k)) # Damping ratio # Determine regime if zeta < 1.0: regime: Literal["underdamped", "critically_damped", "overdamped"] = "underdamped" omega_d = omega0 * math.sqrt(1.0 - zeta * zeta) # Damped frequency exp_term = math.exp(-zeta * omega0 * t) x = exp_term * ( x0 * math.cos(omega_d * t) + ((v0 + zeta * omega0 * x0) / omega_d) * math.sin(omega_d * t) ) v = -exp_term * ( (zeta * omega0 * x0 + omega_d * (v0 + zeta * omega0 * x0) / omega_d) * math.cos(omega_d * t) - omega_d * x0 * math.sin(omega_d * t) ) elif abs(zeta - 1.0) < 1e-6: regime = "critically_damped" exp_term = math.exp(-omega0 * t) x = exp_term * (x0 + (v0 + omega0 * x0) * t) v = exp_term * (v0 - omega0 * (x0 + (v0 + omega0 * x0) * t) + (v0 + omega0 * x0)) else: # zeta > 1 regime = "overdamped" r1 = -omega0 * (zeta + math.sqrt(zeta * zeta - 1.0)) r2 = -omega0 * (zeta - math.sqrt(zeta * zeta - 1.0)) c1 = (v0 - r2 * x0) / (r1 - r2) c2 = x0 - c1 x = c1 * math.exp(r1 * t) + c2 * math.exp(r2 * t) v = c1 * r1 * math.exp(r1 * t) + c2 * r2 * math.exp(r2 * t) return DampedOscillationResponse(position=x, velocity=v, damping_ratio=zeta, regime=regime) - Pydantic model DampedOscillationRequest: mass, spring_constant, damping_coefficient, initial_position, initial_velocity, time.
class DampedOscillationRequest(BaseModel): """Request for damped oscillation calculation.""" mass: float = Field(..., description="Mass in kg", gt=0.0) spring_constant: float = Field(..., description="Spring constant k in N/m", gt=0.0) damping_coefficient: float = Field(..., description="Damping coefficient b in kg/s", ge=0.0) initial_position: float = Field(default=1.0, description="Initial position in meters") initial_velocity: float = Field(default=0.0, description="Initial velocity in m/s") time: float = Field(..., description="Time t in seconds", ge=0.0) - Pydantic model DampedOscillationResponse: position, velocity, damping_ratio, regime (underdamped/critically_damped/overdamped).
class DampedOscillationResponse(BaseModel): """Response for damped oscillation calculation.""" position: float = Field(..., description="Position x(t) in meters") velocity: float = Field(..., description="Velocity v(t) in m/s") damping_ratio: float = Field(..., description="Damping ratio ζ (zeta)") regime: Literal["underdamped", "critically_damped", "overdamped"] = Field( ..., description="Damping regime" ) - MCP tool wrapper for calculate_damped_oscillation. Decorated with @tool, accepts individual float arguments, constructs a DampedOscillationRequest, calls the core function, and returns the response dict.
@tool # type: ignore[arg-type] async def calculate_damped_oscillation( mass: float, spring_constant: float, damping_coefficient: float, time: float, initial_position: float = 1.0, initial_velocity: float = 0.0, ) -> dict: """Calculate damped oscillation with friction/resistance. Real oscillators lose energy over time due to damping (air resistance, friction). Three regimes: underdamped, critically damped, overdamped. Args: mass: Mass in kg spring_constant: k in N/m damping_coefficient: b in kg/s (damping strength) time: Time t in seconds initial_position: Initial position in meters (default 1.0) initial_velocity: Initial velocity in m/s (default 0.0) Returns: Dict containing: - position: x(t) in meters - velocity: v(t) in m/s - damping_ratio: ζ (zeta) = b/(2√(mk)) - regime: "underdamped", "critically_damped", or "overdamped" Damping regimes: - ζ < 1: Underdamped (oscillates, gradually decays) - ζ = 1: Critically damped (returns fastest without oscillating) - ζ > 1: Overdamped (slow return, no oscillation) Example - Car suspension: result = await calculate_damped_oscillation( mass=300, # kg (quarter car mass) spring_constant=20000, # N/m damping_coefficient=2000, # kg/s time=1.0 ) # Should be slightly underdamped for comfort """ from ..oscillations import DampedOscillationRequest, calculate_damped_oscillation as calc_damped request = DampedOscillationRequest( mass=mass, spring_constant=spring_constant, damping_coefficient=damping_coefficient, initial_position=initial_position, initial_velocity=initial_velocity, time=time, ) response = calc_damped(request) return response.model_dump() - src/chuk_mcp_physics/tools/oscillations.py:142-142 (registration)Registration of the damped oscillation tool via the @tool decorator (from chuk_mcp_server).
@tool # type: ignore[arg-type]