theprivateer/fit-file-analysis

该软件包的最新版本(dev-master)没有可用的许可信息。

用于分析由Garmin GPS设备创建的FIT文件的PHP类

dev-master 2023-10-09 11:28 UTC

This package is auto-updated.

Last update: 2024-09-09 13:27:27 UTC


README

最初从 https://github.com/adriangibbons/php-fit-file-analysis 分支,并根据自身边缘情况进行了调整

用于分析由Garmin GPS设备创建的FIT文件的PHP类(>= v5.4)。

实时演示(右键单击并在新标签页中打开)

演示截图

Mountain Biking Power Analysis Quadrant Analysis Swim

如果您有任何问题或需要支持,请首先阅读本页面的全部内容以及 常见问题解答(FAQ)

什么是FIT文件?

FIT或灵活且可互操作的数据传输是一种用于GPS轨迹和路线的文件格式。它被较新的Garmin健身GPS设备使用,包括Edge和Forerunner系列,这些设备在自行车手和跑步者中很受欢迎。

访问Wiki中的常见问题解答页面以获取更多信息。

我如何将phpFITFileAnalysis与我的PHP驱动的网站一起使用?

这里有几个选择

更现代的方法:在composer.json文件中添加软件包 adriangibbons/php-fit-file-analysis

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

从命令行运行 composer update

composer.json文件应自动加载phpFITFileAnalysis类,因此只要您在PHP文件中包含自动加载文件,就应该能够使用以下方式实例化该类:

<?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');
?>

更手动的方法:从GitHub下载ZIP文件,并将/src目录中的PHP类文件放置在适当的位置(例如,classes/)。已经尽力将所有内容保持在单个文件中。

然后在您想要使用的PHP页面上包含该文件,并实例化该类的对象

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

注意,在创建实例时,唯一必需的参数是要加载的FIT文件的路径。

还有更多 可选参数 可以提供。这些将在本页面的下方进行更详细的描述。

对象将自动加载FIT文件并遍历其内容。它将在数组中存储它找到的任何数据,这些数组可以通过公共数据变量访问。

访问数据

由类读取的数据存储在关联数组中,这些数组可以通过公共数据变量访问

$pFFA->data_mesgs

数组索引是消息和它们包含的字段的名称。例如

// 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']

好吧,但我如何知道文件中包含哪些消息和字段?您可以选择遍历$pFFA->data_mesgs数组,或者查看可以输出到网页的调试信息

// 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...

一些实际例子如何?

// 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 "];";

枚举数据 FIT协议使用枚举数据类型。在FIT SDK中识别出这些值后,它们被包含在类中作为私有变量:$enum_data。

有一个公共函数可以返回给定消息类型的枚举值。例如

// 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

此外,公共函数提供了一种简短的访问常用枚举数据的方法

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

可选参数

当实例化phpFITFileAnalysis对象时,可以传递五个可选参数,这些参数可以作为关联数组传递。这些是:

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

例如:

$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);

以下更详细地描述了可选参数。

“固定”数据

观察到的FIT文件中,某些传感器(例如踏频器/脚传感器)的数据点缺失,而其他传感器(例如心率)在同一瞬间收集了信息。原因不明,通常只有相对较少的数据点缺失。修复问题可能是多余的,因为每个数据项都使用时间戳进行索引。然而,对于您的项目来说,每种类型的数据点数量完全相同可能很重要。

识别值: 'all', 'cadence', 'distance', 'heart_rate', 'lat_lon', 'power', 'speed'

**示例:**

$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

如果没有提供fix_data数组,则不会执行数据“修复”。

一个FIT文件可能包含以下内容

如上图所示,最易缺失数据点的数据类型是:position_lat、position_long、altitude、heart_rate、cadence、distance、speed和power。

除踏频信息外,缺失的数据点通过插入插值值进行“修复”。

对于踏频,插入零值,因为在这种情况下,很可能在那个时间点没有收集到数据,因为没有运动。

缺失数据点的插值

// 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];

如您在上面的简单示例中看到的,温度数据已为五个时间戳(100、101、102、103和104)记录。然而,距离信息没有为时间戳102和103记录。

如果fix_data包括'distance',则该类将尝试在距离数组的索引102和103处插入数据。值是通过在索引101(4.01)和104(10.88)之间进行线性插值来确定的。

结果将是:

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

每秒数据

一些Garmin的健身设备提供智能记录或每秒记录的选择。

