Giter VIP home page Giter VIP logo

php-fit-file-analysis's Introduction

Build Status Packagist Packagist Coverage Status

phpFITFileAnalysis

A PHP (>= v5.4) class for analysing FIT files created by Garmin GPS devices.

Live demonstration (Right-click and Open in new tab)

Demo Screenshots

Mountain Biking Power Analysis Quadrant Analysis Swim

Please read this page in its entirety and the FAQ first if you have any questions or need support.

What is a FIT file?

FIT or Flexible and Interoperable Data Transfer is a file format used for GPS tracks and routes. It is used by newer Garmin fitness GPS devices, including the Edge and Forerunner series, which are popular with cyclists and runners.

Visit the FAQ page within the Wiki for more information.

How do I use phpFITFileAnalysis with my PHP-driven website?

A couple of choices here:

The more modern way: Add the package adriangibbons/php-fit-file-analysis in a composer.json file:

{
    "require": {
        "adriangibbons/php-fit-file-analysis": "^3.2.0"
    }
}

Run composer update from the command line.

The composer.json file should autoload the phpFITFileAnalysis class, so as long as you include the autoload file in your PHP file, you should be able to instantiate the class with:

<?php
    require __DIR__ . '/vendor/autoload.php';  // this file is in the project's root folder
    $pFFA = new adriangibbons\phpFITFileAnalysis('fit_files/my_fit_file.fit');
?>

The more manual way: Download the ZIP from GitHub and put PHP class file from the /src directory somewhere appropriate (e.g. classes/). A conscious effort has been made to keep everything in a single file.

Then include the file on the PHP page where you want to use it and instantiate an object of the class:

<?php
    include('classes/phpFITFileAnalysis.php');
    $pFFA = new adriangibbons\phpFITFileAnalysis('fit_files/my_fit_file.fit');
?>

Note that the only mandatory parameter required when creating an instance is the path to the FIT file that you want to load.

There are more Optional Parameters that can be supplied. These are described in more detail further down this page.

The object will automatically load the FIT file and iterate through its contents. It will store any data it finds in arrays, which are accessible via the public data variable.

Accessing the Data

Data read by the class are stored in associative arrays, which are accessible via the public data variable:

$pFFA->data_mesgs

The array indexes are the names of the messages and fields that they contain. For example:

// Contains an array of all heart_rate data read from the file, indexed by timestamp
$pFFA->data_mesgs['record']['heart_rate']
// Contains an integer identifying the number of laps
$pFFA->data_mesgs['session']['num_laps']

OK, but how do I know what messages and fields are in my file? You could either iterate through the $pFFA->data_mesgs array, or take a look at the debug information you can dump to a webpage:

// Option 1. Iterate through the $pFFA->data_mesgs array
foreach ($pFFA->data_mesgs as $mesg_key => $mesg) {  // Iterate the array and output the messages
    echo "<strong>Found Message: $mesg_key</strong><br>";
    foreach ($mesg as $field_key => $field) {  // Iterate each message and output the fields
        echo " - Found Field: $mesg_key -> $field_key<br>";
    }
    echo "<br>";
}

// Option 2. Show the debug information
$pFFA->showDebugInfo();  // Quite a lot of info...

How about some real-world examples?

// Get Max and Avg Speed
echo "Maximum Speed: ".max($pFFA->data_mesgs['record']['speed'])."<br>";
echo "Average Speed: ".( array_sum($pFFA->data_mesgs['record']['speed']) / count($pFFA->data_mesgs['record']['speed']) )."<br>";

// Put HR data into a JavaScript array for use in a Chart
echo "var chartData = [";
    foreach ($pFFA->data_mesgs['record']['heart_rate'] as $timestamp => $hr_value) {
        echo "[$timestamp,$hr_value],";
    }
echo "];";

Enumerated Data The FIT protocol makes use of enumerated data types. Where these values have been identified in the FIT SDK, they have been included in the class as a private variable: $enum_data.

A public function is available, which will return the enumerated value for a given message type. For example:

// Access data stored within the private class variable $enum_data
// $pFFA->enumData($type, $value)
// e.g.
echo $pFFA->enumData('sport', 2));  // returns 'cycling'
echo $pFFA->enumData('manufacturer', $this->data_mesgs['device_info']['manufacturer']);  // returns 'Garmin';
echo $pFFA->manufacturer();  // Short-hand for above

