{"id":21540896,"url":"https://github.com/mariusae/tune","last_synced_at":"2026-03-06T02:13:42.368Z","repository":{"id":40973624,"uuid":"230709955","full_name":"mariusae/tune","owner":"mariusae","description":"Parameter tuning models for Loop","archived":false,"fork":false,"pushed_at":"2023-07-06T21:54:42.000Z","size":26,"stargazers_count":9,"open_issues_count":3,"forks_count":8,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-24T05:04:29.978Z","etag":null,"topics":["loop","t1d"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mariusae.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-29T06:02:14.000Z","updated_at":"2024-09-20T20:09:12.000Z","dependencies_parsed_at":"2024-11-24T06:02:14.634Z","dependency_job_id":null,"html_url":"https://github.com/mariusae/tune","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariusae%2Ftune","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariusae%2Ftune/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariusae%2Ftune/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mariusae%2Ftune/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mariusae","download_url":"https://codeload.github.com/mariusae/tune/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248154983,"owners_count":21056542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["loop","t1d"],"created_at":"2024-11-24T04:22:58.802Z","updated_at":"2026-03-06T02:13:37.341Z","avatar_url":"https://github.com/mariusae.png","language":"Python","readme":"# Loop parameter estimation\n\nTune implements parameter estimation for\n[Loop](https://github.com/LoopKit/Loop). Tune employs a simple \"basal\nand bolus\" model that can estimate basal rates, carb ratios, and\ninsulin sensitivities.\n\n## Web service\n\nThis repository includes a Google AppEngine service (deployed at\nhttps://tune.basal.io/) that accepts a user's historical data, trains\nthe model, and provides estimated parameters.\n\n## API\n\nThe web service can expose a number of models. Each model\nis named by its URI. For example, the \"standard\" model is reached\nvia the URL `https://tune.basal.io/standard`.\n\nModel handlers accept JSON-formatted POST requests with content-type\n\"application/json\". The JSON payload encodes a number of timelines,\nindexed by (Unix) timestamp. Each timeline has a type and parameters.\nTimeline values are delta encoded (the value is the difference from\nthe previous; the first value is the difference from 0). ~~Timeline values\nmay also be runlength encoded by specifying a 2-element array in place\nof the value: the first element is the value; the second the number of repetitions.\nRun length encoding is applied after delta encoding.~~\nMissing timeline values should be omitted; in particular,\nthe presence of NaN values is undefined.\n\nThe JSON content should have the following layout. Timelines should\nbe provided for insulin delivery, glucose readings, and carbohydrate\nentries.\n\n```\n{\n\t// Version indicates the version of the data schema to be used.\n\t// This informal layout document describes version 1.\n\t\"version\": 1,\n\n\t// Timezone is the timezone of all of the data. This is used to\n\t// compute the \"time of day\" in the model. (Note: currently the\n\t// model does not make any assumptions about, e.g., night-time vs.\n\t// day time, but it may in the future.)\n\t\"timezone\": \"US/Pacific\",\n\n\t// The smallest time interval for basal rate schedules, in seconds. (Optional.)\n\t\"minimum_time_interval\": 1800,\n\n\t// The maximum number of basal rate entries. (Optional.)\n\t\"maximum_schedule_item_count\": 48,\n\n\t// Allowable basal rate values. (Optional.)\n\t\"allowed_basal_rates\": [0, 0.05, 0.1, 0.15, 0.2, ...],\n\n\t// The parameters (see below) for basal insulin delivery.\n\t\"basal_insulin_parameters\": {\n\t\t\"delay\": 5.008907445178995,\n\t\t\"peak\": 65.17257836911605,\n\t\t\"duration\": 203.67999991629117\n\t},\n\n\t// Current parameter schedules: insulin_sensitivity_schedule,\n\t// basal_rate_schedule, and carb_ratio_schedule are the current\n\t// parameter schedules in use by the subject. Schedules are indexed\n\t// by time (minutes) since midnight.\n\t//\n\t// These schedules may be used to initialize model parameters. Some\n\t// models may attempt to \"fine-tune\" user-supplied parameters, while\n\t// others may attempt to build de novo parameter schedules.\n\n\t// The current insulin sensitivity schedule. Values are in mg/dL/U.\n\t\"insulin_sensitivity_schedule\": {\n\t\t\"index\": [360, 720, ...],\n\t\t\"values\": [140, 100, ...],\n\t},\n\n\t// The current carbohydrate ratio schedule. Values are in g/U.\n\t\"carb_ratio_schedule\": {\n\t\t\"index\": [0, 360, ...],\n\t\t\"values\": [25, 16, ...],\n\t},\n\n\t// The current basal rate schedule. Values are in U/h.\n\t\"basal_rate_schedule\": {\n\t\t\"index\": [360, ...],\n\t\t\"values\": [0.25, ...],\n\t}\n\n\t// Optional parameter specifying the allowable parameter tuning range.\n\t// If specified and greater than zero, it indicates the percentage of value\n\t// that should be considered the tunable range.\n\t\"tuning_limit\": 0.35,\n\n\t// Timelines contains time-indexed data for all features relevant to\n\t// modeling insulin and carbohydrate response.\n\t\"timelines\": [\n\t\t{\n\t\t\t// Basal insulin columns must specify the delay, peak, and\n\t\t\t// duration (all in minutes), parameterizing the insulin curves.\n\t\t\t// Each column value is the rate delivered at the provided time;\n\t\t\t// the duration given was the amount of time this basal rate was\n\t\t\t// delivered.\n\t\t\t\"type\": \"basal\",\n\t\t\t\"parameters\": {\n\t\t\t\t\"delay\": 6,\n\t\t\t\t\"peak\": 65,\n\t\t\t\t\"duration\": 200,\n\t\t\t},\n\t\t\t// Index is delta-encoded Unix timestamps.\n\t\t\t\"index\": [\n\t\t\t\t1576623834,\n\t\t\t\t300,\n\t\t\t\t300,\n\t\t\t\t...\n\t\t\t],\n\t\t\t// Basal insulin values are given in milliunits per hour (mU/h).\n\t\t\t\"values\": [\n\t\t\t\t500,\n\t\t\t\t100,\n\t\t\t\t-200,\n\t\t\t\t...\n\t\t\t],\n\t\t\t// Durations are given in seconds.\n\t\t\t\"durations\": [\n\t\t\t\t3600,\n\t\t\t\t120,\n\t\t\t\t...\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\t// Insulin columns must specify the delay, peak, and\n\t\t\t// duration (all in minutes), parameterizing the insulin\n\t\t\t// curves. Each column value is the amount delivered at\n\t\t\t// the indexed time.\n\t\t\t\"type\": \"insulin\",\n\t\t\t\"parameters\": {\n\t\t\t\t\"delay\": 6,\n\t\t\t\t\"peak\": 65,\n\t\t\t\t\"duration\": 200,\n\t\t\t},\n\t\t\t// Index is delta-encoded Unix timestamps.\n\t\t\t\"index\": [\n\t\t\t\t1576623834,\n\t\t\t\t300,\n\t\t\t\t300,\n\t\t\t\t300,\n\t\t\t\t...\n\t\t\t],\n\t\t\t// Basal insulin values are given in milliunits per hour (mU/h).\n\t\t\t\"values\": [\n\t\t\t\t50,\n\t\t\t\t100,\n\t\t\t\t60,\n\t\t\t\t...\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\t// Carb columns must specify the delay and duration of\n\t\t\t// absorption (both in minutes).\n\t\t\t\"type\": \"carb\",\n\t\t\t\"parameters\": {\n\t\t\t\t\"delay\": 15,\n\t\t\t\t\"duration\": 120,\n\t\t\t}\n\t\t\t\"index\": [\n\t\t\t\t1576623834,\n\t\t\t\t164,\n\t\t\t\t...\n\t\t\t],\n\t\t\t// Carb values are given in grams (g).\n\t\t\t\"values\": [\n\t\t\t\t10,\n\t\t\t\t-5,\n\t\t\t\t...\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"type\": \"glucose\"\n\t\t\t\"index\": [\n\t\t\t\t1576623834,\n\t\t\t\t300,\n\t\t\t\t300,\n\t\t\t\t...\n\t\t\t]\n\t\t\t// Glucose values are given in mg/dL.\n\t\t\t\"values\": [\n\t\t\t\t110,\n\t\t\t\t2,\n\t\t\t\t-4,\n\t\t\t\t...\n\t\t\t]\n\t\t}\n\t]\n}\n```\n\nAlternative encodings may be offered in the future allowing for a\nmore compact representation of values. (TODO: consider allowing for\ndelta-encoded values in this encoding too.) The current encoding\ncompresses (using gzip) to about 40kB for 3 months of data for my\ndaughter, with deliveries (almost) every 5 minutes, and the frequency\nof meals that can be attained only by 6 year-olds and ultra-marathon\nrunners. (Without delta encoding, the same content compresses to\nabout 100kB).\n\nOnce the model has been trained, the model handler returns the estimated\nparameters in a JSON-formatted body (content-type \"application/json\") with\nthe following layout:\n\n```\n{\n\t// The version corresponding to the output. This should always\n\t// be the same as in the request.\n\t\"version\": 1,\n\n\t// The timezone for which the time of day indices below are relative.\n\t// This should always be the same as in the request.\n\t\"timezone\": \"US/Pacific\",\n\n\t// Modeled parameters: insulin_sensitivity_schedule,\n\t// carb_ratio_schedule, and basal_rate_schedule. These are as in the\n\t// request. Each represents a schedule of parameters, indexed by\n\t// time (in minutes) relative to midnight.\n\t//\n\t// Each schedule specifies an index (whose values are minutes since\n\t// midnight) and a value vector, whose values depends on the\n\t// specific value type. The entries are sorted by start time. The\n\t// schedule is always complete: the value for one entry is valid\n\t// until the next entry. The last entry may span midnight: it always\n\t// ends at the time of the first entry.\n\n\t\"insulin_sensitivity_schedule\": {\n\t\t\"index\": [360, 720, ...]\n\t\t// The insulin sensitivity at 360 minutes past 00:00 (i.e.,\n\t\t// at 6am) is 119, at 720 minutes past 00:00 (noon)\n\t\t// it is 130,\n\t\t\"values\": [119, 130, ...],\n\t},\n\n\t// The computed carb ratios, in g/U.\n\t\"carb_ratio_schedule\": {\n\t\t\"index\": [0, ...],\n\t\t\"values\": [17.615762468879538, ...],\n\t},\n\n\t// The computed basal rates, in U/h.\n\t\"basal_rate_schedule\": {\n\t\t\"index\": [180, ...],\n\t\t\"values\": [0.3, ...],\n\t}\n\n\t// The training loss (goodness of fit) of the above parameters. This\n\t// is not interpretable by the user except by relative comparison:\n\t// Lower values indicate a better fit.\n\t\"training_loss\": 0.7105391088965228\n}\n```\n\nThese formats are implemented by the python module\n[codec.py](https://github.com/mariusae/tune/blob/master/codec.py).\n\n## Development\n\nThe AppEngine frontend is a [Flask](https://www.palletsprojects.com/p/flask/)\napplication. The Python module `main.py` implements the tuning service API;\nit can be run locally:\n\n```\n$ python3 main.py\n```\n\nThe project may also be deployed as an AppEngine server. Once you\nhave set up an AppEngine project, you can deploy it in the usual\nmanner, from the present directory:\n\n```\n$ gcloud app deploy\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmariusae%2Ftune","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmariusae%2Ftune","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmariusae%2Ftune/lists"}