Source for file PolarHrm.class.php
Documentation is available at PolarHrm.class.php
* Class to parse Polar HRM file and insert / update data to database
* HRM file contains data related to 1 exercise.
* This data comes from Polar watch (via Polar software).
* @author Jean-Philippe Brunon <jp75018@free.fr>
* @copyright 2007-2009 Jean-Philippe Brunon
* @license http://www.opensource.org/licenses/gpl-license.php GPL
* @version $Id: PolarHrm.class.php 52 2009-03-17 15:15:30Z jp75018 $
* Class common to all Polar files
require_once ('PolarFile.class.php');
* Heart rate tools to get user rest HR if not in day info
require_once ('include/hr_tools.php');
* Get exercise data from database
require_once ('PolarDbQuery.class.php');
* To generate laps for distance steps / ascend-descend / interval training
require_once ('PolarAutoLap.class.php');
* Load user related sports
require_once ('PolarSport.class.php');
* In case no PDD day info, default sport is running
define('HRM_DEF_SPORT_ID', 1);
* Number of data insert in a single query (HR data and stats insert)
define('HRM_INSERT_DATA_NB', 100);
* Class to parse Polar HRM file and insert / update data to database
* HRM file contains data related to 1 exercise.
* The following fields are handled when present in HRM file (some fields are
* computed before inserting into database):
* - hrm_version : Version of HRM file
* - date : Date of exercise (format : YYYYMMDD)
* - start_time : Start time (format : HH:MM:SS)
* - rank : Rank of exercise in day
* - monitor_type : Type of monitor (see list of values)
* - s_mode : List of data type recorded in
* ('hr','rr','speed','altitude','cadence')
* - rec_interval : Recording interval in (1,5,15,30,60,...)
* - elapsed : Duration in seconds * 10
* - max_hr : Maximum heart rate (bpm)
* - rest_hr : Rest heart rate (bpm)
* - vo2max : VO2 max * 10
* - weight : Weight in Kg * 10
* Exercise info (some fields are computed from HR data before inserting) :
* - rec_distance : Recorded distance in meters * 10
* - ini_hr : Initial heart rate (bpm)
* - min_hr : Minimum heart rate (bpm)
* - avg_hr : Average heart rate (bpm)
* - max_hr : Maximum heart rate (bpm)
* - end_hr : Final heart rate (bpm)
* - ini_speed : Initial speed in km/h * 10
* - min_speed : Minimum speed in km/h * 10
* - avg_speed : Average speed in km/h * 10
* - max_speed : Maximum speed in km/h * 10
* - end_speed : Final speed in km/h * 10
* - ini_cadence : Initial cadence in cycle / min
* - min_cadence : Minimum cadence in cycle / min
* - avg_cadence : Average cadence in cycle / min
* - max_cadence : Maximum cadence in cycle / min
* - end_cadence : Final cadence in cycle / min
* - avg_stride : Average stride length in centimeters
* - max_stride : Maximum stride length in centimeters
* - ini_altitude : Initial altitude in meters
* - min_altitude : Minimum altitude in meters
* - avg_altitude : Average altitude in meters
* - max_altitude : Maximum altitude in meters
* - end_altitude : Final altitude in meters
* - ascend : Ascend in meters
* - beat_sum : Number of heart beats
* - physio_energy : Physiological energy F(HR) in Kcal
* - meca_energy : Mecanical energy (movement + ground friction + air friction
* + cinetic + potential up - C * potential down) in Kcal
* - move_energy : Movement energy (internal energy) in calories
* - fr_grn_energy : Ground friction energy in calories
* - fr_air_energy : Air friction energy in calories
* - cin_energy : (external) kinetic energy in calories
* - up_energy : Potential (ascend only) energy in calories
* - down_energy : Potential (descend only) energy in calories (in part)
* - exercise_type : Type of exercise in ('training', 'contest')
* - mid_elapsed : Elapsed time at mid-distance in seconds * 10
* - description : Note for the exercise
* Interval training elements :
* - repeat_nb : Number of repeatitions (>= 1)
* - work_distance : Work distance in meters
* - work_duration : Work duration in seconds
* - reco_distance : Recovery distance in meters
* - reco_duration : Recovery duration in seconds
* Laps (some fields are computed from HR data before inserting) :
* - elapsed : Duration in seconds * 10 since exercise start
* - lap_elapsed : Duration in seconds * 10
* - distance : Recorded distance in meters
* - ini_hr : Initial heart rate (bpm)
* - min_hr : Minimum heart rate (bpm)
* - avg_hr : Average heart rate (bpm)
* - max_hr : Maximum heart rate (bpm)
* - end_hr : Final heart rate (bpm)
* - ini_speed : Initial speed in km/h * 10
* - min_speed : Minimum speed in km/h * 10
* - avg_speed : Average speed in km/h * 10
* - max_speed : Maximum speed in km/h * 10
* - end_speed : Final speed in km/h * 10
* - ini_cadence : Initial cadence in cycle / min
* - min_cadence : Minimum cadence in cycle / min
* - avg_cadence : Average cadence in cycle / min
* - max_cadence : Maximum cadence in cycle / min
* - end_cadence : Final cadence in cycle / min
* - avg_stride : Average stride length in centimeters
* - max_stride : Maximum stride length in centimeters
* - ini_altitude : Initial altitude in meters
* - min_altitude : Minimum altitude in meters
* - avg_altitude : Average altitude in meters
* - max_altitude : Maximum altitude in meters
* - end_altitude : Final altitude in meters
* - ascend : Ascend in meters
* - physio_energy : Physiological energy F(HR) in cal
* - meca_energy : Mecanical energy in cal
* - description : Note for lap
* HR data : For each recording interval (or each heart beat for 'rr'),
* - hr : Heart rate (bpm)
* - speed : Speed in km/h * 10
* - cadence: Cadence in cycles / minute
* - altitude : Altitude in meters
* - rr : Heart beat duration in milliseconds
* List of recorded data types in ('hr','rr','speed','altitude','cadence')
* Sport standard alias (use to compute mechanical energy)
* @param string $fileName Polar HRM file name (full path name)
* @param integer $userId User ID (as in database)
* Insert exercise into database
* - plw_day_info (insert / update)
* - plw_exercise (insert / update)
* - plw_lap (delete / insert)
* - plw_data (delete / insert), only if data inserted
* - plw_stat (delete / insert), only if statistics inserted
* @param array $exercise Structure for exercise info, laps, and data:
* - 'params' : Parameters (s-mode, interval, ...)
* - 'note' : Description of exercise
* - 'inttimes' : Data for each lap
* - 'intnotes' : Note for each lap (if any)
* - 'hrzones' : HR zones data (not used)
* - 'trip' : Trip data (not used)
* - 'hrdata' : Data for each type recorded
* @param boolean $hr_data True to store 'hrdata' in database, else false
* @param boolean $stat True to store statistics in database, else false
* Statistics contain (value, nb) pairs for data types:
* 'hr', 'speed', 'cadence', 'stride'.
function db_insert($exercise, $hr_data =
true, $stat =
true)
$para =
$exercise['params'];
$note =
$exercise['note'];
$intt =
$exercise['inttimes'];
$intn =
$exercise['intnotes'];
$hrzn =
$exercise['hrzones'];
$trip =
$exercise['trip'];
$data =
$exercise['hrdata'];
while (list
($mode) =
each($para['smode']))
for ($i =
1; $i <=
count($intt); $i++
)
// Fix "zombie" laps ! (less than 5 second with speed > 30 m/s - 108 km/h)
$lap_duration =
$intt[$i]['elapsed'] -
$sum_elapsed;
$sum_elapsed =
$intt[$i]['elapsed'];
if (($lap_duration <
50) &&
($lap_duration >
0))
if (($intt[$i]['distance'] /
$lap_duration) >
3)
// Compute right distance if end speed
if ($intt[$i]['end_speed'])
{ $distance +=
round($intt[$i]['end_speed'] *
$lap_duration /
360); }
{ $distance +=
$intt[$i]['distance']; }
// Get weight from day info (more precision) for energy computing
// Get closest date if weight = 0
$exact_weight =
$para['weight'];
$request =
sprintf("SELECT weight FROM plw_day_info WHERE user_id = %d AND weight > 0 ORDER BY ABS(DATEDIFF(day, %s)) LIMIT 1",
$this->userId, $para['date']);
$exact_weight =
$row['weight'] /
10;
// Get rest HR, VO2max/MAS from day info (more precision) for energy computing
// Get closest date if rest HR = 0
// Get or compute VMA * 10 for speed ratios
// If no VMA and no VO2max info => Use reserve HR and speed / HR ratio
$request =
sprintf("SELECT rest_hr, max_hr, vo2max, vma FROM plw_day_info WHERE user_id = %d AND rest_hr > 0 ORDER BY ABS(DATEDIFF(day, %s)) LIMIT 1",
$this->userId, $para['date']);
$rest_hr =
$row['rest_hr'];
$max_user_hr =
$row['max_hr'];
$vo2max =
$row['vo2max'];
// If no rest HR => get from user record
// If no VO2max, try to get vo2max / vma from user record
$request =
sprintf("SELECT vo2max, vma FROM plw_user WHERE id = %d",
// If yet no VMA, compute from avg speed and HR if possible
$vma =
round($exe_avg_speed *
(($max_user_hr -
$rest_hr) /
($exe['avg_hr'] -
$rest_hr)));
/* Try to get sport ID from exercise table (day info PDD file) =>
Get std sport alias used to compute mechanical energy */
$request =
sprintf("SELECT sport_id FROM plw_exercise WHERE user_id = %d AND day = %s AND rank = %d",
$this->userId, $para['date'], $rank);
$sport_id =
$row['sport_id'];
$sports =
$sport->get_sports($this->userId);
// Get ini, end, avg, min, max HR, beat_sum from HR data ('hr' and 'rr' cases)
if ($para['smode']['hr'])
$ini_hr =
$data[0]['hr'];
$end_hr =
$data[$nb_data -
1]['hr'];
for ($i =
0; $i <
$nb_data; $i++
)
$sum_hr +=
$data[$i]['hr'];
if ($data[$i]['hr'] >
$max_hr)
{ $max_hr =
$data[$i]['hr']; }
if ($data[$i]['hr'] <
$min_hr)
{ $min_hr =
$data[$i]['hr']; }
if ($stat &&
($data[$i]['hr'] >
0)) // No stat if HR = 0
{ $stats['hr'][$data[$i]['hr']] +=
$para['interval']; }
$avg_hr =
round($sum_hr /
$nb_data, 2);
$beat_sum =
round(($para['interval'] *
$sum_hr) /
60);
if ($para['smode']['rr'])
$ini_hr =
round(60000 /
$data[0]['rr'], 2);
$end_hr =
round(60000 /
$data[$nb_data -
1]['rr'], 2);
$avg_hr =
round($nb_data /
($para['length'] /
600), 2);
for ($i =
0; $i <
$nb_data; $i++
)
if ($data[$i]['rr'] >
$rr_max)
{ $rr_max =
$data[$i]['rr']; }
if ($data[$i]['rr'] <
$rr_min)
{ $rr_min =
$data[$i]['rr']; }
{ $stats['hr'][round(60000/
$data[$i]['rr'])] +=
$data[$i]['rr']/
1000; }
$max_hr =
round(60000 /
$rr_min, 2);
$min_hr =
round(60000 /
$rr_max, 2);
$beat_sum =
$nb_data +
1;
// Rounds HR stats and removes if nb = 0
while (list
($value) =
each($stats['hr']))
$stats['hr'][$value] =
round($stats['hr'][$value]);
if (! $stats['hr'][$value])
{ unset
($stats['hr'][$value]); }
// Get ini, end, avg, min, max speed from HR data
if ($para['smode']['speed'])
$ini_speed =
$data[0]['speed'];
$end_speed =
$data[$nb_data -
1]['speed'];
for ($i =
0; $i <
$nb_data; $i++
)
$speed =
$data[$i]['speed'];
$sum_d2 +=
$para['interval'] *
$speed /
36;
$cin_en +=
$speed *
$speed -
$p_speed *
$p_speed;
$speed *
$speed /
46656; // delta_dist * C * V * V
if ($stat &&
($data[$i]['speed'] >
0)) // No stat if speed = 0
{ $stats['speed'][$data[$i]['speed']] +=
$para['interval']; }
$avg_speed =
round($sum_speed /
$nb_data, 2);
$cin_en *=
$exact_weight /
2592; // 2592 = 2 * (10 * 3.6)^2
$air_en =
round($air_en *
$exact_weight);
// 2nd loop to get mid-distance elapsed time
{ $d_ratio =
$distance /
$sum_d2; }
$mid_dist =
$distance /
2;
for ($i =
0; $i <
$nb_data; $i++
)
$dd =
$d_ratio *
$para['interval'] *
$data[$i]['speed'] /
36;
if (($dd >
0) &&
(($sum_d +
$dd) >=
$mid_dist))
round(($i +
($mid_dist -
$sum_d) /
$dd) *
$para['interval'] *
10);
// Get ini, end, avg, min, max cadence from HR data
// Also compute avg and max stride length
if ($para['smode']['cadence'])
$ini_cadence =
$data[0]['cadence'];
$end_cadence =
$data[$nb_data -
1]['cadence'];
for ($i =
0; $i <
$nb_data; $i++
)
$sum_cadence +=
$data[$i]['cadence'];
if ($data[$i]['cadence'] >
$max_cadence)
{ $max_cadence =
$data[$i]['cadence']; }
if ($data[$i]['cadence'] <
$min_cadence)
{ $min_cadence =
$data[$i]['cadence']; }
if ($stat &&
($data[$i]['cadence'] >
0)) // No stat if cadence = 0
{ $stats['cadence'][$data[$i]['cadence']] +=
$para['interval']; }
if ($para['smode']['speed'])
if ($data[$i]['cadence'] >
0)
round(250 *
$data[$i]['speed'] /
(3 *
$data[$i]['cadence']), 2);
{ $stride =
$prev_stride; }
if ($stride >
$max_stride)
{ $max_stride =
$stride; }
if ($stat &&
(round($stride) >
0)) // No stat if stride = 0
{ $stats['stride'][round($stride)] +=
$para['interval']; }
$avg_cadence =
round($sum_cadence /
$nb_data, 2);
if ($para['smode']['speed'] &&
($avg_cadence >
0))
{ $avg_stride =
round(250 *
$sum_speed /
(3 *
$sum_cadence), 2); }
// Get ini, end, avg, min, max altitude + ascend from HR data
if ($para['smode']['altitude'])
$ini_altitude =
$data[0]['altitude'];
$end_altitude =
$data[$nb_data -
1]['altitude'];
$alt_local_min =
$data[0]['altitude'];
for ($i =
1; $i <
$nb_data; $i++
)
$sum_altitude +=
$data[$i]['altitude'];
if ($data[$i]['altitude'] >
$max_altitude)
{ $max_altitude =
$data[$i]['altitude']; }
if ($data[$i]['altitude'] <
$min_altitude)
{ $min_altitude =
$data[$i]['altitude']; }
// Skip variations due to pause / merge exercises (air pressure change)
if ($data[$i]['altitude'] >
{ $alt_local_min =
$data[$i]['altitude']; }
// Avoid variations due to measure precision (MIN_DELTA_ALTITUDE)
$ascend +=
$data[$i]['altitude'] -
$alt_local_min;
$alt_local_min =
$data[$i]['altitude'];
if ($data[$i]['altitude'] <
$alt_local_min)
{ $alt_local_min =
$data[$i]['altitude']; }
$avg_altitude =
round($sum_altitude /
$nb_data, 2);
$descend =
$ascend +
$ini_altitude -
$end_altitude;
$meca_en =
round(($cin_en +
$pot_en_up -
$pot_en_down +
$mov_en +
$grn_en +
$air_en) /
1000);
// Parse note to extract contest distance or interval training expression
$exercise_type =
'training';
&$exercise_type, &$exact_dist, &$int_train, &$options);
// Check parsed distance is close enough to recorded distance (15%)
if (($distance >
0) &&
($exercise_type ==
'contest'))
if (abs($exact_dist -
$distance) /
($exact_dist +
$distance) >
0.075)
$real_dist =
($exact_dist >
0) ?
$exact_dist :
$distance;
// 1. Insert / Update day part
// Note : weight not updated (better from PDD file)
$request =
sprintf("INSERT INTO plw_day_info(user_id, day, cre_date, mod_date, rest_hr, max_hr, weight, vo2max) VALUES(%d, %s, NOW(), NOW(), %s, %s, %s, %s) ON DUPLICATE KEY UPDATE cre_date=cre_date, mod_date=NOW(), rest_hr=%s, max_hr=%s, vo2max=%s",
$para['resthr'] >
0 ?
$para['resthr'] :
'NULL',
$para['maxhr'] >
0 ?
$para['maxhr'] :
'NULL',
$para['weight'] >
0 ?
10 *
$para['maxhr'] :
'NULL',
$para['vo2max'] >
0 ?
10 *
$para['vo2max'] :
'NULL',
$para['resthr'] >
0 ?
$para['resthr'] :
'NULL',
$para['maxhr'] >
0 ?
$para['maxhr'] :
'NULL',
$para['vo2max'] >
0 ?
10 *
$para['vo2max'] :
'NULL'
// Get last inserted exercise ID to check if insert or update
$request =
sprintf("SELECT MAX(id) AS id FROM plw_exercise WHERE user_id = %d",
$max_exercise_id =
$row['id'];
$exe_avg_speed =
$avg_speed;
// Computes energy from physilogical parameters (HR, rest HR, weight)
if ($exact_weight &&
$rest_hr &&
$beat_sum &&
$para['length'] &&
$vma)
$physio_old =
round(6.67 *
// 2. Insert / Update exercise part
Note : real_distance, description, exercise_type, and options not updated
(up-to-date in PDD file only)
// Unset footpod options if no speed measure !
if (! $para['smode']['speed'])
unset
($options['footpod_id']);
unset
($options['footpod_batt']);
$exe_delta_altitude =
$max_altitude -
$min_altitude;
$request =
sprintf("INSERT INTO plw_exercise(user_id, day, rank, status, cre_date, mod_date, sport_id, start_time, hrm_version, monitor_type, s_mode, rec_interval, elapsed, rec_distance, real_distance, ini_hr, min_hr, avg_hr, max_hr, end_hr, ini_speed, min_speed, avg_speed, max_speed, end_speed, ini_cadence, min_cadence, avg_cadence, max_cadence, end_cadence, avg_stride, max_stride, ini_altitude, min_altitude, avg_altitude, max_altitude, end_altitude, ascend, beat_sum, physio_energy, meca_energy, move_energy, fr_grn_energy, fr_air_energy, cin_energy, up_energy, down_energy, exercise_type, mid_elapsed, description, shoe, shoe_ini_dist, footpod_id, footpod_batt) VALUES (%d, %s, %d, 'offline', NOW(), NOW(), %d, '%s', %d, %d, ('%s'), %d, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, '%s', %s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE status=IF(status='offline','offline','online'), cre_date=cre_date, mod_date=NOW(), start_time='%s', hrm_version=%d, monitor_type=%d, s_mode=('%s'), rec_interval=%d, elapsed=%d, rec_distance=%s, ini_hr=%s, min_hr=%s, avg_hr=%s, max_hr=%s, end_hr=%s, ini_speed=%s, min_speed=%s, avg_speed=%s, max_speed=%s, end_speed=%s, ini_cadence=%s, min_cadence=%s, avg_cadence=%s, max_cadence=%s, end_cadence=%s, avg_stride=%s, max_stride=%s, ini_altitude=%s, min_altitude=%s, avg_altitude=%s, max_altitude=%s, end_altitude=%s, ascend=%s, beat_sum=%s, physio_energy=%s, meca_energy=%s, move_energy=%s, fr_grn_energy=%s, fr_air_energy=%s, cin_energy=%s, up_energy=%s, down_energy=%s, mid_elapsed=%s, footpod_id=%s, footpod_batt=%s",
$this->userId, $para['date'], $rank, $sport_id,
$para['starttime'], $para['version'], $para['monitor'],
implode(',', $smode), $para['interval'] ?
$para['interval'] :
0,
$para['length'], $distance >
0 ?
$distance :
'NULL',
$real_dist >
0 ?
$real_dist :
'NULL',
$max_hr >
0 ?
$ini_hr :
'NULL', $max_hr >
0 ?
$min_hr :
'NULL',
$max_hr >
0 ?
$avg_hr :
'NULL', $max_hr >
0 ?
$max_hr :
'NULL',
$max_hr >
0 ?
$end_hr :
'NULL',
$max_speed >
0 ?
$ini_speed :
'NULL',
$max_speed >
0 ?
$min_speed :
'NULL',
$max_speed >
0 ?
$avg_speed :
'NULL',
$max_speed >
0 ?
$max_speed :
'NULL',
$max_speed >
0 ?
$end_speed :
'NULL',
$max_cadence >
0 ?
$ini_cadence :
'NULL',
$max_cadence >
0 ?
$min_cadence :
'NULL',
$max_cadence >
0 ?
$avg_cadence :
'NULL',
$max_cadence >
0 ?
$max_cadence :
'NULL',
$max_cadence >
0 ?
$end_cadence :
'NULL',
$max_stride >
0 ?
$avg_stride :
'NULL',
$max_stride >
0 ?
$max_stride :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$ini_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$min_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$avg_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$max_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$end_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$ascend :
'NULL',
$beat_sum >
0 ?
$beat_sum :
'NULL',
$physio_en >
0 ?
$physio_en :
'NULL', $meca_en >
0 ?
$meca_en :
'NULL',
$meca_en >
0 ?
$mov_en :
'NULL', $meca_en >
0 ?
$grn_en :
'NULL',
$meca_en >
0 ?
$air_en :
'NULL', $meca_en >
0 ?
$cin_en :
'NULL',
$meca_en >
0 ?
$pot_en_up :
'NULL', $meca_en >
0 ?
$pot_en_down :
'NULL',
$mid_elapsed >
0 ?
$mid_elapsed :
'NULL',
$options['shoe_ini_dist'] >
0 ?
$options['shoe_ini_dist'] :
'NULL',
isset
($options['footpod_id']) ?
$options['footpod_id'] :
'NULL',
isset
($options['footpod_batt']) ?
$options['footpod_batt'] :
'NULL',
$para['starttime'], $para['version'], $para['monitor'],
implode(',', $smode), $para['interval'] ?
$para['interval'] :
0,
$distance >
0 ?
$distance :
'NULL',
$max_hr >
0 ?
$ini_hr :
'NULL', $max_hr >
0 ?
$min_hr :
'NULL',
$max_hr >
0 ?
$avg_hr :
'NULL', $max_hr >
0 ?
$max_hr :
'NULL',
$max_hr >
0 ?
$end_hr :
'NULL',
$max_speed >
0 ?
$ini_speed :
'NULL',
$max_speed >
0 ?
$min_speed :
'NULL',
$max_speed >
0 ?
$avg_speed :
'NULL',
$max_speed >
0 ?
$max_speed :
'NULL',
$max_speed >
0 ?
$end_speed :
'NULL',
$max_cadence >
0 ?
$ini_cadence :
'NULL',
$max_cadence >
0 ?
$min_cadence :
'NULL',
$max_cadence >
0 ?
$avg_cadence :
'NULL',
$max_cadence >
0 ?
$max_cadence :
'NULL',
$max_cadence >
0 ?
$end_cadence :
'NULL',
$max_stride >
0 ?
$avg_stride :
'NULL',
$max_stride >
0 ?
$max_stride :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$ini_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$min_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$avg_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$max_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$end_altitude :
'NULL',
(($avg_altitude !=
0) ||
($ascend >
0)) ?
$ascend :
'NULL',
$beat_sum >
0 ?
$beat_sum :
'NULL',
$physio_en >
0 ?
$physio_en :
'NULL', $meca_en >
0 ?
$meca_en :
'NULL',
$meca_en >
0 ?
$mov_en :
'NULL', $meca_en >
0 ?
$grn_en :
'NULL',
$meca_en >
0 ?
$air_en :
'NULL', $meca_en >
0 ?
$cin_en :
'NULL',
$meca_en >
0 ?
$pot_en_up :
'NULL', $meca_en >
0 ?
$pot_en_down :
'NULL',
$mid_elapsed >
0 ?
$mid_elapsed :
'NULL',
$para['smode']['speed'] ?
'footpod_id' :
'NULL',
$para['smode']['speed'] ?
'footpod_batt' :
'NULL'
// Get exercise ID to work with laps, interval training, and HR data
// 3. Insert interval training elements (only if new exercise)
if (is_array($int_train) &&
($exercise_id >
$max_exercise_id))
for ($int =
0; $int <
count($int_train); $int++
)
$train =
$int_train[$int];
$request =
sprintf("INSERT INTO plw_int_training(exercise_id, rank, repeat_nb, work_distance, work_duration, reco_distance, reco_duration) VALUES (%d, %d, %d, %s, %s, %s, %s)",
$exercise_id, $int, $train['repeat_nb'],
$train['work_distance'] >
0 ?
$train['work_distance'] :
'NULL',
$train['work_duration'] >
0 ?
$train['work_duration'] :
'NULL',
$train['reco_distance'] >
0 ?
$train['reco_distance'] :
'NULL',
$train['reco_duration'] >
0 ?
$train['reco_duration'] :
'NULL'
// 4. Insert laps, delete first (not for 'rr')
$request =
sprintf("DELETE FROM plw_lap WHERE exercise_id=%d",$exercise_id);
if (! $para['smode']['rr'])
// 4.a Insert 'polar' laps
for ($l =
1; $l <=
count($intt); $l++
)
$ind =
floor($total_elapsed /
(10 *
$para['interval'])); // Ind in HR data
$nb_rec =
floor($intt[$l]['elapsed'] /
(10 *
$para['interval'])) -
$ind;
if (($ind +
$nb_rec) >
$nb_data)
{ $nb_rec =
$nb_data -
$ind; }
$lap_length =
$intt[$l]['elapsed'] -
$total_elapsed;
$lap_distance =
$intt[$l]['distance'];
// Get ini, end, avg, min, max HR from HR data
if ($para['smode']['hr'] &&
($nb_rec >
0))
$ini_hr =
$data[$ind]['hr'];
$end_hr =
$data[$ind +
$nb_rec -
1]['hr'];
for ($i =
$ind; $i <
$ind +
$nb_rec; $i++
)
$sum_hr +=
$data[$i]['hr'];
if ($data[$i]['hr'] >
$max_hr)
{ $max_hr =
$data[$i]['hr']; }
if ($data[$i]['hr'] <
$min_hr)
{ $min_hr =
$data[$i]['hr']; }
$avg_hr =
round($sum_hr /
$nb_rec, 2);
// Computes energy from physilogical parameters (HR, rest HR, weight)
$beat_sum =
round(($para['interval'] *
$sum_hr) /
60);
if ($exact_weight &&
$rest_hr &&
$beat_sum &&
$lap_length &&
$vma)
// Get ini, end, avg, min, max speed from HR data
if ($para['smode']['speed'] &&
($nb_rec >
0))
$ini_speed =
$data[$ind]['speed'];
$end_speed =
$data[$ind +
$nb_rec -
1]['speed'];
for ($i =
$ind; $i <
$ind +
$nb_rec; $i++
)
$speed =
$data[$i]['speed'];
$cin_en +=
$speed *
$speed -
$p_speed *
$p_speed;
$speed *
$speed /
46656; // delta_dist * C * V * V
$avg_speed =
round(360 *
$lap_distance /
$lap_length, 2);
$cin_en *=
$exact_weight /
2592; // 2592 = 2 * (10 * 3.6)^2
$air_en =
round($air_en *
$exact_weight);
// Adjust cinetic and air energy considering exact duration
$dist_ratio =
$lap_length /
(10 *
$nb_rec *
$para['interval']);
// Get ini, end, avg, min, max cadence from HR data
// Also compute avg and max stride length
if ($para['smode']['cadence'] &&
($nb_rec >
0))
$ini_cadence =
$data[$ind]['cadence'];
$end_cadence =
$data[$ind +
$nb_rec -
1]['cadence'];
for ($i =
$ind; $i <
$ind +
$nb_rec; $i++
)
$sum_cadence +=
$data[$i]['cadence'];
if ($data[$i]['cadence'] >
$max_cadence)
{ $max_cadence =
$data[$i]['cadence']; }
if ($data[$i]['cadence'] <
$min_cadence)
{ $min_cadence =
$data[$i]['cadence']; }
if ($para['smode']['speed'])
if ($data[$i]['cadence'] >
0)
round(250 *
$data[$i]['speed'] /
(3 *
$data[$i]['cadence']), 2);
{ $stride =
$prev_stride; }
if ($stride >
$max_stride)
{ $max_stride =
$stride; }
$avg_cadence =
round($sum_cadence /
$nb_rec, 2);
if ($para['smode']['speed'] &&
($avg_cadence >
0))
{ $avg_stride =
round(250 *
$sum_speed /
(3 *
$sum_cadence), 2); }
// Get ini, end, avg, min, max altitude + ascend from HR data
if ($para['smode']['altitude'] &&
($nb_rec >
0))
$ini_altitude =
$data[$ind]['altitude'];
$end_altitude =
$data[$ind +
$nb_rec -
1]['altitude'];
$alt_local_min =
$data[$ind]['altitude'];
for ($i =
$ind; $i <
$ind +
$nb_rec; $i++
)
$sum_altitude +=
$data[$i]['altitude'];
if ($data[$i]['altitude'] >
$max_altitude)
{ $max_altitude =
$data[$i]['altitude']; }
if ($data[$i]['altitude'] <
$min_altitude)
{ $min_altitude =
$data[$i]['altitude']; }
$ascend +=
$data[$i]['altitude'] -
$alt_local_min;
$alt_local_min =
$data[$i]['altitude'];
if ($data[$i]['altitude'] <
$alt_local_min)
{ $alt_local_min =
$data[$i]['altitude']; }
$avg_altitude =
round($sum_altitude /
$nb_rec, 2);
$descend =
$ascend +
$ini_altitude -
$end_altitude;
$meca_en =
round($cin_en +
$pot_en_up -
$pot_en_down +
$mov_en +
$grn_en +
$air_en);
'elapsed' =>
$intt[$l]['elapsed'],
'lap_elapsed' =>
$intt[$l]['elapsed'] -
$total_elapsed,
'distance' =>
$intt[$l]['distance'],
'ini_speed' =>
$ini_speed,
'min_speed' =>
$min_speed,
'avg_speed' =>
$avg_speed,
'max_speed' =>
$max_speed,
'end_speed' =>
$end_speed,
'ini_cadence' =>
$ini_cadence,
'min_cadence' =>
$min_cadence,
'avg_cadence' =>
$avg_cadence,
'max_cadence' =>
$max_cadence,
'end_cadence' =>
$end_cadence,
'avg_stride' =>
$avg_stride,
'max_stride' =>
$max_stride,
'ini_altitude' =>
$ini_altitude,
'min_altitude' =>
$min_altitude,
'avg_altitude' =>
$avg_altitude,
'max_altitude' =>
$max_altitude,
'end_altitude' =>
$end_altitude,
'physio_energy' =>
$physio_en,
'meca_energy' =>
$meca_en,
'description' =>
$intn[$l]
if ($nb_rec >
0) // Add Test to avoid empty intervals!
$total_elapsed =
$intt[$l]['elapsed'];
// 4.b Insert 'distance' laps if recorded distance (speed mesure)
// Get real distance from database because it comes from PDD file
$request =
sprintf("SELECT real_distance FROM plw_exercise WHERE id = %d",
$real_distance =
$exe_data['real_distance'];
if ($real_distance <=
100000) // <= 100 km
{ $d_step =
2000; } // 2 km
if ($real_distance <=
50000) // <= 50 km
{ $d_step =
1000; } // 1 km
if ($real_distance <
10000) // < 10 km
{ $d_step =
500; } // 500 m
if ($real_distance <
5000) // < 5 km
{ $d_step =
100; } // 100 m
$d_laps =
$auto_lap->generate_auto_laps('distance', $data,
$para['interval'], $real_distance, $rest_hr, $exact_weight, $d_step,
for ($l =
1; $l <=
count($d_laps); $l++
)
{ $this->_insert_lap($exercise_id, 'distance', $l, $d_laps[$l]); }
// 4.c Insert 'interval' laps if recorded distance (speed mesure)
// Get interval training elements because may be set in PDD exercise note
$int_train =
$dbQuery->get_interval_training($exercise_id);
$i_laps =
$auto_lap->generate_interval_training($p_laps,
for ($l =
1; $l <=
count($i_laps); $l++
)
{ $this->_insert_lap($exercise_id, 'interval', $l, $i_laps[$l]); }
// 4.d Insert 'altitude' laps if recorded altitude
$a_laps =
$auto_lap->generate_auto_laps('altitude', $data,
$para['interval'], $real_distance, $rest_hr, $exact_weight,
$exe_delta_altitude, $vma /
10);
for ($l =
1; $l <=
count($a_laps); $l++
)
{ $this->_insert_lap($exercise_id, 'altitude', $l, $a_laps[$l]); }
// 4.e Insert 'time' laps
if ($para['length'] <=
864000) // <= 24 H
{ $t_step =
18000; }// 30'
if ($para['length'] <=
432000) // <= 12 H
{ $t_step =
9000; } // 15'
if ($para['length'] <=
144000) // <= 4 H
{ $t_step =
3000; } // 5'
if ($para['length'] <=
30000) // <= 50'
if ($para['length'] <=
15000) // <= 25'
{ $t_step =
300; } // 30"
if ($para['length'] <=
7200) // <= 12'
{ $t_step =
150; } // 15"
$t_laps =
$auto_lap->generate_auto_laps('time', $data,
$para['interval'], $real_distance, $rest_hr, $exact_weight, $t_step,
for ($l =
1; $l <=
count($t_laps); $l++
)
{ $this->_insert_lap($exercise_id, 'time', $l, $t_laps[$l]); }
// 5. Insert data, delete first
sprintf("DELETE FROM plw_data WHERE exercise_id=%d", $exercise_id);
for ($i =
0; $i <
$nb_data; $i++
)
$request =
'INSERT INTO plw_data(exercise_id, rank, hr, rr, speed, cadence, altitude) VALUES ';
$request .=
sprintf("(%d,%d,%s,%s,%s,%s,%s)",
$para['smode']['hr'] ?
"'" .
$data[$i]['hr'] .
"'" :
'NULL',
$para['smode']['rr'] ?
"'" .
$data[$i]['rr'] .
"'" :
'NULL',
$para['smode']['speed'] ?
"'" .
$data[$i]['speed'] .
"'" :
'NULL',
$para['smode']['cadence'] ?
"'" .
$data[$i]['cadence'] .
"'" :
'NULL',
$para['smode']['altitude'] ?
"'" .
$data[$i]['altitude'] .
"'":
'NULL'
// 5. Insert stats, delete first
sprintf("DELETE FROM plw_stat WHERE exercise_id=%d", $exercise_id);
while (list
($data_type, $values) =
each($stats))
{ $nb_stat +=
count($values); }
while (list
($data_type, $values) =
each($stats))
while (list
($value, $nb) =
each($values))
$request =
'INSERT INTO plw_stat(exercise_id, data_type, value, nb) VALUES ';
$request .=
sprintf("(%d,'%s',%d,%d)",
$exercise_id, $data_type, $value, $nb);
* Insert one lap row into plw_lap SQL table
* @param integer $exercise_id Exercise ID
* @param string $lap_type Type of lap in ('polar','distance','altitude',
* @param integer $rank Rank of lap (from 1)
* @param array $lap Lap fields (same structure as plw_lap table)
function _insert_lap($exercise_id, $lap_type, $rank, $lap)
$request =
sprintf("INSERT INTO plw_lap(exercise_id, lap_type, rank, subtotal, elapsed, lap_elapsed, distance, ini_hr, min_hr, avg_hr, max_hr, end_hr, ini_speed, min_speed, avg_speed, max_speed, end_speed, ini_cadence, min_cadence, avg_cadence, max_cadence, end_cadence, avg_stride, max_stride, ini_altitude, min_altitude, avg_altitude, max_altitude, end_altitude, ascend, physio_energy, meca_energy, beat_sum, description) VALUES (%d, '%s', %d, '%s', %d, %d, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
$exercise_id, $lap_type, $rank, $lap['subtotal'],
$lap['elapsed'], $lap['lap_elapsed'],
$lap['distance'] >
0 ?
$lap['distance'] :
'NULL',
$lap['max_hr'] >
0 ?
$lap['ini_hr'] :
'NULL',
$lap['max_hr'] >
0 ?
$lap['min_hr'] :
'NULL',
$lap['max_hr'] >
0 ?
$lap['avg_hr'] :
'NULL',
$lap['max_hr'] >
0 ?
$lap['max_hr'] :
'NULL',
$lap['max_hr'] >
0 ?
$lap['end_hr'] :
'NULL',
$lap['max_speed'] >
0 ?
$lap['ini_speed'] :
'NULL',
$lap['max_speed'] >
0 ?
$lap['min_speed'] :
'NULL',
$lap['max_speed'] >
0 ?
$lap['avg_speed'] :
'NULL',
$lap['max_speed'] >
0 ?
$lap['max_speed'] :
'NULL',
$lap['max_speed'] >
0 ?
$lap['end_speed'] :
'NULL',
$lap['max_cadence'] >
0 ?
$lap['ini_cadence'] :
'NULL',
$lap['max_cadence'] >
0 ?
$lap['min_cadence'] :
'NULL',
$lap['max_cadence'] >
0 ?
$lap['avg_cadence'] :
'NULL',
$lap['max_cadence'] >
0 ?
$lap['max_cadence'] :
'NULL',
$lap['max_cadence'] >
0 ?
$lap['end_cadence'] :
'NULL',
$lap['max_stride'] >
0 ?
$lap['avg_stride'] :
'NULL',
$lap['max_stride'] >
0 ?
$lap['max_stride'] :
'NULL',
(($lap['avg_altitude'] !=
0) ||
($lap['ascend'] >
0)) ?
$lap['ini_altitude'] :
'NULL',
(($lap['avg_altitude'] !=
0) ||
($lap['ascend'] >
0)) ?
$lap['min_altitude'] :
'NULL',
(($lap['avg_altitude'] !=
0) ||
($lap['ascend'] >
0)) ?
$lap['avg_altitude'] :
'NULL',
(($lap['avg_altitude'] !=
0) ||
($lap['ascend'] >
0)) ?
$lap['max_altitude'] :
'NULL',
(($lap['avg_altitude'] !=
0) ||
($lap['ascend'] >
0)) ?
$lap['end_altitude'] :
'NULL',
(($lap['avg_altitude'] !=
0) ||
($lap['ascend'] >
0)) ?
$lap['physio_energy'] >
0 ?
$lap['physio_energy'] :
'NULL',
$lap['meca_energy'] >
0 ?
$lap['meca_energy'] :
'NULL',
$lap['beat_sum'] >
0 ?
$lap['beat_sum'] :
'NULL',
$lap['description'] !=
'' ?
* Parse Polar HRM file (parameters, note, lap times and notes, HR data)
* - The following blocks are parsed : <params>, <note>, <inttimes>, <intnotes>,
* <hrzones>, <trip>, <hrdata>.
* - Data from <hrzones> and <trip> blocks is not used.
* @param boolean $header_only True to parse 'params', 'note', and
* 'inttimes' blocks only, else false. True is used to
* display exercise information when uploadind / importing
* @return array Structure for exercise data :
* - 'params' : Exercise parameters
* - 'note' : Exercise description
* - 'inttimes' : Exercise laps (there is at least 1 lap)
* - 'intnotes' : Exercise notes when present
* - 'trip' : Trip information
* - 'hrdata' : Recorded data for each data type
function parse($header_only =
false)
while ($line_no <
count($buffer))
$begin_block =
$line_no +
1;
(! in_array($block_name, array('params', 'note', 'inttimes'))))
$lg_block =
$line_no -
$begin_block -
1;
if (! trim($buffer[$end_block]))
$parse_func =
'_parse_block_' .
$block_name .
'_get';
$this->$parse_func(&$buffer, $begin_block, $lg_block);
// Check day match filename !
$data_day =
$exercise['params']['date'];
if ($file_day !=
$data_day)
* Parse <params> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return array Array of parameters
for ($i =
$start; $i <
($start +
$nb); $i++
)
$name_value =
explode('=', $buffer[$i]);
$value =
trim($name_value[1]);
{ $value['cadence'] =
1; }
{ $value['altitude'] =
1; }
{ $value['cadence'] =
1; }
{ $value['altitude'] =
1; }
$value =
substr($value, 0, 8);
$value =
36000 * (int)
substr($value, 0, 2) +
600 * (int)
substr($value, 3, 2) +
10 * (int)
substr($value, 6, 2) +
$params['smode']['rr'] =
1;
unset
($params['smode']['hr']);
$this->smode =
$params['smode'];
* Parse <note> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return string Exercise note
for ($i =
$start; $i <
($start +
$nb); $i++
)
{ $note .=
$buffer[$i]; }
* Parse <inttimes> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return array Array of laps (1 to N)
for ($i =
0; $i <
($nb /
5); $i++
)
$laps[$i +
1]['elapsed'] =
36000 * (int)
substr($row[0], 0, 2) +
600 * (int)
substr($row[0], 3, 2) +
10 * (int)
substr($row[0], 6, 2) +
$laps[$i +
1]['end_hr'] =
$row[1];
$laps[$i +
1]['min_hr'] =
$row[2];
$laps[$i +
1]['avg_hr'] =
$row[3];
$laps[$i +
1]['max_hr'] =
$row[4];
$row =
explode("\t", trim($buffer[$start +
5 *
$i +
1]));
$laps[$i +
1]['end_speed'] =
$row[3];
$laps[$i +
1]['end_altitude'] =
$row[5];
$row =
explode("\t", trim($buffer[$start +
5 *
$i +
3]));
$laps[$i +
1]['distance'] =
$row[1];
$row =
explode("\t", trim($buffer[$start +
5 *
$i +
4]));
$laps[$i +
1]['end_stride'] =
$row[0]; // To check !
* Parse <intnotes> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return array Array of lap notes (indexed by lap number), empty if
for ($i =
$start; $i <
($start +
$nb); $i++
)
$notes[$row[0]] =
$row[1];
* Parse <hrzones> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return array Array of HR zones, from 1
for ($i =
$start; $i <
($start +
$nb); $i++
)
$value =
trim($buffer[$i]);
{ $zones[$j++
] =
$value; }
* Parse <trip> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return array Trip structure
for ($i =
$start; $i <
($start +
$nb); $i++
)
{ $rows[$j++
] =
trim($buffer[$i]); }
$trip['distance'] =
$rows[0];
$trip['ascend'] =
$rows[1];
$trip['duration'] =
$rows[2];
$trip['avg_altitude'] =
$rows[3];
$trip['max_altitude'] =
$rows[4];
$trip['avg_speed'] =
$rows[5];
$trip['max_speed'] =
$rows[6];
* Parse <hrdata> block in HRM file
* @param string $buffer Buffer with HRM file content
* @param integer $start Line number of block in buffer
* @param integer $nb Number of lines in block
* @return array Array of recorded data values, from 0
for ($i =
$start; $i <
($start +
$nb); $i++
)
{ $hrdata[$j]['hr'] =
$row[$k++
]; }
{ $hrdata[$j]['rr'] =
$row[$k++
]; }
if ($this->smode['speed'])
{ $hrdata[$j]['speed'] =
$row[$k++
]; }
if ($this->smode['cadence'])
{ $hrdata[$j]['cadence'] =
$row[$k++
]; }
if ($this->smode['altitude'])
{ $hrdata[$j]['altitude'] =
$row[$k++
]; }
Documentation generated on Sat, 28 Mar 2009 23:16:46 +0000 by phpDocumentor 1.4.1