In addition, public functions provide a short-hand way to access commonly used enumerated data:

  • manufacturer()
  • product()
  • sport()

Optional Parameters

There are five optional parameters that can be passed as an associative array when the phpFITFileAnalysis object is instantiated. These are:

  • fix_data
  • data_every_second
  • units
  • pace
  • garmin_timestamps
  • overwrite_with_dev_data

For example:

$options = [
    'fix_data'                => ['cadence', 'distance'],
    'data_every_second'       => true
    'units'                   => 'statute',
    'pace'                    => true,
    'garmin_timestamps'       => true,
    'overwrite_with_dev_data' => false
];
$pFFA = new adriangibbons\phpFITFileAnalysis('my_fit_file.fit', $options);

The optional parameters are described in more detail below.

"Fix" the Data

FIT files have been observed where some data points are missing for one sensor (e.g. cadence/foot pod), where information has been collected for other sensors (e.g. heart rate) at the same instant. The cause is unknown and typically only a relatively small number of data points are missing. Fixing the issue is probably unnecessary, as each datum is indexed using a timestamp. However, it may be important for your project to have the exact same number of data points for each type of data.

Recognised values: 'all', 'cadence', 'distance', 'heart_rate', 'lat_lon', 'power', 'speed'

**Examples: **

$options = ['fix_data' => ['all']];  // fix cadence, distance, heart_rate, lat_lon, power, and speed data
$options = ['fix_data' => ['cadence', 'distance']];  // fix cadence and distance data only
$options = ['fix_data' => ['lat_lon']];  // fix position data only

If the fix_data array is not supplied, then no "fixing" of the data is performed.

A FIT file might contain the following:

# Data Points Delta (c.f. Timestamps)
timestamp102510
position_lat1023625
position_long1023625
altitude102510
heart_rate102510
cadence9716535
distance1023625
speed1023625
power102429
temperature102510

As illustrated above, the types of data most susceptible to missing data points are: position_lat, position_long, altitude, heart_rate, cadence, distance, speed, and power.

With the exception of cadence information, missing data points are "fixed" by inserting interpolated values.

For cadence, zeroes are inserted as it is thought that it is likely no data has been collected due to a lack of movement at that point in time.

Interpolation of missing data points

// Do not use code, just for demonstration purposes
var_dump($pFFA->data_mesgs['record']['temperature']);  // ['100'=>22, '101'=>22, '102'=>23, '103'=>23, '104'=>23];
var_dump($pFFA->data_mesgs['record']['distance']);  // ['100'=>3.62, '101'=>4.01, '104'=>10.88];

As you can see from the trivial example above, temperature data have been recorded for each of five timestamps (100, 101, 102, 103, and 104). However, distance information has not been recorded for timestamps 102 and 103.

If fix_data includes 'distance', then the class will attempt to insert data into the distance array with the indexes 102 and 103. Values are determined using a linear interpolation between indexes 101(4.01) and 104(10.88).

The result would be:

var_dump($pFFA->data_mesgs['record']['distance']);  // ['100'=>3.62, '101'=>4.01, '102'=>6.30, '103'=>8.59, '104'=>10.88];

Data Every Second

Some of Garmin's Fitness devices offer the choice of Smart Recording or Every Second Recording.

Smart Recording records key points where the fitness device changes direction, speed, heart rate or elevation. This recording type records less track points and will potentially have gaps between timestamps of greater than one second.

You can force timestamps to be regular one second intervals by setting the option:

$options = ['data_every_second' => true];

Missing timestamps will have data interpolated as per the fix_data option above.

If the fix_data option is not specified in conjunction with data_every_second then 'fix_data' => ['all'] is assumed.

Note that you may experience degraded performance using the fix_data option. Improving the performance will be explored - it is likely the interpolateMissingData() function is sub-optimal.

Set Units

By default, metric units (identified in the table below) are assumed.

Metric
(DEFAULT)
Statute Raw
Speedkilometers per hourmiles per hourmeters per second
Distancekilometersmilesmeters
Altitudemetersfeetmeters
Latitudedegreesdegreessemicircles
Longitudedegreesdegreessemicircles
Temperaturecelsius (℃)fahrenheit (℉)celsius (℃)

You can request statute or raw units instead of metric. Raw units are those were used by the device that created the FIT file and are native to the FIT standard (i.e. no transformation of values read from the file will occur).

