Example #1
0
        public void TestSingleFileParsePerformance()
        {
            int  recordsParsed  = 0;
            long fastParserTime = TimeIt(5, @"TestData\large_file.fit", (stream) =>
            {
                System.DateTime maxTime = System.DateTime.MinValue;
                var fastParser          = new FastParser(stream);
                foreach (var dataRecord in fastParser.GetMessages())
                {
                    System.DateTime timeStamp;
                    if (dataRecord.GlobalMessageNumber == GlobalMessageDecls.Record)
                    {
                        if (dataRecord.TryGetField(RecordDef.TimeStamp, out timeStamp))
                        {
                            // Bogus calculation to make sure we don't optimize this away
                            if (timeStamp > maxTime)
                            {
                                maxTime = timeStamp;
                            }
                        }
                        recordsParsed++;
                    }
                }
            });

            Console.WriteLine("Parse large_file.fit best time {0}ms, {1} records parsed", fastParserTime, recordsParsed);
        }
Example #2
0
        private FileResult TestReadingAllFilesInDirectoryUsingFastParser(Stream stream, bool validateCrc)
        {
            System.DateTime maxTime       = System.DateTime.MinValue;
            int             recordsParsed = 0;
            var             fastParser    = new FastParser(stream);

            if (validateCrc)
            {
                Assert.IsTrue(fastParser.IsFileValid());
            }

            foreach (var dataRecord in fastParser.GetMessages())
            {
                System.DateTime timeStamp;
                if (dataRecord.GlobalMessageNumber == GlobalMessageDecls.Record)
                {
                    if (dataRecord.TryGetField(RecordDef.TimeStamp, out timeStamp))
                    {
                        // Bogus calculation to make sure we don't optimize this away
                        if (timeStamp > maxTime)
                        {
                            maxTime = timeStamp;
                        }
                    }
                    recordsParsed++;
                }
            }
            return(new FileResult {
                Records = recordsParsed, LatestDateTimeInFile = maxTime
            });
        }
