def test_compute_iob_single_step_net(): """ Test IOB computing for a net insulin profile with a single step. """ # Define a DIA DIA = 3.0 # Get an IDC walsh = idc.WalshIDC(DIA) # Create net insulin profile netInsulin = net.Net() netInsulin.t = np.array([-DIA, 0]) netInsulin.y = np.array([1, 1]) # Define integral over single step walshIntegrals = np.array([1.45532, 0]) expectedIOB = np.sum(netInsulin.y * walshIntegrals) IOB = calculator.computeIOB(netInsulin, walsh) assert isEqual(IOB, expectedIOB) # Redefine net insulin profile that corresponds to only scheduled basals # (there should be no insulin on board) netInsulin.t = np.array([-DIA, 0]) netInsulin.y = [0, 0] expectedIOB = 0 IOB = calculator.computeIOB(netInsulin, walsh) assert isEqual(IOB, expectedIOB)
def computeIOBs(t, T, Net, IDC): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ COMPUTEIOBS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This function computes the IOB at a given time. """ # Initialize IOBs IOBs = [] # Compute IOB for each BG for i in range(len(T)): # Copy net insulin profile net_ = copy.deepcopy(Net) # Cut it for current IOB computation start = T[i] - datetime.timedelta(hours=IDC.DIA) end = T[i] net_.cut(start, end) net_.normalize() # Compute corresponding IOB, store, and show it IOB = calculator.computeIOB(net_, IDC) IOBs += [IOB] print "IOB(" + lib.formatTime(end) + ") = " + fmt.IOB(IOB) return IOBs
def computeExpectedBGDeltas(t, T, Net, IDC, ISFs): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ COMPUTEEXPECTEDBGDELTAS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This function computes an array of expected BG variations, given an IDC and a net insulin profile. """ # Initialize expected BG deltas expectedDeltaBGs = [] # Compute expected BG deltas for i in range(len(T) - 1): # Copy net insulin profile net_ = copy.deepcopy(Net) # Cut it for current IOB computation start = T[i] - datetime.timedelta(hours=IDC.DIA) end = T[i] net_.cut(start, end) net_.normalize() # Compute corresponding IOB IOB0 = calculator.computeIOB(net_, IDC) # Move net insulin profile into the past by the time that passes until # next BG value dt = t[i + 1] - t[i] net_.shift(-dt) # Compute new IOB, and the difference with the last one IOB1 = calculator.computeIOB(net_, IDC) dIOB = IOB1 - IOB0 # Get current ISF and compute dBG using dIOB # NOTE: there might be some error slipping in here if ISF changes # between the two IOBs ISF = ISFs.f(t[i]) dBG = dIOB * ISF # Store and show expected BG delta expectedDeltaBGs += [dBG] print "dBG(" + lib.formatTime(start) + ") = " + fmt.BG(dBG) return expectedDeltaBGs
def build(self, net, IDC, dt, show=False): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BUILD ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Build prediction profile of IOB decay. """ # Info Logger.debug("Building 'FutureIOB'...") # Reset components self.reset() # Define time references self.define(net.end, IDC.DIA, dt) # Copy net insulin profile net = copy.deepcopy(net) # Compute IOB decay for _ in self.t: # Compute new IOB and store it self.y += [calculator.computeIOB(net, IDC)] # Move net insulin profile into the past (only normalized axis is # needed for IOB computation) net.shift(-self.dt) # Derivate self.derivate() # Store current IOB self.store() # Show if show: self.show()
def test_compute_iob_multiple_steps_net(): """ Test IOB computing for a net insulin profile with multiple steps. """ # Define a DIA DIA = 3.0 # Get an IDC walsh = idc.WalshIDC(DIA) # Create net insulin profile netInsulin = net.Net() netInsulin.t = np.array([-DIA, -2, -1, 0]) netInsulin.y = np.array([2, -0.5, 3, 1]) # Define part integrals (one for each step) walshIntegrals = np.array([0.129461, 0.444841, 0.881021, 0]) expectedIOB = np.sum(netInsulin.y * walshIntegrals) IOB = calculator.computeIOB(netInsulin, walsh) assert isEqual(IOB, expectedIOB)
def build(self, past, net, IDC, futureISF, dt, show=False): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BUILD ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Predict natural IOB decay and compute resulting BG variation at the same time, using ISF profile and IDC. The formula used to compute it is given by: dBG = SUM_t' ISF(t') * dIOB(t') where t' represents the value of a given time step, dIOB(t') the drop in active insuline (IOB) during that time, and ISF(t') the corresponding insulin sensitivity factor. The variation in BG after the end of insulin activity is given by dBG. """ # Info Logger.debug("Building 'FutureBG'...") Logger.debug("Step size: " + str(self.dt) + " h") # Ensure there is one BG recent enough to accurately predict decay calculator.countValidBGs(past, 15, 1) # Reset previous BG predictions self.reset() # Define time references self.define(net.end, IDC.DIA, dt) # Initialize BG BG = past.y[-1] # Store initial (most recent) BG self.y.append(BG) # Copy net insulin profile net = copy.deepcopy(net) # Compute initial IOB IOBs = [calculator.computeIOB(net, IDC)] # Compute dBG for i in range(len(self.t) - 1): # Compute start/end of current step [t0, t1] = [self.t[i], self.t[i + 1]] # Generate time axis associated with ISF changes over current step t = [t0] t += list(filter(lambda t_: t0 < t_ < t1, futureISF.t)) t += [t1] # Loop on ISF changes for j in range(len(t) - 1): # Move net insulin profile into the past dt = t[j + 1] - t[j] net.shift(-dt) # Compute new IOB and difference with last one IOB = calculator.computeIOB(net, IDC) dIOB = IOB - IOBs[-1] IOBs += [IOB] # Compute dBG for current step and corresponding expected BG dBG = futureISF.f(t[j]) * dIOB BG += dBG # Store BG at end of current step self.y += [BG] # Derivate self.derivate() # Show if show: self.show()
def autosens(self, now, t = 24): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AUTOSENS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Define past reference time past = now - datetime.timedelta(hours = t) # Define DIA as a datetime timedelta object dia = datetime.timedelta(hours = self.DIA) # Instanciate profiles profiles = {"IDC": IDC.WalshIDC(self.DIA), "Suspend": None, "Resume": None, "Basal": None, "TB": None, "Bolus": None, "Net": None, "ISF": ISF.ISF(), "PastBG": BG.PastBG()} # Build past BG profile profiles["PastBG"].build(past, now) # Build past ISF profile profiles["ISF"].build(past, now) # Reference to BG time axis T = profiles["PastBG"].T # Initialize IOB arrays IOBs = [] # Get number of BGs n = len(T) # Compute IOB for each BG for i in range(n): # Reset necessary profiles profiles["Suspend"] = suspend.Suspend() profiles["Resume"] = resume.Resume() profiles["Basal"] = basal.Basal() profiles["TB"] = TB.TB() profiles["Bolus"] = bolus.Bolus() profiles["Net"] = net.Net() # Build net insulin profile profiles["Net"].build(T[i] - dia, T[i], profiles["Suspend"], profiles["Resume"], profiles["Basal"], profiles["TB"], profiles["Bolus"]) # Do it IOBs.append(calc.computeIOB(profiles["Net"], profiles["IDC"])) # Show IOB print "IOB(" + lib.formatTime(T[i]) + ") = " + fmt.IOB(IOBs[-1])
def build(self, dt, net, IDC, futureISF, past): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BUILD ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Predict natural IOB decay and compute resulting BG variation at the same time, using ISF profile and IDC. The formula used to compute it is given by: dBG = SUM_t' ISF(t') * dIOB(t') where t' represents the value of a given time step, dIOB(t') the drop in active insuline (IOB) during that time, and ISF(t') the corresponding insulin sensitivity factor. The variation in BG after the end of insulin activity is given by dBG. """ # Give user info Logger.debug("Building 'FutureBG'...") # Ensure there is one BG recent enough to accurately predict decay calc.countValidBGs(past, 15, 1) # Initialize BG BG = past.y[-1] # Give user info Logger.debug("Step size: " + str(self.dt) + " h") Logger.debug("Initial BG: " + str(BG) + " " + self.units) # Reset previous BG predictions self.reset() # Define time references self.define(net.end, IDC.DIA, dt) # Store initial (most recent) BG self.y.append(BG) # Copy net insulin profile net = copy.deepcopy(net) # Compute initial IOB IOB0 = calc.computeIOB(net, IDC) # Read number of steps in prediction n = len(self.t) - 1 # Read number of entries in net insulin profile m = len(net.t) # Read number of entries in ISF profile l = len(futureISF.t) # Compute dBG for i in range(n): # Compute start/end of current step t0 = self.t[i] t1 = self.t[i + 1] # Initialize time axis associated with ISF changes t = [] # Define start time t.append(t0) # Fill it with ISF change times for j in range(l): # Change contained within current step if t0 < futureISF.t[j] < t1: # Add it t.append(futureISF.t[j]) # Define end time t.append(t1) # Loop on ISF changes for j in range(len(t) - 1): # Define step dt = t[j + 1] - t[j] # Move net insulin profile into the past for k in range(m): # Update normalized time axis net.t[k] -= dt # Compute new IOB IOB = calc.computeIOB(net, IDC) # Compute dIOB dIOB = IOB - IOB0 # Update IOB IOB0 = IOB # Compute dBG for current step dBG = futureISF.f(t[j]) * dIOB # Compute expected BG BG += dBG # Store BG at end of current step self.y.append(BG) # Normalize self.normalize() # Derivate self.derivate() # Show self.show()