Referencia Técnica y Fórmulas
Implementación Matemática Completa
Guía de Implementación
Esta página proporciona fórmulas listas para copiar y pegar, así como métodos de cálculo paso a paso para todas las métricas de Swim Analytics. Úsalas para implementaciones personalizadas, verificación o comprensión más profunda.
⚠️ Notas de Implementación
- Todos los tiempos deben convertirse a segundos para los cálculos
- El ritmo de natación es inverso (mayor % = ritmo más lento)
- Valida siempre las entradas para rangos razonables
- Maneja casos límite (división por cero, valores negativos)
¿Quiere evitar los cálculos manuales? Lea nuestroGuía de carga de entrenamientoo utilice la aplicación gratuita Swim Analytics.
Métricas de Rendimiento Principales
Velocidad Crítica de Nado (CSS)
Fórmula:
CSS (m/s) = (D₂ - D₁) / (T₂ - T₁)
CSS Ritmo/100m (segundos) = (T₄₀₀ - T₂₀₀) / 2
🧪 Calculadora Interactiva - Prueba la Fórmula
Ritmo CSS por 100m:
1:49
Pasos del cálculo:
CSS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Ritmo/100m = 100 / 0.917 = 109 segundos = 1:49
CSS (m/s) = (400 - 200) / (368 - 150) = 0.917 m/s
Ritmo/100m = 100 / 0.917 = 109 segundos = 1:49
Implementación en JavaScript:
function calculateCSS(distance1, time1, distance2, time2) {
// Convertir tiempos a segundos si es necesario
const t1 = typeof time1 === 'string' ? timeToSeconds(time1) : time1;
const t2 = typeof time2 === 'string' ? timeToSeconds(time2) : time2;
// Calcular CSS en m/s
const css_ms = (distance2 - distance1) / (t2 - t1);
// Calcular ritmo por 100m en segundos
const pace_per_100m = 100 / css_ms;
// Convertir a formato mm:ss
const minutes = Math.floor(pace_per_100m / 60);
const seconds = Math.round(pace_per_100m % 60);
return {
css_ms: css_ms,
pace_seconds: pace_per_100m,
pace_formatted: `${minutes}:${seconds.toString().padStart(2, '0')}`
};
}
// Ejemplo de uso:
const result = calculateCSS(200, 150, 400, 368);
// Devuelve: { css_ms: 0.917, pace_seconds: 109, pace_formatted: "1:49" }TSS de Natación (sTSS)
Fórmula Completa:
sTSS = (IF³) × Duración (horas) × 100
IF = NSS / FTP
NSS = Distancia Total / Tiempo Total (m/min)
🧪 Calculadora Interactiva - Prueba la Fórmula
sTSS Calculado:
55
Pasos del cálculo:
NSS = 3000m / 55min = 54.5 m/min
FTP = 100 / (93/60) = 64.5 m/min
IF = 54.5 / 64.5 = 0.845
sTSS = 0.845³ × (55/60) × 100 = 55
NSS = 3000m / 55min = 54.5 m/min
FTP = 100 / (93/60) = 64.5 m/min
IF = 54.5 / 64.5 = 0.845
sTSS = 0.845³ × (55/60) × 100 = 55
Implementación en JavaScript:
function calculateSTSS(distance, timeMinutes, ftpMetersPerMin) {
// Calcular Velocidad de Nado Normalizada
const nss = distance / timeMinutes;
// Calcular Factor de Intensidad
const intensityFactor = nss / ftpMetersPerMin;
// Calcular horas
const hours = timeMinutes / 60;
// Calcular sTSS usando factor de intensidad al cubo
const stss = Math.pow(intensityFactor, 3) * hours * 100;
return Math.round(stss);
}
// Ejemplo de uso:
const stss = calculateSTSS(3000, 55, 64.5);
// Devuelve: 55
// Auxiliar: Convertir CSS a FTP
function cssToFTP(cssPacePer100mSeconds) {
// FTP en m/min = 100m / (ritmo en minutos)
return 100 / (cssPacePer100mSeconds / 60);
}
// Ejemplo: CSS de 1:33 (93 segundos)
const ftp = cssToFTP(93); // Devuelve: 64.5 m/minSWOLF
Fórmula:
SWOLF = Tiempo del Largo (segundos) + Cuenta de Brazadas
SWOLF₂₅ = (Tiempo × 25/Longitud Piscina) + (Brazadas × 25/Longitud Piscina)
🧪 Calculadora Interactiva - Prueba la Fórmula
Puntuación SWOLF:
35
Cálculo:
SWOLF = 20s + 15 brazadas = 35
SWOLF = 20s + 15 brazadas = 35
Implementación en JavaScript:
function calculateSWOLF(timeSeconds, strokeCount) {
return timeSeconds + strokeCount;
}
function calculateNormalizedSWOLF(timeSeconds, strokeCount, poolLength) {
const normalizedTime = timeSeconds * (25 / poolLength);
const normalizedStrokes = strokeCount * (25 / poolLength);
return normalizedTime + normalizedStrokes;
}
// Ejemplo:
const swolf = calculateSWOLF(20, 15);
// Devuelve: 35
const swolf50m = calculateNormalizedSWOLF(40, 30, 50);
// Devuelve: 35 (normalizado a 25m)Mecánica de Brazada
Stroke Rate (SR)
Fórmula:
SR = 60 / Tiempo de Ciclo (segundos)
SR = (Número de Brazadas / Tiempo en segundos) × 60
🧪 Calculadora Interactiva - Prueba la Fórmula
Stroke Rate (SPM):
72
Cálculo:
SR = (30 / 25) × 60 = 72 SPM
SR = (30 / 25) × 60 = 72 SPM
Implementación en JavaScript:
function calculateStrokeRate(strokeCount, timeSeconds) {
return (strokeCount / timeSeconds) * 60;
}
// Ejemplo:
const sr = calculateStrokeRate(30, 25);
// Devuelve: 72 SPMDistance Per Stroke (DPS)
Fórmula:
DPS = Distancia / Cuenta de Brazadas
DPS = Distancia / (SR / 60)
Implementación en JavaScript:
function calculateDPS(distance, strokeCount, pushoffDistance = 0) {
const effectiveDistance = distance - pushoffDistance;
return effectiveDistance / strokeCount;
}
// Ejemplo (piscina 25m, 5m impulso):
const dps = calculateDPS(25, 12, 5);
// Devuelve: 1.67 m/brazada
// Para múltiples largos:
const dps100m = calculateDPS(100, 48, 4 * 5);
// Devuelve: 1.67 m/brazada (4 largos × 5m impulso)Velocidad a partir de SR y DPS
Fórmula:
Velocidad (m/s) = (SR / 60) × DPS
Implementación en JavaScript:
function calculateVelocity(strokeRate, dps) {
return (strokeRate / 60) * dps;
}
// Ejemplo:
const velocity = calculateVelocity(70, 1.6);
// Devuelve: 1.87 m/sStroke Index (SI)
Fórmula:
SI = Velocidad (m/s) × DPS (m/brazada)
Implementación en JavaScript:
function calculateStrokeIndex(velocity, dps) {
return velocity * dps;
}
// Ejemplo:
const si = calculateStrokeIndex(1.5, 1.7);
// Devuelve: 2.55Gráfico de Gestión del Rendimiento (PMC)
Cálculos de CTL, ATL, TSB
Fórmulas:
CTL hoy = CTL ayer + (TSS hoy - CTL ayer) × (1/42)
ATL hoy = ATL ayer + (TSS hoy - ATL ayer) × (1/7)
TSB = CTL ayer - ATL ayer
Implementación en JavaScript:
function updateCTL(previousCTL, todayTSS) {
return previousCTL + (todayTSS - previousCTL) * (1/42);
}
function updateATL(previousATL, todayTSS) {
return previousATL + (todayTSS - previousATL) * (1/7);
}
function calculateTSB(yesterdayCTL, yesterdayATL) {
return yesterdayCTL - yesterdayATL;
}
// Calculate PMC for series of workouts
function calculatePMC(workouts) {
let ctl = 0, atl = 0;
const results = [];
workouts.forEach(workout => {
ctl = updateCTL(ctl, workout.tss);
atl = updateATL(atl, workout.tss);
const tsb = calculateTSB(ctl, atl);
results.push({
date: workout.date,
tss: workout.tss,
ctl: Math.round(ctl * 10) / 10,
atl: Math.round(atl * 10) / 10,
tsb: Math.round(tsb * 10) / 10
});
});
return results;
}
// Example usage:
const workouts = [
{ date: '2025-01-01', tss: 50 },
{ date: '2025-01-02', tss: 60 },
{ date: '2025-01-03', tss: 45 },
// ... more workouts
];
const pmc = calculatePMC(workouts);
// Returns array with CTL, ATL, TSB for each dayCálculos Avanzados
CSS desde Múltiples Distancias (Método de Regresión)
Implementación en JavaScript:
function calculateCSSRegression(distances, times) {
// Linear regression: distance = a + b*time
const n = distances.length;
const sumX = times.reduce((a, b) => a + b, 0);
const sumY = distances.reduce((a, b) => a + b, 0);
const sumXY = times.reduce((sum, x, i) => sum + x * distances[i], 0);
const sumXX = times.reduce((sum, x) => sum + x * x, 0);
const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
const intercept = (sumY - slope * sumX) / n;
return {
css: slope, // Critical swimming velocity (m/s)
anaerobic_capacity: intercept // Anaerobic distance capacity (m)
};
}
// Ejemplo con múltiples distancias de prueba:
const distances = [100, 200, 400, 800];
const times = [65, 150, 340, 720]; // en segundos
const result = calculateCSSRegression(distances, times);
// Devuelve: { css: 1.18, anaerobic_capacity: 15.3 }Factor de Intensidad desde el Ritmo
Implementación en JavaScript:
function calculateIntensityFactor(actualPace100m, thresholdPace100m) {
// Convert pace to speed (m/s)
const actualSpeed = 100 / actualPace100m;
const thresholdSpeed = 100 / thresholdPace100m;
return actualSpeed / thresholdSpeed;
}
// Ejemplo:
const if_value = calculateIntensityFactor(110, 93);
// Devuelve: 0.845 (nadando al 84.5% del umbral)Análisis de Consistencia del Ritmo
Implementación en JavaScript:
function analyzePaceConsistency(laps) {
const paces = laps.map(lap => lap.distance / lap.time);
const avgPace = paces.reduce((a, b) => a + b) / paces.length;
const variance = paces.reduce((sum, pace) =>
sum + Math.pow(pace - avgPace, 2), 0) / paces.length;
const stdDev = Math.sqrt(variance);
const coefficientOfVariation = (stdDev / avgPace) * 100;
return {
avgPace,
stdDev,
coefficientOfVariation,
consistency: coefficientOfVariation < 5 ? "Excelente" :
coefficientOfVariation < 10 ? "Buena" :
coefficientOfVariation < 15 ? "Moderada" : "Variable"
};
}
// Ejemplo:
const laps = [
{ distance: 100, time: 70 },
{ distance: 100, time: 72 },
{ distance: 100, time: 71 },
// ...
];
const analysis = analyzePaceConsistency(laps);
// Devuelve: { avgPace: 1.41, stdDev: 0.02, coefficientOfVariation: 1.4, consistency: "Excelente" }Detección de Fatiga mediante Cuenta de Brazadas
Implementación en JavaScript:
function detectFatigue(laps) {
const firstThird = laps.slice(0, Math.floor(laps.length/3));
const lastThird = laps.slice(-Math.floor(laps.length/3));
const firstThirdAvg = firstThird.reduce((sum, lap) =>
sum + lap.strokeCount, 0) / firstThird.length;
const lastThirdAvg = lastThird.reduce((sum, lap) =>
sum + lap.strokeCount, 0) / lastThird.length;
const strokeCountIncrease = ((lastThirdAvg - firstThirdAvg) / firstThirdAvg) * 100;
return {
firstThirdAvg: Math.round(firstThirdAvg * 10) / 10,
lastThirdAvg: Math.round(lastThirdAvg * 10) / 10,
percentIncrease: Math.round(strokeCountIncrease * 10) / 10,
fatigueLevel: strokeCountIncrease < 5 ? "Mínima" :
strokeCountIncrease < 10 ? "Moderada" :
strokeCountIncrease < 20 ? "Significativa" : "Severa"
};
}
// Ejemplo:
const laps = [
{ strokeCount: 14 }, { strokeCount: 14 }, { strokeCount: 15 },
{ strokeCount: 15 }, { strokeCount: 16 }, { strokeCount: 16 },
{ strokeCount: 17 }, { strokeCount: 18 }, { strokeCount: 18 }
];
const fatigue = detectFatigue(laps);
// Devuelve: { firstThirdAvg: 14.3, lastThirdAvg: 17.7, percentIncrease: 23.8, fatigueLevel: "Severa" }Validación de Datos
Verificación de Calidad de Datos de Entrenamiento
Implementación en JavaScript:
function validateWorkoutData(workout) {
const issues = [];
// Check for reasonable pace ranges (1:00-5:00 per 100m)
const avgPace = (workout.totalTime / workout.totalDistance) * 100;
if (avgPace < 60 || avgPace > 300) {
issues.push(`Ritmo promedio inusual: ${Math.round(avgPace)}s por 100m`);
}
// Check for reasonable stroke counts (10-50 per 25m)
const avgStrokesPer25m = (workout.totalStrokes / workout.totalDistance) * 25;
if (avgStrokesPer25m < 10 || avgStrokesPer25m > 50) {
issues.push(`Cuenta de brazadas inusual: ${Math.round(avgStrokesPer25m)} por 25m`);
}
// Check for reasonable stroke rate (30-150 SPM)
const avgSR = calculateStrokeRate(workout.totalStrokes, workout.totalTime);
if (avgSR < 30 || avgSR > 150) {
issues.push(`Frecuencia de brazada inusual: ${Math.round(avgSR)} SPM`);
}
// Check for missing laps (gaps in time)
if (workout.laps && workout.laps.length > 1) {
for (let i = 1; i < workout.laps.length; i++) {
const gap = workout.laps[i].startTime -
(workout.laps[i-1].startTime + workout.laps[i-1].duration);
if (gap > 300) { // 5 minute gap
issues.push(`Hueco grande detectado entre largos ${i} y ${i+1}`);
}
}
}
return {
isValid: issues.length === 0,
issues
};
}
// Ejemplo:
const workout = {
totalDistance: 2000,
totalTime: 1800, // 30 minutos
totalStrokes: 800,
laps: [/* datos de largos */]
};
const validation = validateWorkoutData(workout);
// Devuelve: { isValid: true, issues: [] }Funciones Auxiliares
Utilidades de Conversión de Tiempo
Implementación en JavaScript:
// Convert mm:ss to seconds
function timeToSeconds(timeString) {
const parts = timeString.split(':');
return parseInt(parts[0]) * 60 + parseInt(parts[1]);
}
// Convert seconds to mm:ss
function secondsToTime(seconds) {
const minutes = Math.floor(seconds / 60);
const secs = Math.round(seconds % 60);
return `${minutes}:${secs.toString().padStart(2, '0')}`;
}
// Convert seconds to hh:mm:ss
function secondsToTimeDetailed(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = Math.round(seconds % 60);
return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
// Ejemplos:
timeToSeconds("1:33"); // Devuelve: 93
secondsToTime(93); // Devuelve: "1:33"
secondsToTimeDetailed(3665); // Devuelve: "1:01:05"Recursos de Implementación
Todas las fórmulas en esta página están listas para producción y validadas contra literatura científica. Úsalas para herramientas de análisis personalizadas, verificación o comprensión más profunda de los cálculos de rendimiento en natación.
💡 Mejores Prácticas
- Valida las entradas: Verifica rangos razonables antes de calcular
- Maneja casos límite: División por cero, valores negativos, datos nulos
- Redondea apropiadamente: CTL/ATL/TSB a 1 decimal, sTSS a entero
- Almacena precisión: Mantén precisión completa en base de datos, redondea para mostrar
- Prueba exhaustivamente: Usa datos conocidos y correctos para verificar cálculos