智能记录记录健身设备改变方向、速度、心率或海拔的关键点。此记录类型记录的轨迹点较少,可能在时间戳之间产生大于一秒的间隔。

您可以通过设置选项来强制时间戳为固定的每秒间隔

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

缺失的时间戳将根据上面的fix_data选项进行插值。

如果未指定与data_every_second一起使用的fix_data选项,则假定'fix_data' => ['all']

请注意,您可能在使用fix_data选项时遇到性能下降。将探索提高性能的方法 - 很可能是interpolateMissingData()函数效率不高。

设置单位

默认情况下,假设使用以下表中的识别的**公制**单位。

您可以选择请求**英制**或**原始**单位而不是公制。原始单位是创建FIT文件的设备使用的,并且是FIT标准的本地单位(即,从文件中读取的值不会进行转换)。

要选择所需的单位,请使用以下之一

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

配速

如果用户需要,可以提供配速而不是速度。根据请求的单位,配速将是在公制单位中的每公里分钟(min/km);或英制单位中的每英里分钟(min/mi)。

要选择配速,请使用以下选项

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

配速值将是十进制分钟。要获取秒数,您可能希望执行如下操作:

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

请注意,如果请求“原始”单位,则此参数不会影响速度数据,因为它将保持从文件中读取的原始值。

时间戳

Unix时间是从1970年1月1日UTC 00:00:00开始算起的秒数,然而FIT标准规定时间戳(即date_time和local_date_time类型字段)表示的是从1989年12月31日UTC 00:00:00开始的秒数。

FIT和Unix时间戳之间的差异(以秒为单位)为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);

默认情况下,从FIT文件中读取的date_time和local_date_time类型的字段会加上这个差值,以便它们可以被视为Unix时间。如果需要FIT时间戳,可以将'garmin_timestamps'选项设置为true。

用开发者数据覆盖

FIT标准允许开发者定义数据的含义,而无需更改正在使用的FIT配置文件。他们可以定义已经包含在标准中的数据,例如HR、踏频、功率等。默认情况下,如果开发者这样做,数据将覆盖常规的$pFFA->data_mesgs['record']数组中的任何内容。如果您不希望发生这种情况,请将'overwrite_with_dev_data'选项设置为false。数据仍将在$pFFA->data_mesgs['developer_data']中可用。

分析

以下函数返回可以用于创建表格/图表的数据数组

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);

要获得对这些函数的高级控制,或与其他传感器数据(例如踏频或速度)一起使用,请使用底层函数

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='');

存在基于用户提供的百分比数据确定阈值的函数

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]);

心率

存在一个用于分析心率数据的函数

// 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');

心率指标

  • TRIMP(训练脉冲)
  • 强度系数

功率

存在三个用于分析功率数据的函数

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

功率指标

  • 平均功率
  • 千焦
  • 标准化功率(假设您的功率输出保持恒定的情况下的估计值)
  • 变异性指数(标准化功率/平均功率的比率)
  • 强度系数(标准化功率/功能阈限功率的比率)
  • 训练压力分数(基于相对强度和持续时间的努力程度)

临界功率(或最大努力)是在活动过程中,在指定时间内维持的最高平均功率。您可以为单个时间周期(以秒为单位)提供,也可以为时间周期的数组提供。

象限分析通过比较踏频和功率来比较踏板速度和力,从而提供对骑行中神经肌肉需求的洞察。

请注意,如果服务器上已加载PHP Trader扩展,则$pFFA->criticalPower和一些功率指标(标准化功率、变异性指数、强度系数、训练压力分数)将使用该扩展。如果扩展未加载,则将使用内置的简单移动平均算法,这在大文件中尤其性能较差!

功率分析演示可在此处获得这里

其他方法

使用时间戳作为键返回布尔值数组。true == 计时器暂停(例如自动暂停)

array isPaused()

返回包含请求骑行数据的JSON对象

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']
 */

返回齿轮变换信息数组(如果有,例如使用Shimano D-Fly无线Di2发射器)

// 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)

致谢

此类是基于ANT(thisisant.com)提供的软件开发套件(SDK)中可用的信息创建的。

作为最低要求,我建议阅读SDK中包含的三份PDF文件

  1. FIT文件类型描述
  2. FIT SDK入门指南
  3. 灵活且可互操作的数据传输(FIT)协议

之后是'Profile.xls'电子表格和Java/C/C++示例。