To select the units you require, use one of the following:

$options = ['units' => 'statute'];
$options = ['units' => 'raw'];
$options = ['units' => 'metric'];  // explicit but not necessary, same as default

Pace

If required by the user, pace can be provided instead of speed. Depending on the units requested, pace will either be in minutes per kilometre (min/km) for metric units; or minutes per mile (min/mi) for statute.

To select pace, use the following option:

$options = ['pace' => true];

Pace values will be decimal minutes. To get the seconds, you may wish to do something like:

foreach ($pFFA->data_mesgs['record']['speed'] as $key => $value) {
    $min = floor($value);
    $sec = round(60 * ($value - $min));
    echo "pace: $min min $sec sec<br>";
}

Note that if 'raw' units are requested then this parameter has no effect on the speed data, as it is left untouched from what was read-in from the file.

Timestamps

Unix time is the number of seconds since UTC 00:00:00 Jan 01 1970, however the FIT standard specifies that timestamps (i.e. fields of type date_time and local_date_time) represent seconds since UTC 00:00:00 Dec 31 1989.

The difference (in seconds) between FIT and Unix timestamps is 631,065,600:

$date_FIT = new DateTime('1989-12-31 00:00:00', new DateTimeZone('UTC'));
$date_UNIX = new DateTime('1970-01-01 00:00:00', new DateTimeZone('UTC'));
$diff = $date_FIT->getTimestamp() - $date_UNIX->getTimestamp();
echo 'The difference (in seconds) between FIT and Unix timestamps is '. number_format($diff);

By default, fields of type date_time and local_date_time read from FIT files will have this delta added to them so that they can be treated as Unix time. If the FIT timestamp is required, the 'garmin_timestamps' option can be set to true.

Overwrite with Developer Data

The FIT standard allows developers to define the meaning of data without requiring changes to the FIT profile being used. They may define data that is already incorporated in the standard - e.g. HR, cadence, power, etc. By default, if developers do this, the data will overwrite anything in the regular $pFFA->data_mesgs['record'] array. If you do not want this occur, set the 'overwrite_with_dev_data' option to false. The data will still be available in $pFFA->data_mesgs['developer_data'].

Analysis

The following functions return arrays of data that could be used to create tables/charts:

array $pFFA->hrPartionedHRmaximum(int $hr_maximum);
array $pFFA->hrPartionedHRreserve(int $hr_resting, int $hr_maximum);
array $pFFA->powerPartioned(int $functional_threshold_power);
array $pFFA->powerHistogram(int $bucket_width = 25);

For advanced control over these functions, or use with other sensor data (e.g. cadence or speed), use the underlying functions:

array $pFFA->partitionData(string $record_field='', $thresholds=null, bool $percentages = true, bool $labels_for_keys = true);
array $pFFA->histogram(int $bucket_width=25, string $record_field='');

Functions exist to determine thresholds based on percentages of user-supplied data:

