Morbidostat PID algorithm, tuning, and suggestions

I have been playing around with the PID morbidostat, and it’s quite fun. I think some support for tuning the parameters might be nice to add. As is, the defaults are likely to be a bit aggressive, and I would bet many users would appreciate some guidance.

Following Zhong 2020, we could try a Ziegler-Nichols approach. Automating this with experimental profiles should be feasible. Maybe ramping Kp up by 0.5 or 1 every X hours, then checking for oscillations at each point. Automatic parameter inference would be nice, and I think pretty simple algorithmically, but seems like it would require a script.

I am also thinking about how best to handle dilution event rates, target growth rates, and their interactions. The eVOLVER paper used 1 hour, but with yeast and targeting 6 hour doubling times. Should dilution events be a function of growth rate?

A few minor suggestions, too:

  1. In the case where the alternative media is dosing a known concentration of some substrate, it would be nice for the chart to display calculated substrate concentrations rather than fractions.

  2. PID outputs should maybe be capped to that there are minimums for media dispensing. That is, I had some dosing events require 0.04 mL, which seems unrealistically low. Maybe using minimum calculated dispensing times is the best way to go?

  3. Support for sampling from the vial would be great. Keeping track of media levels is great, but if I remove a mL and try to add 1 mL of fresh media the internal state gets confused. Also, the alt media calculations will end up (slightly) off, as well.

It’s soooo coool though, we’re having a blast and can’t wait to order a few more! I am hoping to supply some of these myself, if possible, but wanted to post the feedback in case anyone else was thinking about this.

Hi @chri-s,

Glad you’re having fun!

The Morbidostat’s PID parameters are mostly placeholders - the best values are going to depend on the users culture, media, concentration, etc. I will make a note in the docs to say that the parameters should be updated. Using a script is a great idea! I’ll think more about that.

Aren’t they already? The amount of media vs other media introduced is a function of the growth rate. Do you mean frequency of dosing? Yea, there’s no interaction between growth rate and frequency of dosing, but it would make sense since as gr increases, then you’ll need to dose more often (both to constrain the gr and to lower the OD).

I really like your suggestions - I may start implementing some of those soon…

I think this is possible now, but with knowledge of some internal bits. Maybe this comes out-of-the-box-ready later. But here’s how you can do this using our Charts protocol (skip the docs, just do the below for now):

  1. Create a file called, for example, concentration_in_vial.yaml in the folder /home/pioreactor/.pioreactor/plugins/ui/contrib/charts/. Add the following to the file:
---
chart_key: concentration_in_vial
data_source: alt_media_fractions
title: "Concentration of X in vial"
data_source_column: alt_media_fraction
mqtt_topic: dosing_automation/alt_media_fraction
source: app
y_axis_label: concentration
interpolation: stepAfter
y_axis_domain: [0.00, 0.05]
lookback: 100000
fixed_decimals: 3
y_transformation: "(y) => 0.001 * y" # change 0.001 to your alt media's known concentration of substrate

Save and exit.

  1. In your config.ini, adding the following under ui.overview.charts:
[ui.overview.charts]
...
concentration_in_vial=1

Hit [Save].

  1. Refresh the overview page. There may be a cache, so wait like 20 to 30s.

What we are doing is converting the fraction of alt-media to concentration of substrate via a y-axis transformation. (I may be an idiot, but I believe it’s linear transformation from fraction to concentration, like I have above in y_transformation).

You could even make the concentration a config parameter:

y_transformation: "(y) => parseFloat(config['dosing_automation.pid_morbidostat']['concentration']) * y"

Just add a concentration parameter under dosing_automation.pid_morbidostat in your config.ini. I think that would work…

Perfect - I was going to fiddle with charts once I got some free time, but you beat me to it. Yeah, it should be linear: if the starting media has a non-zero concentration, presumably just adding a constant to y_transformation should work.

Playing around a bit more, this would be tricky to implement. As a first go, a simple turbidostat with stepped increases in alt-media fraction might be simplest to try to ballpark dose-response ranges. I made an experiment for that, but having some simple analysis of growth rate as a function of alt-media fraction might be nice. Perhaps a good first chart to whip up!

Yeah, I meant dosing frequency. I can see an argument for having it both ways, but it might be neat to dose with respect to generations rather than wall time. Probably unnecessary, but it might be a neat trick…

In the latest release, 23.6.7, we added two things that may help:

  • PIDMorbidostat has a configuration parameter [dosing_automation.pid_morbidostat] minimum_dosing_volume_ml (default 0.1). If a calculated volume to be dosed is less than this parameter, then it’s set to 0.0 instead. Example:
[dosing_automation.pid_morbidostat]
Kp=5
Ki=0
Kd=0
minimum_dosing_volume_ml=0.25
  • A way to add manual adjustments, under the Dosing tab.

Happy to hear any feedback on these!

These seem perfect! I will update to give these a try.