Salut,
Hier soir, j’ai demandé à Copilot de me convertir le code Python en PHP, et je l’ai mis dans un bloc Code d’un scénario.
Je suis parti de la source que j’ai trouvé pour ne pas piller BLEA :
from math import floor
from body_scales import bodyScales
class bodyMetrics:
def __init__(self, weight, height, age, sex, impedance):
self.weight = weight
self.height = height
self.age = age
self.sex = sex
self.impedance = impedance
self.scales = bodyScales(age, height, sex, weight)
# Check for potential out of boundaries
if self.height > 220:
raise Exception("Height is too high (limit: >220cm)")
elif weight < 10 or weight > 200:
raise Exception("Weight is either too low or too high (limits: <10kg and >200kg)")
elif age > 99:
raise Exception("Age is too high (limit >99 years)")
elif impedance > 3000:
This file has been truncated. show original
La partie metric donne les % de gras, le BMR…
Testé et fonctionne.
La partie scale est une série de valeurs utilisées en interne.
Testé indirectement et fonctionne avec mes données.
La partie score, je n’ai pas compris ce que c’était
Je laisse tout car c’est long à convertir.
Ce bout de code sert de base :
Je n’ai pas amélioré le tout pour chercher les données dans un virtuel et alimenter un virtuel en retour,
Je n’ai pas fait de code qui cherche qui peut bien se peser,
Je n’ai testé qu’avec mes données, et j’ai comparé avec l’application Zepp,
Je n’ai pas d’environnement dédié PHP pour debuguer correctement.
Je verrai si j’ai l’envie et le temps d’aller plus loin en mode scénario.
Et pour finir, je renvoi sur une vidéo Youtube de Scilabus qui montre que l’indicateur IMC n’est qu’un indicateur :
Obésité, surpoids, normalité : quand l’IMC se trompe
Bon jeu
class Person {
public $age;
public $height;
public $sex;
public $weight;
public $impedance;
}
$person = new Person();
$person->age = 49; // Age
$person->height = 180; // Taille en cm
$person->sex = 'male'; // 'male' ou 'female'
$person->weight = 80; // poids en kg
$person->impedance = 460; // impedance
$person->scaleType = 'xiaomi';
// Metrics
$person->bmrCoef = round(getLBMCoefficient($person), 2);
$person->bmr = round(getBMR($person), 2);
$person->bodyfat = round(getFatPercentage($person), 2);
$person->water = round(getWaterPercentage($person), 2);
$person->bone = round(getBoneMass($person), 2);
$person->muscle = round(getMuscleMass($person), 2);
$person->visceral_fat = round(getVisceralFat($person), 2);
$person->bmi = round(getBMI($person), 2);
$person->protein = round(getProteinPercentage($person, True), 2);
$person->ideal = round(getIdealWeight($person, $orig=True), 2);
$person->metabolicAge = round(getMetabolicAge($person), 2);
$scenario->setLog('person:'.json_encode($person));
$fatPercentageScale = getFatPercentageScale($person);
$test = getBodyType($person->bodyfat, $person->muscle, $fatPercentageScale, $muscleMassScale);
$scenario->setLog('getBodyType:'.$test);
// Score
/*
$scale = getBmiDeductScore($person);
$scenario->setLog('getBmiDeductScore:'.$scale);
$scale = getBodyFatDeductScore($person);
$scenario->setLog('getBodyFatDeductScore:'.$scale);
$scale = getMuscleDeductScore($person);
$scenario->setLog('getMuscleDeductScore:'.$scale);
$scale = getWaterDeductScore($person);
$scenario->setLog('getWaterDeductScore:'.$scale);
$scale = getBoneDeductScore($person);
$scenario->setLog('getBoneDeductScore:'.$scale);
*/
//------------- bodyMetrics ----------
/**
* Set the value to a boundary if it overflows
*/
function checkValueOverflow($value, $minimum, $maximum) {
if ($value < $minimum) {
return $minimum;
} elseif ($value > $maximum) {
return $maximum;
} else {
return $value;
}
}
/**
* Get LBM coefficient (with impedance)
*/
function getLBMCoefficient($person) {
$lbm = ($person->height * 9.058 / 100) * ($person->height / 100);
$lbm += $person->weight * 0.32 + 12.226;
$lbm -= $person->impedance * 0.0068;
$lbm -= $person->age * 0.0542;
return $lbm;
}
/**
* Get BMR
*/
function getBMR($person) {
if ($person->sex == 'female') {
$bmr = 864.6 + $person->weight * 10.2036;
$bmr -= $person->height * 0.39336;
$bmr -= $person->age * 6.204;
} else {
$bmr = 877.8 + $person->weight * 14.916;
$bmr -= $person->height * 0.726;
$bmr -= $person->age * 8.976;
}
// Capping
if ($person->sex == 'female' && $bmr > 2996) {
$bmr = 5000;
} elseif ($person->sex == 'male' && $bmr > 2322) {
$bmr = 5000;
}
return checkValueOverflow($bmr, 500, 10000);
}
/**
* Get fat percentage
*/
function getFatPercentage($person) {
// Set a constant to remove from LBM
if ($person->sex == 'female' && $person->age <= 49) {
$const = 9.25;
} elseif ($person->sex == 'female' && $person->age > 49) {
$const = 7.25;
} else {
$const = 0.8;
}
// Calculate body fat percentage
$LBM = getLBMCoefficient($person);
if ($person->sex == 'male' && $person->weight < 61) {
$coefficient = 0.98;
} elseif ($person->sex == 'female' && $person->weight > 60) {
$coefficient = 0.96;
if ($person->height > 160) {
$coefficient *= 1.03;
}
} elseif ($person->sex == 'female' && $person->weight < 50) {
$coefficient = 1.02;
if ($person->height > 160) {
$coefficient *= 1.03;
}
} else {
$coefficient = 1.0;
}
$fatPercentage = (1.0 - (((floatval($LBM) - $const) * $coefficient) / $person->weight)) * 100;
// Capping body fat percentage
if ($fatPercentage > 63) {
$fatPercentage = 75;
}
return checkValueOverflow($fatPercentage, 5, 75);
}
/**
* Get water percentage
*/
function getWaterPercentage($person) {
$fatPercentage = getFatPercentage($person);
$waterPercentage = (100 - $fatPercentage) * 0.7;
if ($waterPercentage <= 50) {
$coefficient = 1.02;
} else {
$coefficient = 0.98;
}
// Capping water percentage
if ($waterPercentage * $coefficient >= 65) {
$waterPercentage = 75;
}
return checkValueOverflow($waterPercentage * $coefficient, 35, 75);
}
/**
* Get bone mass
*/
function getBoneMass($person) {
if ($person->sex == 'female') {
$base = 0.245691014;
} else {
$base = 0.18016894;
}
$boneMass = ($base - (getLBMCoefficient($person) * 0.05158)) * -1;
if ($boneMass > 2.2) {
$boneMass += 0.1;
} else {
$boneMass -= 0.1;
}
// Capping boneMass
if ($person->sex == 'female' && $boneMass > 5.1) {
$boneMass = 8;
} elseif ($person->sex == 'male' && $boneMass > 5.2) {
$boneMass = 8;
}
return checkValueOverflow($boneMass, 0.5 , 8);
}
/**
* Get muscle mass
*/
function getMuscleMass($person) {
$fatPercentage = getFatPercentage($person);
$boneMass = getBoneMass($person);
$muscleMass = $person->weight - (($fatPercentage * 0.01) * $person->weight) - $boneMass;
// Capping muscle mass
if ($person->sex == 'female' && $muscleMass >= 84) {
$muscleMass = 120;
} elseif ($person->sex == 'male' && $muscleMass >= 93.5) {
$muscleMass = 120;
}
return checkValueOverflow($muscleMass, 10 ,120);
}
/**
* Get Visceral Fat
*/
function getVisceralFat($person) {
if ($person->sex == 'female') {
if ($person->weight > (13 - ($person->height * 0.5)) * -1) {
$subsubcalc = (($person->height * 1.45) + ($person->height * 0.1158) * $person->height) - 120;
$subcalc = $person->weight * 500 / $subsubcalc;
$vfal = ($subcalc - 6) + ($person->age * 0.07);
} else {
$subcalc = 0.691 + ($person->height * -0.0024) + ($person->height * -0.0024);
$vfal = ((($person->height * 0.027) - ($subcalc * $person->weight)) * -1) + ($person->age * 0.07) - $person->age;
}
} else {
if ($person->height < $person->weight * 1.6) {
$subcalc = (($person->height * 0.4) - ($person->height * ($person->height * 0.0826))) * -1;
$vfal = (($person->weight * 305) / ($subcalc + 48)) - 2.9 + ($person->age * 0.15);
} else {
$subcalc = 0.765 + $person->height * -0.0015;
$vfal = ((($person->height * 0.143) - ($person->weight * $subcalc)) * -1) + ($person->age * 0.15) - 5.0;
}
}
return checkValueOverflow($vfal, 1 ,50);
}
/**
* Get BMI
*/
function getBMI($person) {
return checkValueOverflow($person->weight/(($person->height/100)*($person->height/100)), 10, 90);
}
/**
* Get ideal weight (just doing a reverse BMI, should be something better)
*/
function getIdealWeight($person, $orig=True) {
if ($orig && $person->sex == 'female') {
return ($person->height - 70) * 0.6;
} elseif ($orig && $person->sex == 'male') {
return ($person->height - 80) * 0.7;
} else {
return checkValueOverflow((22*$person->height)*$person->height/10000, 5.5, 198);
}
}
/**
* Get fat mass to ideal (guessing mi fit formula)
*/
function getFatMassToIdeal($person, $fatPercentage, $fatPercentageScale) {
$mass = ($person->weight * ($fatPercentage / 100)) - ($person->weight * ($fatPercentageScale[2] / 100));
if ($mass < 0) {
return ['type' => 'to_gain', 'mass' => $mass*-1];
} else {
return ['type' => 'to_lose', 'mass' => $mass];
}
}
/**
* Get protetin percentage (warn: guessed formula)
*/
function getProteinPercentage($person, $orig=True) {
if ($orig) {
$proteinPercentage = ($person->muscle / $person->weight) * 100;
$proteinPercentage -= $person->water;
} else {
$proteinPercentage = 100 - (floor($person->bodyfat * 100) / 100);
$proteinPercentage -= floor($person->water * 100) / 100;
$proteinPercentage -= floor(($person->bone/$person->weight*100) * 100) / 100;
}
return checkValueOverflow($proteinPercentage, 5, 32);
}
/**
* Get body type (out of nine possible)
*/
function getBodyType($fatPercentage, $muscleMass, $fatPercentageScale, $muscleMassScale) {
if ($fatPercentage > $fatPercentageScale[2]) {
$factor = 0;
} elseif ($fatPercentage < $fatPercentageScale[1]) {
$factor = 2;
} else {
$factor = 1;
}
if ($muscleMass > $muscleMassScale[1]) {
return 2 + ($factor * 3);
} elseif ($muscleMass < $muscleMassScale[0]) {
return ($factor * 3);
} else {
return 1 + ($factor * 3);
}
}
/**
* Get Metabolic Age
*/
function getMetabolicAge($person) {
if ($person->sex == 'female') {
$metabolicAge = ($person->height * -1.1165) + ($person->weight * 1.5784) + ($person->age * 0.4615) + ($person->impedance * 0.0415) + 83.2548;
} else {
$metabolicAge = ($person->height * -0.7471) + ($person->weight * 0.9161) + ($person->age * 0.4184) + ($person->impedance * 0.0517) + 54.2267;
}
return checkValueOverflow($metabolicAge, 15, 80);
}
//----------------------------------
//-------- body_scales ---------
/**
* Get BMI scale
*/
function getBMIScale($scaleType) {
if ($scaleType == 'xiaomi') {
return [18.5, 25.0, 28.0, 32.0];
} elseif ($scaleType == 'holtek') {
return [18.5, 25.0, 30.0];
}
}
/**
* Get fat percentage scale
*/
function getFatPercentageScale($person) {
if ($person->scaleType == 'xiaomi') {
$scales = [
['min' => 0, 'max' => 11, 'female' => [12.0, 21.0, 30.0, 34.0], 'male' => [7.0, 16.0, 25.0, 30.0]],
['min' => 12, 'max' => 13, 'female' => [15.0, 24.0, 33.0, 37.0], 'male' => [7.0, 16.0, 25.0, 30.0]],
['min' => 14, 'max' => 15, 'female' => [18.0, 27.0, 36.0, 40.0], 'male' => [7.0, 16.0, 25.0, 30.0]],
['min' => 16, 'max' => 17, 'female' => [20.0, 28.0, 37.0, 41.0], 'male' => [7.0, 16.0, 25.0, 30.0]],
['min' => 18, 'max' => 39, 'female' => [21.0, 28.0, 35.0, 40.0], 'male' => [11.0, 17.0, 22.0, 27.0]],
['min' => 40, 'max' => 59, 'female' => [22.0, 29.0, 36.0, 41.0], 'male' => [12.0, 18.0, 23.0, 28.0]],
['min' => 60, 'max' => 100, 'female' => [23.0, 30.0, 37.0, 42.0], 'male' => [14.0, 20.0, 25.0, 30.0]],
];
}
foreach ($scales as $scale) {
if ($person->age >= $scale['min'] && $person->age <= $scale['max']) {
return $scale[$person->sex];
}
}
}
/**
* Get BMR scale
*/
function getMuscleMassScale($person) {
if ($person->scaleType == 'xiaomi') {
$scales = [
['min' => ['male' => 170, 'female' => 160], 'female' => [36.5, 42.6], 'male' => [49.4, 59.5]],
['min' => ['male' => 160, 'female' => 150], 'female' => [32.9, 37.6], 'male' => [44.0, 52.5]],
['min' => ['male' => 0, 'female' => 0], 'female' => [29.1, 34.8], 'male' => [38.5, 46.6]]
];
} elseif ($person->scaleType == 'holtek') {
$scales = [
['min' => ['male' => 170, 'female' => 170], 'female' => [36.5, 42.5], 'male' => [49.5, 59.4]],
['min' => ['male' => 160, 'female' => 160], 'female' => [32.9, 37.5], 'male' => [44.0, 52.4]],
['min' => ['male' => 0, 'female' => 0], 'female' => [29.1, 34.7], 'male' => [38.5, 46.5]]
];
}
foreach ($scales as $scale) {
if ($person->height >= $scale['min'][$person->sex]) {
return $scale[$person->sex];
}
}
}
/**
* Get water percentage scale
*/
function getWaterPercentageScale($person) {
if ($person->scaleType == 'xiaomi') {
if ($person->sex == 'male') {
return [55.0, 65.1];
} elseif ($person->sex == 'female') {
return [45.0, 60.1];
}
} elseif ($person->scaleType == 'holtek') {
return [53, 67];
}
}
/**
* Get visceral fat scale
*/
function getVisceralFatScale() {
return [10.0, 15.0];
}
/**
* Get bone mass scale
*/
function getBoneMassScale($person) {
if ($person->scaleType == 'xiaomi') {
$scales = [
['male' => ['min' => 75.0, 'scale' => [2.0, 4.2]], 'female' => ['min' => 60.0, 'scale' => [1.8, 3.9]]],
['male' => ['min' => 60.0, 'scale' => [1.9, 4.1]], 'female' => ['min' => 45.0, 'scale' => [1.5, 3.8]]],
['male' => ['min' => 0.0, 'scale' => [1.6, 3.9]], 'female' => ['min' => 0.0, 'scale' => [1.3, 3.6]]]
];
foreach ($scales as $scale) {
if ($person->weight >= $scale[$person->sex]['min']) {
return $scale[$person->sex]['scale'];
}
}
} elseif ($person->scaleType == 'holtek') {
$scales = [
['female' => ['min' => 60, 'optimal' => 2.5], 'male' => ['min' => 75, 'optimal' => 3.2]],
['female' => ['min' => 45, 'optimal' => 2.2], 'male' => ['min' => 69, 'optimal' => 2.9]],
['female' => ['min' => 0, 'optimal' => 1.8], 'male' => ['min' => 0, 'optimal' => 2.5]]
];
foreach ($scales as $scale) {
if ($person->weight >= $scale[$person->sex]['min']) {
return [$scale[$person->sex]['optimal']-1, $scale[$person->sex]['optimal']+1];
}
}
}
}
/**
* Get BMR scale
*/
function getBMRScale($person) {
if ($person->scaleType == 'xiaomi') {
$coefficients = [
'male' => [30 => 21.6, 50 => 20.07, 100 => 19.35],
'female' => [30 => 21.24, 50 => 19.53, 100 => 18.63]
];
} elseif ($person->scaleType == 'holtek') {
$coefficients = [
'female' => [12 => 34, 15 => 29, 17 => 24, 29 => 22, 50 => 20, 120 => 19],
'male' => [12 => 36, 15 => 30, 17 => 26, 29 => 23, 50 => 21, 120 => 20]
];
}
foreach ($coefficients[$person->sex] as $person->ageLimit => $coefficient) {
if ($person->age < $person->ageLimit) {
return [$person->weight * $coefficient];
}
}
}
/**
* Get protein scale (hardcoded in mi fit)
*/
function getProteinPercentageScale() {
return [16, 20];
}
/**
* Get ideal weight scale (BMI scale converted to weights)
*/
function getIdealWeightScale($person, $getBMIScale) {
$scale = [];
foreach ($getBMIScale() as $bmiScale) {
$scale[] = ($bmiScale*$person->height)*$person->height/10000;
}
return $scale;
}
/**
* Get Body Score scale
*/
function getBodyScoreScale() {
return [50.0, 60.0, 80.0, 90.0];
}
/**
* Return body type scale
*/
function getBodyTypeScale() {
return ['obese', 'overweight', 'thick-set', 'lack-exerscise', 'balanced', 'balanced-muscular', 'skinny', 'balanced-skinny', 'skinny-muscular'];
}
//----------------------------
//------------ Score --------------
function getMalus($person, $data, $min_data, $max_data, $max_malus, $min_malus = 0) {
$result = (($data - $max_data) / ($min_data - $max_data)) * floatval($max_malus - $min_malus);
if ($result >= 0.0) {
return $result;
}
return 0.0;
}
function getBmiDeductScore($person) {
if (!($person->height >= 90)) {
// "BMI is not reasonable
return 0.0;
}
$bmi_low = 15.0;
$bmi_verylow = 14.0;
$bmi_normal = 18.5;
$bmi_overweight = 28.0;
$bmi_obese = 32.0;
$fat_scale = getFatPercentageScale($person);
// Perfect range (bmi >= 18.5 and bodyfat not high for adults, bmi >= 15.0 for kids
if ($person->bmi >= 18.5 && $person->age >= 18 && $person->bodyfat < $fat_scale[2]) {
return 0.0;
} elseif ($person->bmi >= $bmi_verylow && $person->age < 18 && $person->bodyfat < $fat_scale[2]) {
return 0.0;
}
// Extremely skinny (bmi < 14)
elseif ($person->bmi <= $bmi_verylow) {
return 30.0;
}
// Too skinny (bmi between 14 and 15)
elseif ($person->bmi > $bmi_verylow && $person->bmi < $bmi_low) {
return getMalus($person, $bmi_verylow, $bmi_low, 30, 15) + 15.0;
}
// Skinny (for adults, between 15 and 18.5)
elseif ($person->bmi >= $bmi_low && $person->bmi < $bmi_normal && $person->age >= 18) {
return getMalus($person, 15.0, 18.5, 15, 5) + 5.0;
}
// Normal or high bmi but too much bodyfat
elseif (($person->bmi >= $bmi_low && $person->age < 18) || ($person->bmi >= $bmi_normal && $person->age >= 18) && $person->bodyfat >= $fat_scale[2]) {
// Obese
if ($person->bmi >= $bmi_obese) {
return 10.0;
}
// Overweight
if ($person->bmi > $bmi_overweight) {
return getMalus($person, 28.0, 25.0, 5, 10) + 5.0;
} else {
return 0.0;
}
}
}
function getBodyFatDeductScore($person) {
$scale = getFatPercentageScale($person);
if ($person->sex == 'male') {
$best = $scale[2] - 3.0;
} elseif ($person->sex == 'female') {
$best = $scale[2] - 2.0;
}
// Slighly low in fat or low part or normal fat
if ($person->bodyfat >= $scale[0] && $person->bodyfat < $best) {
return 0.0;
} elseif ($person->bodyfat >= $scale[3]) {
return 20.0;
} else {
// Sightly high body fat
if ($person->bodyfat < $scale[3]) {
return getMalus($person, $scale[3], $scale[2], 20, 10) + 10.0;
}
// High part of normal fat
elseif ($person->bodyfat <= $normal[2]) {
return getMalus($person, $scale[2], $best, 3, 9) + 3.0;
}
// Very low in fat
elseif ($person->bodyfat < $normal[0]) {
return getMalus($person, 1.0, $scale[0], 3, 10) + 3.0;
}
}
}
function getMuscleDeductScore($person) {
$scale = getMuscleMassScale($person);
// For some reason, there's code to return self.calculate(muscle, normal[0], normal[0]+2.0, 3, 5) + 3.0
// if your muscle is between normal[0] and normal[0] + 2.0, but it's overwritten with 0.0 before return
if ($person->muscle >= $scale[0]) {
return 0.0;
} elseif ($person->muscle < ($scale[0] - 5.0)) {
return 10.0;
} else {
return getMalus($person, $scale[0] - 5.0, $scale[0], 10, 5) + 5.0;
}
}
// No malus = normal or good; maximum malus (10.0) = less than normal-5.0;
// malus = between 5 and 10, on your water being between normal-5.0 and normal
function getWaterDeductScore($person) {
$scale = getWaterPercentageScale($person);
if ($person->water >= $scale[0]) {
return 0.0;
} elseif ($person->water <= ($scale[0] - 5.0)) {
return 10.0;
} else {
return getMalus($person, $scale[0] - 5.0, $scale[0], 10, 5) + 5.0;
}
}
function getVisceralFatDeductScore($person) {
$scale = getVisceralFatScale($person);
if ($person->visceral_fat < $scale[0]) {
// For some reason, the original app would try to
// return 3.0 if vfat == 8 and 5.0 if vfat == 9
// but i's overwritten with 0.0 anyway before return
return 0.0;
} elseif ($person->visceral_fat >= $scale[1]) {
return 15.0;
} else {
return getMalus($person->visceral_fat, $scale[1], $scale[0], 15, 10) + 10.0;
}
}
function getBoneDeductScore($person) {
$scale = getBoneMassScale($person);
if ($person->bone >= $scale[0]) {
return 0.0;
} elseif ($person->bone <= ($scale[0] - 0.3)) {
return 10.0;
} else {
return getMalus($person->bone, $scale[0] - 0.3, $scale[0], 10, 5) + 5.0;
}
}
function getBasalMetabolismDeductScore($person) {
// Get normal BMR
$normal = getBMRScale($person[0]);
if ($person->basal_metabolism >= $normal) {
return 0.0;
} elseif ($person->basal_metabolism <= ($normal - 300)) {
return 6.0;
} else {
// It's really + 5.0 in the app, but it's probably a mistake, should be 3.0
return getMalus($person, $normal - 300, $normal, 6, 3) + 5.0;
}
}
// Get protein percentage malus
function getProteinDeductScore($person) {
// low: 10,16; normal: 16,17
// Check limits
if ($person->protein > 17.0) {
return 0.0;
} elseif ($person->protein < 10.0) {
return 10.0;
} else {
// Return values for low proteins or normal proteins
if ($person->protein <= 16.0) {
return getMalus($person, 10.0, 16.0, 10, 5) + 5.0;
} elseif ($person->protein <= 17.0) {
return getMalus($person, 16.0, 17.0, 5, 3) + 3.0;
}
}
}