array $pFFA->hrZonesMax(int $hr_maximum, array $percentages_array=[0.60, 0.75, 0.85, 0.95]);
array $pFFA->hrZonesReserve(int $hr_resting, int $hr_maximum, array $percentages_array=[0.60, 0.65, 0.75, 0.82, 0.89, 0.94 ]) {
array $pFFA->powerZones(int $functional_threshold_power, array $percentages_array=[0.55, 0.75, 0.90, 1.05, 1.20, 1.50]);

Heart Rate

A function exists for analysing heart rate data:

// hr_FT is heart rate at Functional Threshold, or Lactate Threshold Heart Rate
array $pFFA->hrMetrics(int $hr_resting, int $hr_maximum, string $hr_FT, $gender);
// e.g. $pFFA->hrMetrics(52, 189, 172, 'male');

Heart Rate metrics:

  • TRIMP (TRaining IMPulse)
  • Intensity Factor

Power

Three functions exist for analysing power data:

array $pFFA->powerMetrics(int $functional_threshold_power);
array $pFFA->criticalPower(int or array $time_periods);  // e.g. 300 or [600, 900]
array $pFFA->quadrantAnalysis(float $crank_length, int $ftp, int $selected_cadence = 90, bool $use_timestamps = false);  // Crank length in metres

Power metrics:

  • Average Power
  • Kilojoules
  • Normalised Power (estimate had your power output been constant)
  • Variability Index (ratio of Normalised Power / Average Power)
  • Intensity Factor (ratio of Normalised Power / Functional Threshold Power)
  • Training Stress Score (effort based on relative intensity and duration)

Critical Power (or Best Effort) is the highest average power sustained for a specified period of time within the activity. You can supply a single time period (in seconds), or an array or time periods.

Quadrant Analysis provides insight into the neuromuscular demands of a bike ride through comparing pedal velocity with force by looking at cadence and power.

Note that $pFFA->criticalPower and some power metrics (Normalised Power, Variability Index, Intensity Factor, Training Stress Score) will use the PHP Trader extension if it is loaded on the server. If the extension is not loaded then it will use the built-in Simple Moving Average algorithm, which is far less performant particularly for larger files!

A demo of power analysis is available here.

Other methods

Returns array of booleans using timestamp as key. true == timer paused (e.g. autopause):

array isPaused()

Returns a JSON object with requested ride data:

array getJSON(float $crank_length = null, int $ftp = null, array $data_required = ['all'], int $selected_cadence = 90)
/**
 * $data_required can be ['all'] or a combination of:
 * ['timestamp', 'paused', 'temperature', 'lap', 'position_lat', 'position_long', 'distance', 'altitude', 'speed', 'heart_rate', 'cadence', 'power', 'quadrant-analysis']
 */

Returns array of gear change information (if present, e.g. using Shimano D-Fly Wireless Di2 Transmitter):

// By default, time spent in a gear whilst the timer is paused (e.g. autopause) is ignored. Set to false to include.
array gearChanges($bIgnoreTimerPaused = true)

Acknowledgement

This class has been created using information available in a Software Development Kit (SDK) made available by ANT (thisisant.com).

As a minimum, I'd recommend reading the three PDFs included in the SDK:

  1. FIT File Types Description
  2. FIT SDK Introductory Guide
  3. Flexible & Interoperable Data Transfer (FIT) Protocol

Following these, the 'Profile.xls' spreadsheet and then the Java/C/C++ examples.

php-fit-file-analysis's People

Contributors

adriangibbons avatar alexfraundorf-com avatar konafets avatar rafaelnajera avatar roznet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

php-fit-file-analysis's Issues

Undefined offset: 25 in phpFITFileAnalysis.php on line 1228

1228: $this->types = $this->endianness[$architecture];

Undefined offset: 25 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228
Undefined offset: 139 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228
Undefined offset: 97 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228
Undefined offset: 113 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228
Undefined offset: 119 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228
Undefined offset: 109 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228
Undefined offset: 108 in vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 1228

Di2 D-Fly gear change data from Garmin Edge 1000

Thank you good script.Sir. very very good.
I have GARMIN EDGE1000 and shimano Di2 D-fly.
But I cant get Di2 gear change and gear info data on GARMIN EDGE 1000 RAW fit file.
Is this script cant yet?
I trust this script can it, But I dont understand pick up gear data method, thanks.
If you need gear data in fit file. please message me. I gonna send it.
RGDS.

getJSON function for laps or other fit sections

Is it possible to have new getJSON functions for other FIT sections? This function extracts only data from "record" section, but I need also an extractor for "lap" section.
Thank you so much for this helpful lib!

question: php fit 2 ways

It's great that your code analyse fit files.
is the opposite diretion possible: Is there a possibility to create fit files starting from some coordinates ?

question: chronological access to laps, events and records?

Hi

First, thanks for a truly useful project that is making me attempt an exercise database so much more doable.

Apologies, this is a question rather than an issue. Whilst most applications show lap splits, nothing really allows drilling down into what I term 'legs' i.e. portions of activity between pauses of the timer during a lap. I have a test file where the end of lap 2, the start of lap 3, and one location record all have the same UNIX timestamp and I'm not sure how to calculate which lap this record belongs to. Is it possible for me to iterate through all events (timer pauses), lap markers and location records together in chronological order so as to know which lap to assign a particular record to? Or perhaps access fractions of a second (assuming they exist) for each record?

Data every second

fixData() just ensures timestamp consistency, probably need a function to ensure data is in there for every second of recording...

Suunto Ambit Support

I'm trying to process a file that looks to be from a Suunto Ambit that I can view by uploading to https://www.fitfileviewer.com/ If I try to process using this library I get Undefined offset error @ $this->types = $this->endianness[$architecture];

$architecture is showing as 14. Obviously, the code expects zero or one. Any idea? Fit file attached.

68270818303.zip

incorrect speed values

Hi Adrian,
I am having a problem with speed values that I was hoping you could help me hunt down. I am getting a larger value for average speed than I am for max speed when I var_dump data_mesgs['lap'].
Below is what I am getting for those two sets. I have the fit file available here: https://www.dropbox.com/s/ep31ebzc7s1izu3/file.fit?dl=1
Thank you,
Alex

["avg_speed"]=>
array(8) {
[0]=> float(5.457)
[1]=> float(5.002)
[2]=> float(6.198)
[3]=> float(4.108)
[4]=> float(6.217)
[5]=> float(4.052)
[6]=> float(5.842)
[7]=> float(3.766)
}
["max_speed"]=>
array(8) {
[0]=> float(4.868)
[1]=> float(4.88)
[2]=> float(4.908)
[3]=> float(3.502)
[4]=> float(3.987)
[5]=> float(3.801)
[6]=> float(3.841)
[7]=> float(3.573)
}

pause or smart record

Hi,
How does the code separate between a Pause or just a Smart Record (sampling not every second)?

develop getJSON() function

Would be useful to get data in a JSON format e.g. for use in dc.js

{
    "fix_data": "all",
    "units": "metric",
    "pace": null,
    "data": [
        {
            "timestamp": 71234828,
            "lap": 1,
            "pos_latitude": 32.15,
            "pos_longitude": 115.24,
            "speed": 29.3,
            "altitude": 15,
            "cadence": 91,
            "heart_rate": 116,
            "power": 189,
            "chainring": 53,
            "sprocket": 19
        },
        {
            "timestamp": 71234832,
            "lap": 1,
            "pos_latitude": 32.16,
            "pos_longitude": 115.23,
            "speed": 28.1,
            "altitude": 15,
            "cadence": null,
            "heart_rate": 121,
            "power": 0,
            "chainring": 53,
            "sprocket": 18
        }
    ]
}

Could create the array structure in PHP and then use:

<?php json_encode(); ?>

data_mesgs['session'] is null

Hi, im testing your parser (great job) but i have a problem.

I have an issue with the parser. Unfortunatly, data_mesgs['session'] is null and i don't have any data.
data_mesgs['record'] is ok, full of data. the fit file is ok, is a bike workout (2 hours duration).
recorded using forerunner 935. i tested the fit in fitfileviewer.com and is ok.
do you know where is the problem?

thanks so much.

from fit file to mysql db

Hi Adrian,

I love your php class and use it for a personal project to show my cycling data.
Now I would like to put into mysql db all my fit files for a few years so I can create a custom reports and graph.

I would like to have your opinion on how to organize the mysql db tables.

Thanks.

Daniele

Device byte endianness is ignored

Hi Adrian,

Thanks for the recent fix. In addition to that issue, there is another problem I've been encountering with a specific FIT file. Unfortunately, I am still quite unfamiliar with the FIT spec and cannot pinpoint what the problem is during parsing. What I can tell you is that it gives the error:

Undefined index: record

And that it works in GoldenCheetah. I have uploaded the file to https://www.mediafire.com/?hgc99xr1oc5ic98

Thanks.

Forerunner10 missing altitude

Hi adriangibbons,
First, your fit file reader is great! Thanks for this.
However I have read a fit file created with Garmin Forerunner10 and the altitude information is missing. In my Garmin Connect account I can see the altitude. So I think that the altitude information is in the fit file.
I have also output the fild information - also no altitude exists. Could you check this issue please? Here is a downloadlink to my fit file: http://stephan.mein-sporttagebuch.de/userfiles/tempfiles/514B0111.FIT
Thank you very much in advance.
Kind regards,
Stephan

data_mesgs['record'] null

Hello Adrian :)