Example #3
0
        public List <FastPacket> LoadFastBinaryFile(String fastBinFileName)
        {
            List <FastPacket> packetList = new List <FastPacket>();

            if (!File.Exists(fastBinFileName))
            {
                return(packetList);
            }
            using (FileStream fileStream = File.Open(fastBinFileName, FileMode.Open))
            {
                BinaryReader binaryReader = new BinaryReader(fileStream);
                while (binaryReader.BaseStream.Position <= binaryReader.BaseStream.Length - 1)
                {
                    byte[]          headerBytes = binaryReader.ReadBytes(Marshal.SizeOf(typeof(EnvPacketHeader)));
                    EnvPacketHeader header      = Tool.ByteToStruct <EnvPacketHeader>(headerBytes, 0, headerBytes.Length);
                    if (header.syncHeader.EqualBytes(EnvProtocol.SyncHeader) && header.dataType == (byte)EnvProtocol.DataType.DataTypeFast)
                    {
                        byte[]     buffer = binaryReader.ReadBytes(Marshal.SizeOf(typeof(FastPacket)));
                        FastPacket packet;
                        if (FastParser.Parse(buffer, out packet))
                        {
                            packetList.Add(packet);
                        }
                    }
                }
            }
            return(packetList);
        }
        public void TestFitFile()
        {
            using (var stream = System.IO.File.OpenRead(@"TestData\large_file.fit"))
            {
                var fastParser            = new FastParser(stream);
                var listOfRecordTypesSeen = new List <ushort>();

                foreach (var dataRecord in fastParser.GetMessages())
                {
                    ushort messageNumber = dataRecord.GlobalMessageNumber;
                    if (!listOfRecordTypesSeen.Contains(messageNumber))
                    {
                        MessageDecl messageDef;
                        if (GlobalMessageDecls.Declarations.TryGetValue(messageNumber, out messageDef))
                        {
                            Console.WriteLine("Record type: {0}", GlobalMessageDecls.Declarations[messageNumber].MessageName);
                            DumpFieldsOfKnownRecord(messageDef, dataRecord.MessageDefinition.FieldDefinitions);
                        }
                        else
                        {
                            Console.WriteLine("Record type: {0}", messageNumber);
                            DumpFieldsOfUnknownRecord(dataRecord.MessageDefinition.FieldDefinitions);
                        }
                        foreach (var field in dataRecord.MessageDefinition.FieldDefinitions)
                        {
                        }
                        listOfRecordTypesSeen.Add(messageNumber);
                    }
                }
            }
        }
        public void TestReadLargeFileIntoInternalDataStructures()
        {
            using (var stream = System.IO.File.OpenRead(@"TestData\large_file.fit"))
            {
                var fastParser = new FastParser(stream);

                var records = new List <DataSeriesRecord>();
                foreach (var dataRecord in fastParser.GetMessages())
                {
                    if (dataRecord.GlobalMessageNumber == GlobalMessageDecls.Record)
                    {
                        var record = new DataSeriesRecord();

                        double          latitude, longitude, cadence, heartRate, power, distance, speed;
                        System.DateTime timeStamp;

                        if (dataRecord.TryGetField(RecordDef.TimeStamp, out timeStamp))
                        {
                            record.TimeStamp = timeStamp;
                        }
                        if (dataRecord.TryGetField(RecordDef.PositionLat, out latitude))
                        {
                            record.Latitude = latitude * SEMICIRCLES_TO_DEGREES;
                        }
                        if (dataRecord.TryGetField(RecordDef.PositionLong, out longitude))
                        {
                            record.Longitude = longitude * SEMICIRCLES_TO_DEGREES;
                        }
                        if (dataRecord.TryGetField(RecordDef.HeartRate, out heartRate))
                        {
                            record.HeartRate = heartRate; // beats * min-1
                        }
                        if (dataRecord.TryGetField(RecordDef.Cadence, out cadence))
                        {
                            record.Cadence = cadence; // s-1
                        }
                        if (dataRecord.TryGetField(RecordDef.Power, out power))
                        {
                            record.Power = power; // W
                        }
                        if (dataRecord.TryGetField(RecordDef.Distance, out distance))
                        {
                            record.Distance = distance / 1000; // m
                        }
                        if (dataRecord.TryGetField(RecordDef.Speed, out speed))
                        {
                            record.Speed = speed / 1000; // m/s
                        }

                        records.Add(record);
                    }
                }
                Console.WriteLine("Read {0} timestamp values", records.Count);
            }
        }
        public void ReadFitFileWithoutHrData()
        {
            using (var stream = System.IO.File.OpenRead(@"TestData\no_hr_data.fit"))
            {
                var fastParser = new FastParser(stream);
                Assert.IsTrue(fastParser.IsFileValid());

                foreach (var dataRecord in fastParser.GetMessages())
                {
                    if (dataRecord.GlobalMessageNumber == GlobalMessageDecls.Record)
                    {
                        double heartRate;
                        if (dataRecord.TryGetField(RecordDef.HeartRate, out heartRate))
                        {
                            Assert.IsTrue(false);
                        }
                    }
                }
            }
        }
        public void TestReadLargeFile()
        {
            using (var stream = System.IO.File.OpenRead(@"TestData\large_file.fit"))
            {
                var fastParser = new FastParser(stream);

                var    recordCount = 0;
                double heartRate = 0, currentHeartRate;
                double cadence = 0, currentCadence;
                double power = 0, currentPower;

                foreach (var dataRecord in fastParser.GetMessages())
                {
                    if (dataRecord.GlobalMessageNumber == GlobalMessageDecls.Record)
                    {
                        if (dataRecord.TryGetField(RecordDef.HeartRate, out currentHeartRate))
                        {
                            heartRate += currentHeartRate;
                        }
                        if (dataRecord.TryGetField(RecordDef.Cadence, out currentCadence))
                        {
                            cadence += currentCadence;
                        }
                        if (dataRecord.TryGetField(RecordDef.Power, out currentPower))
                        {
                            power += currentPower;
                        }
                        recordCount++;
                    }
                }
                Console.WriteLine("Read {0} records, average HR = {1}, average Cadence = {2}, average Power = {3}", recordCount,
                                  heartRate / (double)recordCount,
                                  cadence / (double)recordCount,
                                  power / (double)recordCount);
            }
        }
