Mechanics
Classical mechanics โ kinematics, dynamics, and oscillations in one unified module. Covers motion analysis, forces, energy, collisions, rigid bodies, and oscillator models.
Namespace: CSharpNumerics.Physics.Mechanics
Oscillations Namespace: CSharpNumerics.Physics.Mechanics.Oscillations
โฌ๏ธ Free Fallโ
Compute the velocity or time of a freely falling object:
double v = 10.0.FreeFallVelocity(); // scalar: v = sqrt(2*g*h)
double t = 10.0.FreeFallTime(); // scalar: t = sqrt(2*h/g)
// Vector version with optional direction (default downward)
Vector dir = new Vector(0,0,-1);
Vector vVec = 10.0.FreeFallVelocity(dir);
โก๏ธ Constant Velocityโ
Compute position given constant velocity:
double s = 3.0.PositionFromConstantVelocity(time: 5, initialPosition: 2);
Vector velocity = new Vector(2, 0, 0);
Vector initialPosition = new Vector(1, 0, 0);
Vector position = velocity.PositionFromConstantVelocity(4, initialPosition);
๐ Constant Accelerationโ
Compute velocity or position under constant acceleration:
// Scalar
double v = 2.0.VelocityFromConstantAcceleration(time: 4, initialVelocity: 1);
double s = 2.0.PositionFromConstantAcceleration(time: 3, initialVelocity: 1, initialPosition: 0);
// Vector
Vector a = new Vector(1, 0, 0);
Vector v0 = new Vector(0, 0, 0);
Vector s0 = new Vector(0, 0, 0);
Vector vVec = a.VelocityFromConstantAcceleration(3, v0);
Vector sVec = a.PositionFromConstantAcceleration(2, v0, s0);
โฑ๏ธ Time-Independent (SUVAT) Equationsโ
Compute kinematics without explicit time:
double finalV = 2.0.VelocityFromDisplacement(5, initialVelocity: 1);
double displacement = 2.0.DisplacementFromVelocities(finalVelocity: 5, initialVelocity: 1);
double t = 2.0.TimeToReachVelocity(finalVelocity: 5, initialVelocity: 1);
double sAvg = 3.0.DisplacementFromAverageVelocity(initialVelocity: 2, finalVelocity: 4);
// Vector versions are also supported
Vector a = new Vector(2, 0, 0);
Vector s = new Vector(3, 0, 0);
Vector v0 = new Vector(1, 0, 0);
Vector finalVVec = a.VelocityFromDisplacement(s, v0);
Vector displacementVec = a.DisplacementFromVelocities(finalVVec, v0);
๐ Circular Motionโ
Compute centripetal acceleration:
double a = 3.0.CentripetalAcceleration(radius: 2); // scalar
Vector velocity = new Vector(2, 0, 0);
Vector radius = new Vector(0, 3, 0);
Vector ac = velocity.CentripetalAcceleration(radius); // vector, towards center
Angular speed, period, and frequency:
double omega = 10.0.AngularSpeed(radius: 5); // ฯ = v/r = 2 rad/s
double T = 10.0.Period(radius: 5); // T = 2ฯr/v
double f = 10.0.Frequency(radius: 5); // f = v/(2ฯr) = 1/T
Angular velocity vector and tangential velocity:
// Object at (5,0,0) moving at (0,10,0) โ angular velocity along +Z
Vector omega = vel.AngularVelocity(radius); // ฯ = (r ร v) / |r|ยฒ
// Reverse: angular velocity โ tangential velocity
Vector v = omega.TangentialVelocity(radius); // v = ฯ ร r
๐ฏ Projectile Motionโ
Compute projectile trajectory, time of flight, maximum height, and range:
Create an initial velocity vector from speed and launch angle:
// 20 m/s at 45ยฐ โ vโ = (vยทcos(ฮธ), 0, vยทsin(ฮธ))
Vector v0 = 20.0.ProjectileVelocityFromAngle(Math.PI / 4);
Position and velocity at any time:
Vector pos = v0.ProjectilePosition(time: 1.5);
Vector vel = v0.ProjectileVelocity(time: 1.5);
// With initial height (e.g. launched from a 10m cliff)
Vector pos2 = v0.ProjectilePosition(time: 1.5, initialHeight: 10);
Time of flight, maximum height, and range:
// Vector versions (support initial height)
double T = v0.ProjectileTimeOfFlight();
double H = v0.ProjectileMaxHeight();
double R = v0.ProjectileRange();
// With elevated launch
double T2 = v0.ProjectileTimeOfFlight(initialHeight: 10);
double R2 = v0.ProjectileRange(initialHeight: 10);
// Scalar versions (speed + angle, same-height launch)
double T3 = 20.0.ProjectileTimeOfFlight(Math.PI / 4); // T = 2vโsin(ฮธ)/g
double H3 = 20.0.ProjectileMaxHeight(Math.PI / 4); // H = vโยฒsinยฒ(ฮธ)/(2g)
double R3 = 20.0.ProjectileRange(Math.PI / 4); // R = vโยฒsin(2ฮธ)/g
๐ Orbital Mechanicsโ
Gravitational and circular-orbit calculations:
Gravitational helpers:
// Gravitational field strength at distance r from a mass: g = GM/rยฒ
double g = PhysicsConstants.EarthMass.GravitationalFieldStrength(PhysicsConstants.EarthRadius);
// Gravitational force between two masses: F = Gยทmโยทmโ/rยฒ
double F = PhysicsConstants.EarthMass.GravitationalForce(PhysicsConstants.MoonMass, 3.844e8);
// Escape velocity: v = โ(2GM/r)
double vEsc = PhysicsConstants.EarthMass.EscapeVelocity(PhysicsConstants.EarthRadius);
Circular orbit scalars:
double r = PhysicsConstants.EarthRadius + 408000; // ISS altitude
double speed = PhysicsConstants.EarthMass.OrbitalSpeed(r); // v = โ(GM/r) โ 7660 m/s
double period = PhysicsConstants.EarthMass.OrbitalPeriod(r); // T = 2ฯโ(rยณ/GM) โ 92 min
Position, velocity, and acceleration on a circular orbit at time :
double M = PhysicsConstants.EarthMass;
double r = 1e7; // 10 000 km radius
Vector pos = M.OrbitalPosition(r, time); // Rยท(cos ฯt, sin ฯt, 0)
Vector vel = M.OrbitalVelocity(r, time); // Rฯยท(-sin ฯt, cos ฯt, 0)
Vector acc = M.OrbitalAcceleration(r, time); // -ฯยฒRยท(cos ฯt, sin ฯt, 0)
๐ Relative Motionโ
Compute relative kinematics between two objects or reference frames:
var vA = new Vector(30, 0, 0);
var vB = new Vector(-20, 0, 0);
Vector vRel = vA.RelativeVelocity(vB); // v_A - v_B = (50, 0, 0)
Vector rRel = posA.RelativePosition(posB); // r_A - r_B
Vector aRel = accA.RelativeAcceleration(accB); // a_A - a_B
๐๏ธ Newton's Lawsโ
Compute acceleration from force, force from mass and acceleration, net force, and weight:
// Newton's 2nd law: a = F/m
var force = new Vector(10, 0, 0);
Vector acceleration = force.Acceleration(mass: 5); // (2, 0, 0)
// F = ma
Vector F = 10.0.Force(new Vector(0, 0, -9.8)); // (0, 0, -98)
// Sum of forces
Vector net = f1.NetForce(f2, f3);
// Weight (default direction: -Z)
Vector W = 80.0.Weight(); // (0, 0, -784.5)
๐ฅ Momentum & Impulseโ
Compute linear momentum and impulse:
Vector p = 5.0.Momentum(new Vector(3, 4, 0)); // (15, 20, 0)
Vector J = force.Impulse(duration: 0.5); // Fยทฮt
Vector J2 = mass.ImpulseFromVelocityChange(vBefore, vAfter); // mยทฮv
Vector vNew = impulse.ApplyImpulse(mass: 5, v0); // v + J/m
โก Energyโ
Compute kinetic energy, potential energy, and mechanical energy:
double ke = 4.0.KineticEnergy(new Vector(3, 4, 0)); // ยฝmvยฒ = 50 J
double pe = 10.0.PotentialEnergy(height: 5); // mgh
double U = m1.GravitationalPotentialEnergy(m2, r); // -Gmโmโ/r
double E = mass.MechanicalEnergy(velocity, height); // KE + PE
double v = mass.SpeedFromKineticEnergy(ke); // โ(2ยทKE/m)
๐ง Work & Powerโ
Compute work done by a force and instantaneous or average power:
double W = force.Work(displacement); // Fยทd (dot product)
double W2 = 10.0.Work(5, angleRadians: Math.PI / 3); // Fยทdยทcos(ฮธ) = 25 J
double P = force.Power(velocity); // Fยทv (instantaneous)
double P2 = 100.0.AveragePower(duration: 5); // W/ฮt = 20 W
double ฮKE = mass.WorkEnergyTheorem(vBefore, vAfter); // ยฝm(vโยฒ - vโยฒ)
๐ซ Elastic & Inelastic Collisionsโ
Compute outcomes of 1D and 3D collisions:
// 1D elastic collision โ both momentum and energy conserved
var (v1f, v2f) = m1.ElasticCollision(v1, m2, v2);
// Perfectly inelastic (sticky) collision
double vf = m1.InelasticCollisionVelocity(v1, m2, v2);
Vector vf3d = m1.InelasticCollisionVelocity(v1Vec, m2, v2Vec); // 3D version
double loss = m1.InelasticCollisionEnergyLoss(v1, m2, v2);
// Coefficient of restitution: e = 1 (elastic), e = 0 (perfectly inelastic)
double e = v1Before.CoefficientOfRestitution(v2Before, v1After, v2After);
๐งฑ Rigid Bodyโ
Create rigid bodies from standard shapes with automatic inertia tensors:
var sphere = RigidBody.CreateSolidSphere(mass: 10, radius: 2);
var box = RigidBody.CreateSolidBox(mass: 12, width: 2, height: 3, depth: 4);
var cyl = RigidBody.CreateSolidCylinder(mass: 6, radius: 1, height: 4);
var hollow = RigidBody.CreateHollowSphere(mass: 5, radius: 3);
var tube = RigidBody.CreateHollowCylinder(mass: 8, innerRadius: 1, outerRadius: 2, height: 3);
var rod = RigidBody.CreateThinRod(mass: 4, length: 5);
var wall = RigidBody.CreateStatic(new Vector(0, 0, 0)); // immovable
Apply forces, torques, and query state:
var body = RigidBody.CreateSolidSphere(10, 1);
body.Position = new Vector(0, 5, 0);
body.Velocity = new Vector(3, 0, 0);
body.ApplyForce(new Vector(0, 0, -98)); // gravity
body.ApplyForceAtPoint( // generates torque too
new Vector(10, 0, 0), worldPoint: new Vector(0, 1, 0));
body.ApplyTorque(new Vector(0, 0, 5));
Vector a = body.LinearAcceleration; // F/m
Vector alpha = body.AngularAcceleration; // Iโปยนฯ
Vector p = body.LinearMomentum; // mv
Vector L = body.AngularMomentum; // Iฯ
double KE = body.KineticEnergy; // ยฝmvยฒ + ยฝฯแตIฯ
body.ClearForces(); // reset accumulators after integration step
โฑ๏ธ RigidBody Integrationโ
Three time-stepping methods advance a RigidBody by one dt. Each delegates to the corresponding ODE solver in DifferentialEquationExtensions, packing body state into VectorN internally.
// Semi-implicit (symplectic) Euler โ stable for games, first-order
// Apply forces before calling; accumulators are cleared afterwards
var body = RigidBody.CreateSolidSphere(10, 1);
body.Position = new Vector(0, 0, 100);
body.ApplyForce(new Vector(0, 0, -9.80665 * body.Mass));
body.IntegrateSemiImplicitEuler(dt: 0.001);
// Velocity Verlet โ O(dtยฒ) accuracy, excellent energy conservation
// Forces are evaluated by forceFunc (no need to pre-apply)
Func<RigidBody, (Vector force, Vector torque)> gravity = b =>
(new Vector(0, 0, -9.80665 * b.Mass), new Vector(0, 0, 0));
body.IntegrateVelocityVerlet(gravity, dt: 0.01);
// Explicit Euler โ simplest, least stable
body.ApplyForce(new Vector(0, 0, -9.80665 * body.Mass));
body.IntegrateEuler(dt: 0.001);
๐งฒ Common Force Modelsโ
Ready-made force functions for building simulations โ combine them in a forceFunc for the integrators.
// Spring (Hooke's law): F = -kยท(|ฮr| - Lโ)ยทrฬ
var spring = 50.0.SpringForce(restLength: 2.0, position, anchor);
// Viscous damping: F = -cยทv
var damping = 0.5.DampingForce(velocity);
// Aerodynamic drag: F = -ยฝยทCdยทฯยทAยท|v|ยทv
var drag = 0.47.DragForce(fluidDensity: 1.225, crossSectionArea: 0.01, velocity);
// Friction (kinetic โ moving object)
var kinetic = 0.3.FrictionForce(normalForceMagnitude: 98, velocity);
// Friction (static โ stationary object, opposes applied force up to ฮผN)
var friction = 0.5.FrictionForce(normalForceMagnitude: 100, velocity: new Vector(0, 0, 0),
appliedTangentialForce: new Vector(20, 0, 0)); // returns (-20, 0, 0)
// Compose forces in a Verlet simulation
Func<RigidBody, (Vector, Vector)> forces = b =>
{
var F = 50.0.SpringForce(2.0, b.Position, new Vector(0, 0, 0))
+ 0.5.DampingForce(b.Velocity);
return (F, new Vector(0, 0, 0));
};
body.IntegrateVelocityVerlet(forces, dt: 0.01);
๐ Moment of Inertia (Scalar)โ
double I = 10.0.MomentOfInertiaSolidSphere(radius: 2); // 2/5ยทmrยฒ
double I2 = 10.0.MomentOfInertiaHollowSphere(radius: 2); // 2/3ยทmrยฒ
double I3 = 8.0.MomentOfInertiaSolidCylinder(radius: 3); // ยฝmrยฒ
double I4 = 6.0.MomentOfInertiaThinRod(length: 4); // mLยฒ/12
double I5 = 6.0.MomentOfInertiaThinRodEnd(length: 4); // mLยฒ/3
double I6 = 12.0.MomentOfInertiaSolidBox(sideA: 3, sideB: 4); // m/12ยท(aยฒ+bยฒ)
// Parallel axis theorem: I_new = I_cm + mยทdยฒ
double Inew = I.ParallelAxis(mass: 10, distance: 3);
๐งฎ Inertia Tensor (3ร3 Matrix)โ
Matrix I = 10.0.InertiaTensorSolidSphere(radius: 2);
Matrix Ib = 12.0.InertiaTensorSolidBox(width: 2, height: 3, depth: 4);
Matrix Ic = 6.0.InertiaTensorSolidCylinder(radius: 1, height: 4);
๐ต Simple Harmonic Oscillatorโ
Namespace: CSharpNumerics.Physics.Mechanics.Oscillations
Models the undamped system where .
Integration uses Velocity Verlet (symplectic, O(dtยฒ)) โ excellent energy conservation for undamped systems.
var sho = new SimpleHarmonicOscillator(mass: 2, stiffness: 50, initialPosition: 0.5);
double w = sho.AngularFrequency; // ฯโ = โ(k/m) = 5 rad/s
double f = sho.Frequency; // fโ = ฯโ/2ฯ โ 0.796 Hz
double T = sho.Period; // T = 1/fโ โ 1.257 s
double A = sho.Amplitude; // A = โ(xโยฒ + (vโ/ฯโ)ยฒ) = 0.5 m
double phi = sho.PhaseOffset; // ฯ = atan2(-vโ/ฯโ, xโ)
Analytic solution โ exact reference for verification:
double x = sho.AnalyticPosition(t: 1.0); // Aยทcos(ฯโt + ฯ)
double v = sho.AnalyticVelocity(t: 1.0); // -Aฯโยทsin(ฯโt + ฯ)
Simulation & visualisation
sho.Step(dt: 0.001); // advance one time step
sho.Reset(); // restore initial conditions
List<Serie> trajectory = sho.Trajectory(tEnd: sho.Period * 5, dt: 0.001);
List<Serie> phase = sho.PhasePortrait(tEnd: sho.Period * 2, dt: 0.001);
Energy โ conserved for undamped SHM:
double KE = sho.KineticEnergy; // ยฝmvยฒ
double PE = sho.PotentialEnergy; // ยฝkxยฒ
double E = sho.TotalEnergy; // KE + PE (constant)
List<Serie> energy = sho.EnergyOverTime(tEnd: sho.Period * 10, dt: 0.001);
Frequency spectrum โ FFT peak at the natural frequency :
List<Serie> spectrum = sho.FrequencySpectrum(tEnd: sho.Period * 20, dt: 0.01);
With initial velocity
var sho2 = new SimpleHarmonicOscillator(mass: 1, stiffness: 25,
initialPosition: 0, initialVelocity: 5);
Console.WriteLine(sho2.Amplitude); // A = โ(0ยฒ + (5/5)ยฒ) = 1.0 m
๐ Damped Oscillatorโ
Models where .
Three damping regimes are automatically detected:
- Underdamped () โ oscillates with exponential decay
- Critically damped () โ fastest non-oscillatory return
- Overdamped () โ slow exponential decay
Integration uses RK4 โ appropriate for dissipative systems.
var osc = new DampedOscillator(mass: 1, stiffness: 100, damping: 4, initialPosition: 1.0);
double w0 = osc.NaturalFrequency; // ฯโ = 10 rad/s
double g = osc.Gamma; // ฮณ = 2 rad/s
double wd = osc.DampedFrequency; // ฯ_d = โ96 โ 9.80 rad/s
double Td = osc.DampedPeriod; // 2ฯ/ฯ_d โ 0.641 s
DampingRegime regime = osc.Regime; // Underdamped
double Q = osc.QualityFactor; // ฯโ/(2ฮณ) = 2.5
double delta = osc.LogarithmicDecrement; // ฮณยทT_d โ 1.283
Regime detection
var under = new DampedOscillator(1, 100, 4); // ฮณ=2 < ฯโ=10 โ Underdamped
var crit = new DampedOscillator(1, 100, 20); // ฮณ=10 = ฯโ=10 โ CriticallyDamped
var over = new DampedOscillator(1, 100, 40); // ฮณ=20 > ฯโ=10 โ Overdamped
Analytic solution โ all three regimes:
// Underdamped: x(t) = Aยทe^(โฮณt)ยทcos(ฯ_dยทt + ฯ)
// Critical: x(t) = (Cโ + Cโt)ยทe^(โฮณt)
// Overdamped: x(t) = Cโยทe^(rโt) + Cโยทe^(rโt)
double x = osc.AnalyticPosition(t: 1.0);
double v = osc.AnalyticVelocity(t: 1.0);
Simulation & visualisation
osc.Step(dt: 0.001);
osc.Reset();
List<Serie> trajectory = osc.Trajectory(tEnd: 5.0, dt: 0.001);
List<Serie> phase = osc.PhasePortrait(tEnd: 5.0, dt: 0.001); // spirals to origin
Energy โ monotonically decreasing:
double E = osc.TotalEnergy;
List<Serie> energy = osc.EnergyOverTime(tEnd: 5.0, dt: 0.001);
List<Serie> dissipated = osc.EnergyDissipation(tEnd: 5.0, dt: 0.001); // Eโ โ E(t)
Envelope & spectrum
double env = osc.Envelope(t: 1.0); // Aยทe^(โฮณt)
List<Serie> envCurve = osc.EnvelopeCurve(tEnd: 5.0, dt: 0.01);
List<Serie> spectrum = osc.FrequencySpectrum(tEnd: 20.0, dt: 0.005); // peak at ฯ_d
Zero damping reduces to SimpleHarmonicOscillator behaviour.
โก Driven Oscillatorโ
Extends the damped oscillator with a harmonic driving force:
var osc = new DrivenOscillator(
mass: 1.0, stiffness: 100.0, damping: 4.0,
driveAmplitude: 10.0, driveFrequency: 7.0,
initialPosition: 0.0, initialVelocity: 0.0);
| Property | Formula | Description |
|---|---|---|
NaturalFrequency | Undamped natural frequency | |
Gamma | Damping rate | |
DampedFrequency | Damped frequency | |
Regime | auto-detected | Underdamped, CriticallyDamped, or Overdamped |
QualityFactor | Sharpness of resonance | |
ResonanceFrequency | Frequency of max amplitude (0 if ) | |
Bandwidth | Width of resonance peak |
Steady-state response
double A = osc.SteadyStateAmplitude(wd); // (Fโ/m) / โ((ฯโยฒโฯdยฒ)ยฒ + (2ฮณฯd)ยฒ)
double ฯ = osc.SteadyStatePhase(wd); // โatan2(2ฮณฯd, ฯโยฒโฯdยฒ)
double Adrive = osc.SteadyStateAmplitudeAtDrive;
double ฯdrive = osc.SteadyStatePhaseAtDrive;
Resonance curve & phase response
List<Serie> resonance = osc.ResonanceCurve(wMin: 0.1, wMax: 20, steps: 500);
List<Serie> phaseResp = osc.PhaseResponse(wMin: 0.1, wMax: 20, steps: 500);
Transfer function
ComplexNumber H = osc.TransferFunction(s); // H(s) = 1/(sยฒ + 2ฮณs + ฯโยฒ)
ComplexNumber Hiw = osc.FrequencyResponse(w); // H(iฯ)
Simulation
osc.Step(dt: 0.001);
List<Serie> traj = osc.Trajectory(5.0, 0.001);
List<Serie> phase = osc.PhasePortrait(5.0, 0.001);
Steady-state extraction
List<Serie> steady = osc.SteadyStateTrajectory(
steadyDuration: 10.0, dt: 0.001, transientDuration: null); // auto = 5/ฮณ
double Ameas = osc.MeasuredSteadyStateAmplitude(dt: 0.001);