| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- var tz = require('moment-timezone');
- var calcMealCOB = require('../determine-basal/cob');
- function round(value, digits) {
- if (! digits) { digits = 0; }
- var scale = Math.pow(10, digits);
- return Math.round(value * scale) / scale;
- }
- function recentCarbs(opts, time) {
- var treatments = opts.treatments;
- var profile_data = opts.profile;
- if (typeof(opts.glucose) !== 'undefined') {
- var glucose_data = opts.glucose;
- }
- var carbs = 0;
- var nsCarbs = 0;
- var bwCarbs = 0;
- var journalCarbs = 0;
- var bwFound = false;
- var mealCarbTime = time.getTime();
- var lastCarbTime = 0;
- if (!treatments) return {};
- //console.error(glucose_data);
- var iob_inputs = {
- profile: profile_data
- , history: opts.pumphistory
- };
- var COB_inputs = {
- glucose_data: glucose_data
- , iob_inputs: iob_inputs
- , basalprofile: opts.basalprofile
- , mealTime: mealCarbTime
- };
- var mealCOB = 0;
- // this sorts the treatments collection in order.
- treatments.sort(function (a, b) {
- var aDate = new Date(tz(a.timestamp));
- var bDate = new Date(tz(b.timestamp));
- //console.error(aDate);
- return bDate.getTime() - aDate.getTime();
- });
- var carbsToRemove = 0;
- var nsCarbsToRemove = 0;
- var bwCarbsToRemove = 0;
- var journalCarbsToRemove = 0;
- var maxMealAbsorptionTime = 6;
- if (typeof(profile_data.maxMealAbsorptionTime) === 'number' && ! isNaN(profile_data.maxMealAbsorptionTime)) {
- maxMealAbsorptionTime = profile_data.maxMealAbsorptionTime;
- } else {
- console.error("Bad profile.maxMealAbsorptionTime:",profile_data.maxMealAbsorptionTime);
- }
- treatments.forEach(function(treatment) {
- var now = time.getTime();
- // consider carbs from up to the meal preference maxMealAbsorptionTime hours ago in calculating COB
- var carbWindow = now - maxMealAbsorptionTime * 60*60*1000;
- var treatmentDate = new Date(tz(treatment.timestamp));
- var treatmentTime = treatmentDate.getTime();
- if (treatmentTime > carbWindow && treatmentTime <= now) {
- if (treatment.carbs >= 1) {
- if (treatment.nsCarbs >= 1) {
- nsCarbs += parseFloat(treatment.nsCarbs);
- } else if (treatment.bwCarbs >= 1) {
- bwCarbs += parseFloat(treatment.bwCarbs);
- bwFound = true;
- } else if (treatment.journalCarbs >= 1) {
- journalCarbs += parseFloat(treatment.journalCarbs);
- } else {
- console.error("Treatment carbs unclassified:",treatment);
- }
- //console.error(treatment.carbs, maxCarbs, treatmentDate);
- carbs += parseFloat(treatment.carbs);
- COB_inputs.mealTime = treatmentTime;
- lastCarbTime = Math.max(lastCarbTime,treatmentTime);
- var myCarbsAbsorbed = calcMealCOB(COB_inputs).carbsAbsorbed;
- var myMealCOB = Math.max(0, carbs - myCarbsAbsorbed);
- if (typeof(myMealCOB) === 'number' && ! isNaN(myMealCOB)) {
- mealCOB = Math.max(mealCOB, myMealCOB);
- } else {
- console.error("Bad myMealCOB:",myMealCOB, "mealCOB:",mealCOB, "carbs:",carbs,"myCarbsAbsorbed:",myCarbsAbsorbed);
- }
- if (myMealCOB < mealCOB) {
- carbsToRemove += parseFloat(treatment.carbs);
- if (treatment.nsCarbs >= 1) {
- nsCarbsToRemove += parseFloat(treatment.nsCarbs);
- } else if (treatment.bwCarbs >= 1) {
- bwCarbsToRemove += parseFloat(treatment.bwCarbs);
- } else if (treatment.journalCarbs >= 1) {
- journalCarbsToRemove += parseFloat(treatment.journalCarbs);
- }
- } else {
- carbsToRemove = 0;
- nsCarbsToRemove = 0;
- bwCarbsToRemove = 0;
- }
- //console.error(carbs, carbsToRemove);
- //console.error("COB:",mealCOB);
- }
- }
- });
- // only include carbs actually used in calculating COB
- carbs -= carbsToRemove;
- nsCarbs -= nsCarbsToRemove;
- bwCarbs -= bwCarbsToRemove;
- journalCarbs -= journalCarbsToRemove;
- // calculate the current deviation and steepest deviation downslope over the last hour
- COB_inputs.ciTime = time.getTime();
- // set mealTime to 6h ago for Deviation calculations
- COB_inputs.mealTime = time.getTime() - maxMealAbsorptionTime * 60 * 60 * 1000;
- var c = calcMealCOB(COB_inputs);
- //console.error(c.currentDeviation, c.slopeFromMaxDeviation);
- // set a hard upper limit on COB to mitigate impact of erroneous or malicious carb entry
- if (typeof(profile_data.maxCOB) === 'number' && ! isNaN(profile_data.maxCOB)) {
- mealCOB = Math.min( profile_data.maxCOB, mealCOB );
- console.error("mealCOB: " + round(mealCOB,1) + " with maxCOB " + profile_data.maxCOB + "g and maxMealAbsorptionTime " + maxMealAbsorptionTime + "hrs.");
- } else {
- console.error("Bad profile.maxCOB:",profile_data.maxCOB);
- }
- // if currentDeviation is null or maxDeviation is 0, set mealCOB to 0 for zombie-carb safety
- if (typeof(c.currentDeviation) === 'undefined' || c.currentDeviation === null) {
- console.error("");
- console.error("Warning: setting mealCOB to 0 because currentDeviation is null/undefined");
- mealCOB = 0;
- }
- if (typeof(c.maxDeviation) === 'undefined' || c.maxDeviation === null) {
- console.error("");
- console.error("Warning: setting mealCOB to 0 because maxDeviation is 0 or undefined");
- mealCOB = 0;
- }
- return {
- carbs: Math.round( carbs * 1000 ) / 1000
- , nsCarbs: Math.round( nsCarbs * 1000 ) / 1000
- , bwCarbs: Math.round( bwCarbs * 1000 ) / 1000
- , journalCarbs: Math.round( journalCarbs * 1000 ) / 1000
- , mealCOB: Math.round( mealCOB )
- , currentDeviation: Math.round( c.currentDeviation * 100 ) / 100
- , maxDeviation: Math.round( c.maxDeviation * 100 ) / 100
- , minDeviation: Math.round( c.minDeviation * 100 ) / 100
- , slopeFromMaxDeviation: Math.round( c.slopeFromMaxDeviation * 1000 ) / 1000
- , slopeFromMinDeviation: Math.round( c.slopeFromMinDeviation * 1000 ) / 1000
- , allDeviations: c.allDeviations
- , lastCarbTime: lastCarbTime
- , bwFound: bwFound
- };
- }
- exports = module.exports = recentCarbs;
|