private static void ComputeDetailedFileReport(Options options) { using (var stream = File.OpenRead(options.File)) { var parser = new FastParser(stream); var laps = new List <LapSummary>(); double minimumHeartRateStandardDeviation = 4; var normalizedPowerCalculator = new PowerStatisticsCalculator(FTP); var powerCurveCalculator = new PowerCurveCalculator(new int[] { 1, 5, 10, 30, 60, 120, 240, 300, 600, 900 }); var normalizedPowerCurveCalculator = new NormalizedPowerCurveCalculator(new int[] { 60, 120, 240, 300, 600, 900 }); var heartRateVarianceCalculator = new HeartRateVarianceCalculator(new int[] { 600, 1200, 2400, 3600 }); var efficiencyFactorCalculator = new EfficiencyFactorCalculator(new int[] { 600, 1200, 2400 }, minimumHeartRateStandardDeviation); var timer = new Stopwatch(); timer.Start(); foreach (var record in parser.GetMessages()) { if (record.GlobalMessageNumber != GlobalMessageDecls.Record) { // Dump the name of the record Console.WriteLine(record.GlobalMessageNumber.ToString()); } if (record.GlobalMessageNumber == GlobalMessageDecls.Record) { double power, heartRate; bool hasPower, hasHeartRate; if (hasPower = record.TryGetField(RecordDef.Power, out power)) { powerCurveCalculator.Add(power); normalizedPowerCalculator.Add(power); normalizedPowerCurveCalculator.Add(power); } if (hasHeartRate = record.TryGetField(RecordDef.HeartRate, out heartRate)) { heartRateVarianceCalculator.Add(heartRate); } if (hasPower && hasHeartRate) { efficiencyFactorCalculator.Add(power, heartRate); } } else if (record.IsStopTimerEvent()) { normalizedPowerCalculator.Reset(); powerCurveCalculator.Reset(); normalizedPowerCurveCalculator.Reset(); heartRateVarianceCalculator.Reset(); efficiencyFactorCalculator.Reset(); } else if (record.GlobalMessageNumber == GlobalMessageDecls.Lap) { } } timer.Stop(); Console.WriteLine("Peak Average Power Curve:\n"); for (int i = 0; i < powerCurveCalculator.Durations.Length; i++) { Console.WriteLine("Duration: {0}s, Peak Average Power: {1:0}W", powerCurveCalculator.Durations[i], powerCurveCalculator.PeakAveragePowerForDuration[i]); } Console.WriteLine("\n"); Console.WriteLine("Peak Normalized Power Curve:\n"); for (int i = 0; i < normalizedPowerCurveCalculator.Durations.Length; i++) { Console.WriteLine("Duration: {0}s, Peak Normalized Power: {1:0}W", normalizedPowerCurveCalculator.Durations[i], normalizedPowerCurveCalculator.PeakNormalizedPowerForDuration[i]); } Console.WriteLine("\n"); Console.WriteLine("Minimum Heart Rate Variance:\n"); for (int i = 0; i < heartRateVarianceCalculator.Durations.Length; i++) { Console.WriteLine("Duration: {0}s, Average Heart Rate: {1:0}bpm +/- {2:0.0}", heartRateVarianceCalculator.Durations[i], heartRateVarianceCalculator.MeanHeartRateForDuration[i], heartRateVarianceCalculator.StandardDeviationForDuration[i]); } Console.WriteLine("\n"); Console.WriteLine("Efficiency Factor:\n"); for (int i = 0; i < efficiencyFactorCalculator.Durations.Length; i++) { Console.WriteLine("Duration: {0}s, NP = {1:0}W, HR = {2:0.0}+/-{3:0.0}, EF = {4:0.000}", efficiencyFactorCalculator.Durations[i], efficiencyFactorCalculator.NormalizedPowerForDuration[i], efficiencyFactorCalculator.MeanHeartRateForDuration[i], efficiencyFactorCalculator.StandardDeviationForDuration[i], efficiencyFactorCalculator.EfficiencyFactorForDuration[i]); } Console.WriteLine("\n"); Console.WriteLine("Summary statistics:\n"); Console.WriteLine("Average Heart Rate: {0:0}bpm", heartRateVarianceCalculator.AverageHeartRate); Console.WriteLine("Average power: {0:0}W", powerCurveCalculator.AveragePower); Console.WriteLine("Normalized power: {0:0}W", normalizedPowerCalculator.NormalizedPower); Console.WriteLine("Intensity factor: {0:0.000}", normalizedPowerCalculator.IntensityFactor); Console.WriteLine("Variability index: {0:0.000}", normalizedPowerCalculator.VariabilityIndex); Console.WriteLine("Training Stress Score: {0:0}", normalizedPowerCalculator.TrainingStressScore); Console.WriteLine("Processing duration: {0}ms", timer.ElapsedMilliseconds); // Optional part to dump captured heart rate from efficiency calculator if (options.DumpHeartRateData) { for (int i = 0; i < efficiencyFactorCalculator.StandardDeviationForDuration.Length; i++) { if (efficiencyFactorCalculator.StandardDeviationForDuration[i] > 0) { for (int j = 0; j < efficiencyFactorCalculator.CapturedHeartRateTraces[i].Length; j++) { Console.WriteLine(efficiencyFactorCalculator.CapturedHeartRateTraces[i][j]); } } } } } }
static void ComputeTrainingStressReport(Options options) { var files = Directory.GetFiles(options.Directory, "*.fit"); var timer = new Stopwatch(); timer.Start(); var sb = new StringBuilder(); Dictionary <int, Dictionary <int, double> > tssHistogram = new Dictionary <int, Dictionary <int, double> >(); var calendar = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar; foreach (var file in files) { using (var stream = File.OpenRead(file)) { var parser = new FastParser(stream); var powerCalculator = new PowerStatisticsCalculator(FTP); bool isFirstRecord = true, retrievedTimeStampOfFirstRecord = false; DateTime timeStampOfFirstRecord = DateTime.MinValue; foreach (var message in parser.GetMessages()) { if (message.GlobalMessageNumber == GlobalMessageDecls.Record) { if (isFirstRecord) { retrievedTimeStampOfFirstRecord = message.TryGetField(RecordDef.TimeStamp, out timeStampOfFirstRecord); isFirstRecord = false; } double power; if (message.TryGetField(RecordDef.Power, out power)) { powerCalculator.Add(power); } } } if (retrievedTimeStampOfFirstRecord) { int year = timeStampOfFirstRecord.Year; int week = calendar.GetWeekOfYear(timeStampOfFirstRecord, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday); if (!tssHistogram.ContainsKey(year)) { tssHistogram[year] = new Dictionary <int, double>(); } if (tssHistogram[year].ContainsKey(week)) { tssHistogram[year][week] += powerCalculator.TrainingStressScore; } else { tssHistogram[year][week] = powerCalculator.TrainingStressScore; } } else { sb.Append(String.Format("Unknown date for {0} TSS: {1:0}\n", file, powerCalculator.TrainingStressScore)); } } } // Generate Report foreach (int year in tssHistogram.Keys) { sb.Append(String.Format("\nYear {0}\n", year)); foreach (int week in tssHistogram[year].Keys) { sb.Append(String.Format(" Week {0} TSS = {1:0}\n", week, tssHistogram[year][week])); } } timer.Stop(); Console.WriteLine(sb); Console.WriteLine("Total compute time: {0}ms", timer.ElapsedMilliseconds); }
static void ComputeEfficiencyFactorReport(Options options) { // Parameters double standardDeviationThreshold = 7; double meanHeartRateLimit = 142; // upper limit of Z2 var files = Directory.GetFiles(options.Directory, "*.fit"); var timer = new Stopwatch(); timer.Start(); var sb = new StringBuilder(); foreach (var file in files) { using (var stream = File.OpenRead(file)) { var parser = new FastParser(stream); var efficiencyFactorCalculator = new EfficiencyFactorCalculator(new int[] { 600 }, standardDeviationThreshold); foreach (var record in parser.GetMessages()) { if (record.GlobalMessageNumber == GlobalMessageDecls.Record) { double power, heartRate; bool hasPower = record.TryGetField(RecordDef.Power, out power); bool hasHeartRate = record.TryGetField(RecordDef.HeartRate, out heartRate); if (hasPower && hasHeartRate) { efficiencyFactorCalculator.Add(power, heartRate); } } else if (record.IsStopTimerEvent()) { efficiencyFactorCalculator.Reset(); } } if (!efficiencyFactorCalculator.HasData) { //Console.WriteLine("{0} has no HR data", Path.GetFileNameWithoutExtension(file)); } else { for (int i = 0; i < efficiencyFactorCalculator.Durations.Length; i++) { if (efficiencyFactorCalculator.StandardDeviationForDuration[i] > 0 && efficiencyFactorCalculator.MeanHeartRateForDuration[i] < meanHeartRateLimit) { sb.AppendLine(String.Format("{0}, Duration {1}s, EF = {2:0.000}, NP = {3:0}, Avg HR = {4:0.0} +/- {5:0.0}", Path.GetFileNameWithoutExtension(file), efficiencyFactorCalculator.Durations[i], efficiencyFactorCalculator.EfficiencyFactorForDuration[i], efficiencyFactorCalculator.NormalizedPowerForDuration[i], efficiencyFactorCalculator.MeanHeartRateForDuration[i], efficiencyFactorCalculator.StandardDeviationForDuration[i])); } } } } } timer.Stop(); Console.WriteLine(sb); Console.WriteLine("Total compute time: {0}ms", timer.ElapsedMilliseconds); }