Example #8
0
        /// <summary>
        /// Parses  a .fit file and retrieves the data
        /// parses using FastFitParser
        /// </summary>
        public RunData ParseFastFit(FileStream fitFile)
        {
            RunData rtn = null;
            //init parser and list of temp files
            FastParser parser = new FastParser(fitFile);

            if (parser.IsFileValid())
            {
                //init fields for data
                Double  tD  = 0;
                Double  aS  = 0;
                Double  aC  = 0;
                Double  aHR = 0;
                Boolean sR  = false;

                //go through DataRecord and retrieve relevant data
                foreach (DataRecord d in parser.GetDataRecords())
                {
                    if (d.GlobalMessageNumber == GlobalMessageDecls.Record)
                    {
                        if (d.TryGetField(RecordDef.Distance, out Double distance))
                        {
                            if (distance > tD)
                            {
                                tD = distance;
                            }
                        }
                        if (d.TryGetField(RecordDef.Speed, out double speed))
                        {
                            aS += speed;
                        }
                        if (d.TryGetField(RecordDef.Cadence, out double cadence))
                        {
                            aC += cadence;
                        }
                        if (d.TryGetField(RecordDef.HeartRate, out double heartRate))
                        {
                            aHR = heartRate;
                        }
                        //after first run through start finding the average of the data
                        if (sR)
                        {
                            aS  = Math.Round(aS / 2, 2);
                            aC  = Math.Round(aC / 2, 2);
                            aHR = Math.Round(aHR / 2, 2);
                        }
                        else
                        {
                            sR = true;
                        }
                    }
                }
                //convert speed and distance to meters and write to Debug.
                aS = Math.Round(aS / 1000, 2);
                tD = Math.Round(tD / 1000, 2);;
                Debug.WriteLine("Distance: " + tD + " m");
                Debug.WriteLine("Speed: " + aS + " m/s");
                Debug.WriteLine("Cadence: " + aC);
                Debug.WriteLine("Heart Rate: " + aHR);


                rtn             = new RunData();
                rtn.DistanceRan = tD;
                rtn.RunSpeed    = aS;
                rtn.Cadence     = aC;
                rtn.HeartRate   = aHR;



                Console.WriteLine("Distance: " + tD + " m");
                Console.WriteLine("Speed: " + aS + " m/s");
                Console.WriteLine("Cadence: " + aC);
                Console.WriteLine("Heart Rate: " + aHR);
                fitFile.Close();
            }
            return(rtn);
        }
Example #9
0
        private void ParseData(byte[] buffer)
        {
            if (buffer.Length <= Marshal.SizeOf(typeof(EnvPacketHeader)))
            {
                return;
            }
            EnvPacketHeader header = Tool.ByteToStruct <EnvPacketHeader>(buffer, 0, Marshal.SizeOf(typeof(EnvPacketHeader)));

            if (!Enumerable.SequenceEqual(header.syncHeader, EnvProtocol.SyncHeader))
            {
                return;
            }
            byte[] body = new byte[buffer.Length - Marshal.SizeOf(typeof(EnvPacketHeader))];
            Array.Copy(buffer, Marshal.SizeOf(typeof(EnvPacketHeader)), body, 0, body.Length);
            switch ((EnvProtocol.DataType)header.dataType)
            {
            case EnvProtocol.DataType.DataTypeSlow:
                SlowPacket slowPacket;
                if (SlowParser.Parse(body, out slowPacket))
                {
                    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SlowPacket)));
                    Marshal.StructureToPtr(slowPacket, ptr, true);
                    WinApi.PostMessage(mainWindowHandle, WinApi.WM_SLOW_DATA, 0, ptr);
                }
                else
                {
                    WinApi.PostMessage(mainWindowHandle, WinApi.WM_SLOW_DATA, 0, IntPtr.Zero);
                }
                if (IsStartLogData)
                {
                    dataLogger.WriteSlowPacket(buffer);
                }
                break;

            case EnvProtocol.DataType.DataTypeFast:
                FastPacket fastPacket;
                if (FastParser.Parse(body, out fastPacket))
                {
                    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FastPacket)));
                    Marshal.StructureToPtr(fastPacket, ptr, true);
                    WinApi.PostMessage(mainWindowHandle, WinApi.WM_FAST_DATA, 0, ptr);
                }
                else
                {
                    WinApi.PostMessage(mainWindowHandle, WinApi.WM_FAST_DATA, 0, IntPtr.Zero);
                }
                if (IsStartLogData)
                {
                    dataLogger.WriteFastPacket(buffer);
                }
                break;

            case EnvProtocol.DataType.DataTypeTail:
                List <TailPacketRs> tailPacketRs = tailParser.Parse(body);
                if (tailPacketRs.Count > 0)
                {
                    foreach (TailPacketRs packet in tailPacketRs)
                    {
                        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TailPacketRs)));
                        Marshal.StructureToPtr(packet, ptr, true);
                        WinApi.PostMessage(mainWindowHandle, WinApi.WM_TAIL_DATA, 0, ptr);
                    }
                }
                else
                {
                    WinApi.PostMessage(mainWindowHandle, WinApi.WM_TAIL_DATA, 0, IntPtr.Zero);
                }
                if (IsStartLogData)
                {
                    dataLogger.WriteTailPacket(buffer);
                }
                break;

            default:
                break;
            }
        }
Example #10
0
        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);
        }
Example #11
0
        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]);
                            }
                        }
                    }
                }
            }
        }
Example #12
0
        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);
        }