import { Course, CoursePhysics } from '../../types/course'; import { Path } from '../../types/path'; /** * Core power computation engine for virtual cycling simulations. * * This class implements the fundamental physics calculations that drive * the simulation, including: * * **Power Balance:** * - Calculates net power from all sources (cyclist + resistances) * - Determines acceleration/deceleration from power balance * * **Speed Integration:** * - Uses energy conservation for speed calculations * - Enforces minimum speed constraints * * **Time Stepping:** * - Adaptive time step calculations for GPS waypoint alignment * - Binary search for optimal time steps * * **Equivalent Mass:** * - Accounts for rotational inertia of wheels * - Uses effective mass for acceleration calculations * * ## Physics Model * * The core equation relates power to kinetic energy change: * ``` * P_total = ΔKE / Δt = 0.5 × M_eq × (v₂² - v₁²) / Δt * ``` * * Where: * - M_eq = m + (I_front + I_rear) / r² (equivalent mass) * - v₁, v₂: speeds before and after time step * - Δt: time step duration * * Solving for new speed: * ``` * v₂ = √(2ΔtP/M_eq + v₁²) * ``` * * Uses singleton pattern since it's stateless and can be shared across simulations. * * @see https://en.wikipedia.org/wiki/Bicycle_performance#Power_and_energy */ export declare class PowerComputer { static INSTANCE: PowerComputer; protected constructor(); /** * Calculates the net power at a specific point. * * Sums power from all providers to get the total power balance. * Can optionally exclude cyclist power to calculate only resistances. * * @param course Course configuration * @param path Path containing point data * @param pointIndex Index of current point * @param withCyclist If true, include cyclist power; if false, only resistances * @returns Net power in watts (sum of all powers) */ getNewPower(course: CoursePhysics, path: Path, pointIndex: number, withCyclist: boolean): number; /** * Calculates distance traveled given power, mass, speed, and time step. * * Uses energy conservation to determine new speed, then calculates * distance. * * Physics: * 1. Power × time = change in kinetic energy * 2. Solve for new speed: v₂ = √(2ΔtP/M_eq + v₁²) * 3. Distance: Δx = (v₁ + v₂) × Δt / 2 * * Enforces minimum speed constraint to avoid numerical instability. * * @param pSum Net power in watts * @param equivalentMass Equivalent mass including rotational inertia (kg) * @param currentSpeed Current speed in m/s * @param dt Time step in seconds * @returns Distance traveled in meters */ getDx(pSum: number, equivalentMass: number, currentSpeed: number, dt: number): number; /** * Calculates total power from speed change using kinetic energy formula. * * P = ΔKE / Δt = 0.5 × M_eq × (v₂² - v₁²) / Δt * * @param equivalentMass Equivalent mass including rotational inertia (kg) * @param s1 Initial speed in m/s * @param s2 Final speed in m/s * @param dt Time step in seconds * @returns Power in watts */ protected getTotPower(equivalentMass: number, s1: number, s2: number, dt: number): number; /** * Calculates the time step needed to travel a specific distance. * * Uses binary search to find the time step that produces the target * distance given current power balance and speed. * * This is used for GPS waypoint alignment, where we know the distance * between points and need to find the corresponding time step. * * Search range: -0.1 to DT+0.1 seconds * Convergence: dx / 10,000,000 (very tight tolerance) * * @param pSum Net power in watts * @param equivalentMass Equivalent mass including rotational inertia (kg) * @param currentSpeed Current speed in m/s * @param dx Target distance in meters * @returns Time step in seconds */ getDt(pSum: number, equivalentMass: number, currentSpeed: number, dx: number): number; getDtInner(pSum: number, equivalentMass: number, currentSpeed: number, dx: number, dt1: number, dt2: number): number; /** * Computes cyclist power from measured speed change between two points. * * This is the inverse problem: given speed change, calculate the power * that must have been applied. Used for analyzing recorded rides with * speed data but no power meter. * * Process: * 1. Calculate resistance powers at point 1 * 2. Calculate total power from speed change * 3. Cyclist power = total power - resistance powers * 4. Adjust for drivetrain efficiency * * @param course Course configuration * @param path Path containing point data * @param equivalentMass Equivalent mass including rotational inertia (kg) * @param pointIndex1 Index of first point * @param pointIndex2 Index of second point */ computeCyclistPower(course: CoursePhysics, path: Path, equivalentMass: number, i: number): void; /** * Calculates the equivalent mass accounting for rotational inertia. * * Wheels have rotational inertia that effectively increases the mass * that must be accelerated. The equivalent mass formula is: * * M_eq = m + I_total / r² * * Where: * - m: total system mass (cyclist + bike) * - I_total: sum of wheel rotational inertias * - r: wheel radius * * This accounts for the fact that accelerating the wheels requires * energy for both linear and rotational motion. * * Typical values: * - System mass: 80 kg * - Wheel inertia: 0.12 kg⋅m² total * - Wheel radius: 0.7 m * - Equivalent mass: ~80.25 kg (~0.3% increase) * * @param course Course configuration with cyclist and bike parameters * @returns Equivalent mass in kg */ getEquivalentMass(course: Course): number; } //# sourceMappingURL=PowerComputer.d.ts.map