I have an issue with the parser. Unfortunatly, data_mesgs['record'] is null and i don't have any data.

This line seems to be the problem :
$this->file_header['data_size'] = $this->file_header['crc'] - $header_size + 2;

It's a session recorded with Garmin Forerunner 920XT.

Many thanks,

Multiple sessions

Hi,

for the first time Garmin (yesterday and today) has sent me a FIT with multiple sessions, that generate an error.

How to approach this?

Thanks a lot,
Franco

Invalid values

Raw values for lat and long of 2,147,483,647 resulting coordinates of 180,180 on the map.

Approx. 1% (24 of 2,368) data points affected from Forerunner 110.

staticmap

Wrong timestamp

When decoding a .fit file with your lib I don't get real timestamp.

From your lib : 1995-10-03
From Strava : 2015-10-01 (good one)
Timestamp : 812681141

Power, cadence, etc... are fine but I can't figure out why timestamp is wrong.

Do you have any clues ? I can send you the file if needed.

loadFromFile, loadFromData Suggestion...

I will suggest a litte change:

I have a REST api, that api have a method in order to import a FIT file. I am using this class after import, but, is imposible load RAW content. I need first write the content in a file and after that load with phpFITFileAnalysis.

Have sense a function like that?
loadFromFile($file_path, $options = null)
loadFromData($data, $options = null)

