updated body metrics formluas
This commit is contained in:
parent
c86adf6621
commit
419e4c8687
|
@ -1,6 +1,5 @@
|
|||
from math import floor
|
||||
|
||||
# Reverse engineered from the Mi Body Composition Scale's library, could also be used on some other scales such as iHealth
|
||||
from body_scales import bodyScales
|
||||
|
||||
class bodyMetrics:
|
||||
def __init__(self, weight, height, age, sex, impedance):
|
||||
|
@ -9,16 +8,25 @@ class bodyMetrics:
|
|||
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)")
|
||||
print("Height is too high (limit: >220cm) or scale is sleeping")
|
||||
sys.stderr.write('Height is over 220cm or scale is sleeping\n')
|
||||
exit()
|
||||
elif weight < 10 or weight > 200:
|
||||
raise Exception("Weight is either too low or too high (limits: <10kg and >200kg)")
|
||||
print("Weight is either too low or too high (limits: <10kg and >200kg) or scale is sleeping")
|
||||
sys.stderr.write('Weight is above 10kg or below 200kg or scale is sleeping\n')
|
||||
exit()
|
||||
elif age > 99:
|
||||
raise Exception("Age is too high (limit >99 years)")
|
||||
print("Age is too high (limit >99 years) or scale is sleeping")
|
||||
sys.stderr.write('Age is above 99 years or scale is sleeping\n')
|
||||
exit()
|
||||
elif impedance > 3000:
|
||||
raise Exception("Impedance is too high (limit >3000ohm)")
|
||||
print("Impedance is above 3000ohm or scale is sleeping")
|
||||
sys.stderr.write('Impedance is above 3000ohm or scale is sleeping\n')
|
||||
exit()
|
||||
|
||||
# Set the value to a boundary if it overflows
|
||||
def checkValueOverflow(self, value, minimum, maximum):
|
||||
|
@ -55,18 +63,6 @@ class bodyMetrics:
|
|||
bmr = 5000
|
||||
return self.checkValueOverflow(bmr, 500, 10000)
|
||||
|
||||
# Get BMR scale
|
||||
def getBMRScale(self):
|
||||
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}
|
||||
}
|
||||
|
||||
for age, coefficient in coefficients[self.sex].items():
|
||||
if self.age < age:
|
||||
return [self.weight * coefficient]
|
||||
break
|
||||
|
||||
# Get fat percentage
|
||||
def getFatPercentage(self):
|
||||
# Set a constant to remove from LBM
|
||||
|
@ -99,25 +95,6 @@ class bodyMetrics:
|
|||
fatPercentage = 75
|
||||
return self.checkValueOverflow(fatPercentage, 5, 75)
|
||||
|
||||
# Get fat percentage scale
|
||||
def getFatPercentageScale(self):
|
||||
# The included tables where quite strange, maybe bogus, replaced them with better ones...
|
||||
scales = [
|
||||
{'min': 0, 'max': 20, 'female': [18, 23, 30, 35], 'male': [8, 14, 21, 25]},
|
||||
{'min': 21, 'max': 25, 'female': [19, 24, 30, 35], 'male': [10, 15, 22, 26]},
|
||||
{'min': 26, 'max': 30, 'female': [20, 25, 31, 36], 'male': [11, 16, 21, 27]},
|
||||
{'min': 31, 'max': 35, 'female': [21, 26, 33, 36], 'male': [13, 17, 25, 28]},
|
||||
{'min': 46, 'max': 40, 'female': [22, 27, 34, 37], 'male': [15, 20, 26, 29]},
|
||||
{'min': 41, 'max': 45, 'female': [23, 28, 35, 38], 'male': [16, 22, 27, 30]},
|
||||
{'min': 46, 'max': 50, 'female': [24, 30, 36, 38], 'male': [17, 23, 29, 31]},
|
||||
{'min': 51, 'max': 55, 'female': [26, 31, 36, 39], 'male': [19, 25, 30, 33]},
|
||||
{'min': 56, 'max': 100, 'female': [27, 32, 37, 40], 'male': [21, 26, 31, 34]},
|
||||
]
|
||||
|
||||
for scale in scales:
|
||||
if self.age >= scale['min'] and self.age <= scale['max']:
|
||||
return scale[self.sex]
|
||||
|
||||
# Get water percentage
|
||||
def getWaterPercentage(self):
|
||||
waterPercentage = (100 - self.getFatPercentage()) * 0.7
|
||||
|
@ -132,10 +109,6 @@ class bodyMetrics:
|
|||
waterPercentage = 75
|
||||
return self.checkValueOverflow(waterPercentage * coefficient, 35, 75)
|
||||
|
||||
# Get water percentage scale
|
||||
def getWaterPercentageScale(self):
|
||||
return [53, 67]
|
||||
|
||||
# Get bone mass
|
||||
def getBoneMass(self):
|
||||
if self.sex == 'female':
|
||||
|
@ -157,18 +130,6 @@ class bodyMetrics:
|
|||
boneMass = 8
|
||||
return self.checkValueOverflow(boneMass, 0.5 , 8)
|
||||
|
||||
# Get bone mass scale
|
||||
def getBoneMassScale(self):
|
||||
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}}
|
||||
]
|
||||
|
||||
for scale in scales:
|
||||
if self.weight >= scale[self.sex]['min']:
|
||||
return [scale[self.sex]['optimal']-1, scale[self.sex]['optimal']+1]
|
||||
|
||||
# Get muscle mass
|
||||
def getMuscleMass(self):
|
||||
muscleMass = self.weight - ((self.getFatPercentage() * 0.01) * self.weight) - self.getBoneMass()
|
||||
|
@ -181,18 +142,6 @@ class bodyMetrics:
|
|||
|
||||
return self.checkValueOverflow(muscleMass, 10 ,120)
|
||||
|
||||
# Get muscle mass scale
|
||||
def getMuscleMassScale(self):
|
||||
scales = [
|
||||
{'min': 170, 'female': [36.5, 42.5], 'male': [49.5, 59.4]},
|
||||
{'min': 160, 'female': [32.9, 37.5], 'male': [44.0, 52.4]},
|
||||
{'min': 0, 'female': [29.1, 34.7], 'male': [38.5, 46.5]}
|
||||
]
|
||||
|
||||
for scale in scales:
|
||||
if self.height >= scale['min']:
|
||||
return scale[self.sex]
|
||||
|
||||
# Get Visceral Fat
|
||||
def getVisceralFat(self):
|
||||
if self.sex == 'female':
|
||||
|
@ -213,65 +162,61 @@ class bodyMetrics:
|
|||
|
||||
return self.checkValueOverflow(vfal, 1 ,50)
|
||||
|
||||
# Get visceral fat scale
|
||||
def getVisceralFatScale(self):
|
||||
return [10, 15]
|
||||
|
||||
# Get BMI
|
||||
def getBMI(self):
|
||||
return self.checkValueOverflow(self.weight/((self.height/100)*(self.height/100)), 10, 90)
|
||||
|
||||
# Get BMI scale
|
||||
def getBMIScale(self):
|
||||
# Replaced library's version by mi fit scale, it seems better
|
||||
return [18.5, 25, 28, 32]
|
||||
|
||||
# Get ideal weight (just doing a reverse BMI, should be something better)
|
||||
def getIdealWeight(self):
|
||||
return self.checkValueOverflow((22*self.height)*self.height/10000, 5.5, 198)
|
||||
|
||||
# Get ideal weight scale (BMI scale converted to weights)
|
||||
def getIdealWeightScale(self):
|
||||
scale = []
|
||||
for bmiScale in self.getBMIScale():
|
||||
scale.append((bmiScale*self.height)*self.height/10000)
|
||||
return scale
|
||||
def getIdealWeight(self, orig=True):
|
||||
# Uses mi fit algorithm (or holtek's one)
|
||||
if orig and self.sex == 'female':
|
||||
return (self.height - 70) * 0.6
|
||||
elif orig and self.sex == 'male':
|
||||
return (self.height - 80) * 0.7
|
||||
else:
|
||||
return self.checkValueOverflow((22*self.height)*self.height/10000, 5.5, 198)
|
||||
|
||||
# Get fat mass to ideal (guessing mi fit formula)
|
||||
def getFatMassToIdeal(self):
|
||||
mass = (self.weight * (self.getFatPercentage() / 100)) - (self.weight * (self.getFatPercentageScale()[2] / 100))
|
||||
mass = (self.weight * (self.getFatPercentage() / 100)) - (self.weight * (self.scales.getFatPercentageScale()[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)
|
||||
def getProteinPercentage(self):
|
||||
proteinPercentage = 100 - (floor(self.getFatPercentage() * 100) / 100)
|
||||
proteinPercentage -= floor(self.getWaterPercentage() * 100) / 100
|
||||
proteinPercentage -= floor((self.getBoneMass()/self.weight*100) * 100) / 100
|
||||
return proteinPercentage
|
||||
def getProteinPercentage(self, orig=True):
|
||||
# Use original algorithm from mi fit (or legacy guess one)
|
||||
if orig:
|
||||
proteinPercentage = (self.getMuscleMass() / self.weight) * 100
|
||||
proteinPercentage -= self.getWaterPercentage()
|
||||
else:
|
||||
proteinPercentage = 100 - (floor(self.getFatPercentage() * 100) / 100)
|
||||
proteinPercentage -= floor(self.getWaterPercentage() * 100) / 100
|
||||
proteinPercentage -= floor((self.getBoneMass()/self.weight*100) * 100) / 100
|
||||
|
||||
# Get protein scale (hardcoded in mi fit)
|
||||
def getProteinPercentageScale(self):
|
||||
return [16, 20]
|
||||
return self.checkValueOverflow(proteinPercentage, 5, 32)
|
||||
|
||||
# Get body type (out of nine possible)
|
||||
def getBodyType(self):
|
||||
if self.getFatPercentage() > self.getFatPercentageScale()[2]:
|
||||
if self.getFatPercentage() > self.scales.getFatPercentageScale()[2]:
|
||||
factor = 0
|
||||
elif self.getFatPercentage() < self.getFatPercentageScale()[1]:
|
||||
elif self.getFatPercentage() < self.scales.getFatPercentageScale()[1]:
|
||||
factor = 2
|
||||
else:
|
||||
factor = 1
|
||||
|
||||
if self.getMuscleMass() > self.getMuscleMassScale()[1]:
|
||||
if self.getMuscleMass() > self.scales.getMuscleMassScale()[1]:
|
||||
return 2 + (factor * 3)
|
||||
elif self.getMuscleMass() < self.getMuscleMassScale()[0]:
|
||||
elif self.getMuscleMass() < self.scales.getMuscleMassScale()[0]:
|
||||
return (factor * 3)
|
||||
else:
|
||||
return 1 + (factor * 3)
|
||||
|
||||
# Return body type scale
|
||||
def getBodyTypeScale(self):
|
||||
return ['obese', 'overweight', 'thick-set', 'lack-exerscise', 'balanced', 'balanced-muscular', 'skinny', 'balanced-skinny', 'skinny-muscular']
|
||||
# Get Metabolic Age
|
||||
def getMetabolicAge(self):
|
||||
if self.sex == 'female':
|
||||
metabolicAge = (self.height * -1.1165) + (self.weight * 1.5784) + (self.age * 0.4615) + (self.impedance * 0.0415) + 83.2548
|
||||
else:
|
||||
metabolicAge = (self.height * -0.7471) + (self.weight * 0.9161) + (self.age * 0.4184) + (self.impedance * 0.0517) + 54.2267
|
||||
return self.checkValueOverflow(metabolicAge, 15, 80)
|
||||
|
|
Loading…
Reference in a new issue