Newbie: How to dump raw FIT data to text (not FitToCSV.bat)

Is there a tool in the FIT SDK that simply dumps the "raw" FIT data to a text file (XML or CSV) without interpretation (calculation)?

(Although I would appreciate the __addition__ of the distance and altitude calculated to 17 significant digits, because I don't know how to do that from the GPS coordinates.)

If there is such a tool, how can I create a drag-and-drop interface like FitToCSV.bat?

The FitToCSV.bat does not do that (!).

Instead, the CSV file has some calculated fields that are inconsistent and imprecise (albeit probably precise enough).

I want to see the raw FIT data in order to hopefully resolve the inconsistencies -- or to learn that they are inherent in the FIT protocol itself (sigh).

  • Hi km408,

    'number' values, containing 17 digits looks funny at first, but:

    Garmin stores all latitude and longitude values as 32-bit integer values.
    This unit is called semicircle.
    So that gives 2^32 possible values.
    And to represent values up to 360° (or -180° to 180°), each 'degree' represents 2^32 / 360 = 11930465.
    So dividing latitude and longitude (int32) value by 11930465 will give the decimal value.

    Example:
    Stored semicircle latitude value is 373473280.
    Divided by 11930465 gives 31.30416794 => N31.30417.

    On the other hand, distance and altitude values are stored as float values.

    I'm using  FIT SDK for several years to create my 'own' FIT reader and writer, depending on fit type (Activity, Locations, Totals, ... from and for a Garmin Edge 1000), but I have no idea, how to implement such a simple and universal program to dump 'raw' FIT data Frowning2

    Why:

    Inside a fit file informations are stored as messages and each message can contains different values, depending on the message type.

    A record message, contains information about ONE (1!) geo point and can contains a Timestamp, PositionLat, PositionLong, Altitude, HeartRate, Cadence, Distance, Speed, Power, ...
    At the moment up to 74 different values in different units.

    So for each value you need a corresponding function to get 'raw' data (C# example):

    ///<summary>
    /// Retrieves the PositionLat field
    /// Units: semicircles</summary>
    /// <returns>Returns nullable int representing the PositionLat field</returns>
    public int? GetPositionLat()
    {
    Object val = GetFieldValue(0, 0, Fit.SubfieldIndexMainField);
    if(val == null)
    {
    return null;
    }

    return (Convert.ToInt32(val));

    }

    Hope this helps.

    Best regards

    Roland

  • Most values in a FIT file are stored as unsigned integers, either 8, 16, or 32 bits depending on the required precision. The FIT Profile includes a scale and offset for each field that is used to convert the unsigned integer values to/from float point values. The FIT CSV Tool converts the unsigned integers read from the file to floats using the scale and offset in the profile. The FIT CSV Tool does not manipulate the data otherwise. The Profile.xlsx file that comes with the SDK lists the data type, scale, and offset for each field. The Java, C# and C++ make the application of the scale and offset transparent, but if you are using the C SDK then you need to apply the scale and offsets manually.

    In the Record message, distance and altitude fields are stored as uint32 and uint16 (more recently uint32) respectively. This is to reduce file size by not storing more precision than needed. For the purposes of fitness devices, you do not need to store distance to anything less than centimeters. Using unsigned integers along with a scale, and sometimes and offset, is how this is accomplished.

    As an example, altitude values are stored as either uint16 or uint32 values. Originally it was uint16, but when people started to use fitness devices at higher altitudes it was changed to a uint32. In both cases an offset of 500 and a scale of 5 is used to convert the unsigned integer values to/from floats.

    A concrete example, the lowest point in Death Valley is around -86.01456 meters. To convert that to a uint16 you add the offset, multiply by the scale, cast to a uint16, and store that value in the file.

    i.e. (-86.01456m + 500) * 5 = 2069

    Then to convert back to a float you apply the scale and offset in revers.

    2069 / 5 – 500 = 86.2m

    The 5 and -500 allow you to store elevation values from Death Valley to the top of Mt Everest with 20cm resolution using a uint16. When altitude is stored as a uint32, it is still 20cm resolution, but you can go higher.

    The distance field has an offset of zero and a scale of 100, which gives you 1cm resolution.

    For lat/long values the semicircle unit is used. A semicircle is a signed int32 which has a range of +/- 2^31 [-2,147,483,648 to 2,147,483,647] which gives you 2^32 values [4,294,967,296]. The circumference of the Earth at the equator is 4,007,500,000cm, which makes 1 semicircle is slightly less than 1cm.

    From the other commenter's example:
    Stored semicircle latitude value is 373473280.
    Divided by 11930465 gives 31.30416794

    Eight decimal places is about 1.11mm resolution.

  • Hi Ben FIT,

    thanks for the detailed information, how especially distance and altitude values with specific values ​​for scale and offset are implemented.

    Now I understand the line

    newMesg.SetField(new Field("Altitude", 2, 132, 5, 500, "m", false, Type.Uint16));

    inside Profile.cs => CreateRecordMesg()

    thanks and best regards.

    Roland

  • Thanks, Songokuonbike and Ben, for the tutorial information.  But that is not what I am looking for.  And I really do not need it.

    FYI, Ben, you wrote:  ``The FIT CSV Tool converts the unsigned integers read from the file to floats using the scale and offset in the profile. The FIT CSV Tool does not manipulate the data otherwise.``  So you are saying that the "calculated" values are in the FIT file itself, not calculated by the tool (except for some conversion).  That is interesting.  I'll look more closely at the so-called profiles (protocol).

    But there is indeed some "manipulation" going on.  I know this because the CSV file shows altitude, distance and speed with the precision of 1, 2 and 3 decimal places respectively, whereas the corresponding TCX file (downloaded from Garmin Connect) derived from the same FIT file shows those fields with 17 significant digits of precision.  In other words, at the very least, FitCSVTool.jar is rounding those fields to less precision than the data in the FIT file (or the calculations derived from that data).

    And Songokuonbike, I do not find the 17-sig-digit numbers "funny" or daunting.  That is simply the least precision for the decimal approximation that is sufficient to represent all 64-bit binary floating-point values without loss of precision when converting either direction between binary and decimal, according to the IEEE 754 specification (*).

    -----

    But we digress.  Again, what I am looking for is a turnkey program and BAT interface, if the FIT SDK provides it directly or indirectly (I do not accept ad hoc programs from third parties), that simply decodes the binary records into text form with any interpretation at all.

    As I noted, FitCSVTool.jar does not, in fact, do exactly that, at least not in all cases.  And I am hoping that there might be additional records or fields that FitCSVTool.jar is not converting.

    With nearly 30 years of experience in O/S development in C, I am more than qualified to decode the FIT file myself.  But having retired more than 15 years ago, my C language skills are rusty (and of course I would use C++ or C# now), I do not even have those compilers, and I never learned Java -- although I could now, since it came with the FIT SDK.  So it is no longer second nature for me.  Hence the desire for a turnkey solution.

    (The fact is:  I would limp along with Excel VBA to decode the binary file.  Disappointed )

    Again, I am trying to resolve some inconsistencies in the CSV file that I already have from FitToCSV.bat.

    Perhaps I'll present them in another thread.  I might get some answers here before I get a useful response from Garmin engineering (WIP).

    Thanks for taking an interest in my question.  But please try to stay on topic.

    -----
    (*) For example, whereas the exact decimal representation of the binary approximation of 2.345 is 2.34500000000000,0195399252334027551114559173583984375 (**), it is sufficient to write 2.34500000000000,02, the rounded 17-sig-digit approximation, because the next closest binary values (2.345 -/+ 2^-51) are 2.34499999999999,98 and 2.34500000000000,06 (rounded).  The latter values (and others) can be the result of calculations (e.g. 3 - 0.655), yet they all look like 2.345 when rounded to 15 significant digits, as Excel displays (but not "stores"; a common misstatement).  Consequently, in languages like Java, C variants and Excel VBA, 2.345 = 3 - 0.655 is false.

    This is what I do nowadays in my copious spare time:  explain to people why 10.1 - 10 = 0.1 is false (!).  Wink

    (**) I use period for the decimal point and comma to demarcate the first 15 significant digits.

  • The complier and other tools needed to work with the FIT C# SDK are free and available for Windows, OSX, and Linux. Same for Java. Take look at the instructions here to get started with the C# and the example decode recipe.
    developer.garmin.com/.../

    The source of truth are the raw values read from the original FIT file without the scale and offset applied. These values are available using any of the SDKs as Songokuonbike pointed out.

    As for a pseudo explanation as to why there are extra sig-figs in the csv and TCX files…

    The starting altitude for my last activity, as stored in the original FIT file, was 11401. This value is stored in the file as a uint32 with a scale of 5 and an offset of 500.

    Applying the scale and offset in reverse, I get the following when using the Calculator app on my Mac.

    11401 / 5 – 500 = 1780.2

    Doing the division in my head, I would say that is correct. Plus, the 0.2 makes sense given that the scale of 5 gives a precision of 20cm which means the decimal component can only be one of five values [ 0, 0.2, 0.4, 0.6, 0.8].

    ~1780 is also what I expect given where I was. So, so far so good.

    Using the FIT CSV Tool to convert the file, the altitude value of the first record message is:

    1780.1999999999998

    Applying the same scale and offset to convert this value back to a uint32, again with the Calculator app on my Mac, I get back the original value stored in the FIT File.

    (1780.1999999999998 + 500) * 5 = 11401

    I am sure that there is a value that when converted back is off by -0.1 which means it will be off by 1 when cast to a uint32. I'll tell myself that is the exception and not the rule.

    The FIT CSV Tool is written in Java. I do not know the specifics on how the Java Virtual Machine deals with floating point arithmetic, but that more than likely explains the difference. I ran the tool on my Mac, so the difference has to be in the JVM since the same processor was used. I will assume that values in the exported TCX files have the same issue. Also keep in mind that when going from FIT to TCX that the many of the values go through a unit conversion, which means more division resulting in what appears to be extra precision that is the result of floating-point estimation.

    Differences in latitude and longitude values in the csv files and TCX files are a similar issue. In the FIT, and CSV files, coordinates are in semicircles, which is a signed int32 with no scale or offset. So, they are whole numbers and never more than 10 sig-figs. In TCX files coordinates are in decimal degrees. The formula for converting from semicircles to degrees is

    degrees = semicircles * (180 / 2^31)

    Let’s say we have a latitude value that is 1 semicircle. In degrees we get the following value which has 16x more sig-figs than the value stored in the FIT file; and 8 more sig-figs than is needed to represent 1.11mm of distance.

    1 * (180 / 2^31) = 0.000000083819032

     

     

     

     

  • Okay, what I hear Ben and Songokuonbike saying is:  there is no turnkey program in the FIT SDK that decodes the raw FIT data without interpretation; for example, the uint32 value for altitude instead of the calculated decimal value (*).  Instead, the SDK provides the tools for me to develop my own program, as I knew.  I was just hoping to avoid that, being lazy.

    Thanks.  LMK if I misunderstood.

    -----

    (*) I thought perhaps fit.jar is that turnkey program.  But I cannot find documentation on it, and I could not make it work the way that I expected (hoped).

    What is fit.jar, and how do we use it?

    If there is an explanation online, I would appreciate it if you simply directed me to the webpage.  TIA.

    -----

    I am well adept at 64-bit binary floating-point arithmetic, and I need no explanation.  But for posterity, I will correct myself briefly.

    First, I asserted that altitude is rounded to 1 decimal place in the CSV file.  But in fact, it is saved with 17-sig-digit precision in the CSV file.  I made the "rookie" mistake of opening the CSV file directly in Excel instead of importing the file and assigning the Text format to at least some columns, if not all.

    Second, for distance and speed, which are rounded to 2 and 3 decimal places in the CSV file, the "greater" precision in the TCX file is an illusion.  The 17-sig-digit precision is the result of calculating the rounded values with single-precision, then "converting" them to double-precision.

  • fit.jar is a library, like a dll or shared object, on its own it doesn't do anything. You add it as a dependency to your Java project. Although, most people probably add the FIT Java SDK source code directly to their projects rather pull in the jar or dll files. The reason being is that if you need/want to, you can step into the SDK code to see how things work. This is the same for any of the SDKs. 

    Each FIT SDK has a similar interface, so one is not harder than another to work with. It all depends on the language(s) that you want to work in. There are example projects in the SDK for each supported language to help bootstrap your project. In the Cookbook there are more complete example projects that provide solutions to common use-cases. The Cookbook recipes are written in C#, and there are instructions here on how to get up an running with them. developer.garmin.com/.../

  • Thanks, Ben.  It was a stab in the dark.

  • Your question is old but I wanted to add for anyone searching in the future there is a perl conversion tool that bypasses the Garmin SDK so it does a better job

    it's not updated anymore but still works with unknown values and unknown new devices

    download the master.zip from here (not the last release, the master build which is newer)

    https://github.com/mrihtar/Garmin-FIT/tree/master

    you need to install Perl for Windows

    you can make a drag-n-drop batch file like this

    @echo off
    
    setlocal EnableDelayedExpansion
    
    set APP_DIR=%~dp0
    set APP_NAME=fitdump.pl
    set APP_PATH="%APP_DIR%%APP_NAME%"
    
    set a=%*
    
    FOR %%b IN (!a!) DO (
       set c=%%b
       set c=!c:.fit=!   
       call perl %APP_PATH% -b %%b !c!     > !c!.TXT
    )
    pause