Garmin Product Information is incorrect

In the FIT files there are two fields "product" and "garmin_product" which are not interchangeable. Therefore, when pulling out the device information for Garmin devices some values that are returned are incorrect. The code does not distinguish between the "product" fields and the "garmin_product" fields in the FIT file. . I reached out to Garmin directly and they noted that "product" has something to do with Garmin Connect and does not reference the product list from the FIT SDK. I had thought I could simply line up the manufacturer array ( with "1" representing Garmin manufacturer), but this doesn't work either. I'll illustrate with an example. If I run the code on a FIT file I will get a ['device_info]['product] array with 8 entries. However, I will get a manufacturer array with only 7 entries. It seems some values of 'product' in the FIT file do not have a corresponding 'manufacturer' value (while all 'garmin_product" ones do). I manually went through the FIT file and pulled the values to illustrate this point:

manufacturer 1 garmin_product 2050
manufacturer 1 garmin_product 2050
product 558
manufacturer 1 garmin_product 1620
manufacturer 1 garmin_product 2050
manufacturer 1 garmin_product 2050
manufacturer 1 garmin_product 1620
manufacturer 25165 product 3

note no manufacturer for 'product' 558.

Therefore without knowing which values in the ['device_info']['product'] array correspond to 'product' or 'garmin_product' it is impossible as far as I can tell to line these arrays up.

Therefore, $this->data_mesgs['device_info']['product'] should NOT contain values pulled from the "product" field. Is there some small change to the code that can be made to only pull the "garmin_product" field and ignore the "product" field?

Problem with some latitude fields?

The first entries for position_lat and position_long in one of my FIT files are [1539031114] => -40.64575 and [1539031114] => 175.29212. Yes, I'm in New Zealand!

However, I have lap[start_position_lat] => 220.64569, lap[start_position_long] => 175.29196, lap[end_position_lat] => 220.86769, and lap[end_position_long] => 175.06788, and session[start_position_lat] => 220.64569, session[start_position_long] => 175.29196.

It looks as though the conversion for these lap[] and session[] fields isn't working correctly for negative latitudes. I need to subtract the lat values from 180 to get the correct -ve value. The conversion obviously works OK for the position_lat values.

Can anybody point to me to where this needs to be fixed (in function readDataRecords()) please??

Of course it may be my device, Lezyne Mega XL, but I also see the same problem with FIT files from a friend's device from a completely different manufacturer.

Thanks.

Fjeldfross

FatalErrorException: Unsupported operand types

Getting the following error when using the attached FIT file with HR:
_(1/1) FatalErrorExceptionUnsupported operand types
in phpFITFileAnalysis.php (line 2713)

Using the latest master version - looks like $last_event_timestamp is an array of 2 elements rather than the expected integer but not sure how you match the correct version to use..

error3.txt
Tried uploading to garmin connect and FIT file is working ok.

PHP script uses a lot of memory

The process of reading in the file: file_get_contents(), followed by str_split() and then array_reverse() uses a lot of memory and without memory_limit in php.ini set to a suitable value then _Fatal Error: Allowed Memory Size of xxxxxx Bytes Exhausted_ may be experienced. Some users may not have access to change the memory_limit therefore alternatives should be investigated.

For example, reading a FIT file of 263kb:

before file_get_contents(): 524,288 bytes
after file_get_contents(): 1,048,576 bytes
after str_split(): 28,835,840 bytes
after array_reverse(): 44,040,192 bytes (~44mb!)
(using memory_get_peak_usage(true) to return the peak of memory allocated by PHP.)

By the end of the script, approximately 78mb (peak) was used.

One possible solution would be to use substr() on the string read by file_get_contents() instead of splitting the string into an array, reversing it, and using array_pop().

Matching up indexes when some values missing

Great library.

How do you go about matching up the indexes when some are missing?
See attatched - its for the 'lap' element from a swim.
Some of the 'total_distance' elements are 0 (resting period) but this means the indexes are missing from 'swim_stroke' making it pretty hard to match up the corresponding distance and stroke. Is this is a bug or is that the way the data comes through? I looked at the 'fix data' option but it only works for certain elements.

screen shot 2016-12-20 at 15 00 55

Class does not support Compressed Timestamp Headers

If anyone receives:

phpFITFileAnalysis->readDataRecords(): this class can only handle normal headers!

Please share an example FIT file and I'll use this for testing the handling of these timestamps. I'd be flying blind without a file to work so I'm not developing this until someone experiences the Exception above being thrown!

Adrian.

Not able to access the file from s3

I am storing Garmin files into a s3 bucket. But when I try to fetch the file from s3 it is displaying file not found. This is the error which I am getting
phpFITFileAnalysis->__construct(): file 'https://s3-us-west-2.amazonaws.com/uploadedimg/garmin_upload/6465920425' does not exist! in [project_root]/vendor/adriangibbons/php-fit-file-analysis/src/phpFITFileAnalysis.php on line 944

Here is the code provided in my controller

$filepath = 'https://s3-us-west-2.amazonaws.com/uploadedimg/garmin_upload/6465920425';
$options = ['units' => 'statute'];
$pFFA = new \adriangibbons\phpFITFileAnalysis($filespath,$options);
$grCnt = $pFFA->data_mesgs['session'];

Error: phpFITFileAnalysis->readHeader(): file_header['data_size'] does not seem correct!

Hi again,

Run into the above error with a FIT file from a brand new Garmin Forerunner 395 watch. If you comment out the line that throws the error it will parse it but some information is missing.

Ie Record->heart_rate is not present (but it is present in the lap array). This information is definitely in the file as if you upload it to Garmin connect its shown.

This watch seems to have been added between FIT SDK versions 20.16 and 20.30 (latest) somewhere. Not sure if its stored in a different field in the fit file (as this watch uses a different way of capturing heart rate I belive)

1627845922.txt

Add ATL, CTL and TSB to Power Analysis

New public function to take TSS's as input and return:

  • Acute Training Load (Fatigue)
  • Chronic Training Load (Fitness)
  • Training Stress Balance (Form)

E.g. getFatigueFitnessForm($tss_values, $ctl_time_period = 84days, $atl_time_period = 14days)

Class does not support Developer Data

When importing a garmin 820 fit file it errors with "this class can only handle normal headers":

if (($record_header_byte >> 7) & 1) { // Check that it's a normal header
throw new \Exception('phpFITFileAnalysis->readDataRecords(): this class can only handle normal headers!');
}

Anyone has updated code?

Included a copy of the problem fit file.

niels probleem 820 2016-09-07-05-49-08.zip

Regards,
Henk

phpFITFileAnalysis doesn't work with my website any more

I've just made some non-backward compatible changes and bumped the versioning to v3.0.*

I've updated the README - hopefully I haven't missed anything. PSR-4 autoloading to come...

The project now has its own namespace and is starting to be more PSR-2 code styling compliant! E.g. method names are now camelCase - power_metrics() has become powerMetrics() etc.

It's also available on packagist.org too, for easier updating. Just add to your project's composer.json file:

{
    "require": {
        "adriangibbons/php-fit-file-analysis": "3.0.*"
    }
}

example for leaflet js

Hi,

is there also a "mountain-biking.php" example using the OpenStreetMap services with leaflet.js instead of Google maps?

Regards

Precision rounding of fields

Forgive me if this is overly simplistic, however, I'm new to Github and not familiar with the way things typically work. This is more of a feature request...

The rounding of units is restrictive in some cases. For example, distance fields are rounded to 2 decimal places. In many cases, due to the restriction, the maximum data resolution is greater than the maximum GPS error at 95% confidence level. I would kindly suggest considering 3 place precision on distance fields, or perhaps a config option to allow the developer a little more flexibility.

I can edit my files to do what I need, but of course, I would prefer not to create my own custom branch of the code.

Thank you for your work on this useful resource, Adrian.

Cheers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.