Last active
September 27, 2024 15:45
-
-
Save kenwebb/a2b7b95d7f13435e01ad6e9994a51fb4 to your computer and use it in GitHub Desktop.
Negative Feedback - Simplest Models
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Fri Sep 27 2024 11:44:54 GMT-0400 (Eastern Daylight Time)--> | |
<XholonWorkbook> | |
<Notes><![CDATA[ | |
Xholon | |
------ | |
Title: Negative Feedback - Simplest Models | |
Description: | |
Url: http://www.primordion.com/Xholon/gwt/ | |
InternalName: a2b7b95d7f13435e01ad6e9994a51fb4 | |
Keywords: | |
My Notes | |
-------- | |
24 Sept 2024 | |
- see also: "Homeostasis - Glucose Control" 1d0923799df30043a46fb9e198630ac5 | |
26 Sept | |
- see especially in this workbook: SdSystem_p26_4 | |
- this is basically the approach I am trying to develop | |
### Negative Feedback - Simplest Models | |
--------------------------------------- | |
https://duckduckgo.com/?q=simple+negative+feedback+loop+example+models&t=ffab&ia=web | |
https://ocw.mit.edu/courses/15-988-system-dynamics-self-study-fall-1998-spring-1999/a17d3c9414d13bd64cf93b0bdae91695_negative.pdf | |
https://ocw.mit.edu/courses/15-988-system-dynamics-self-study-fall-1998-spring-1999/51ed11ad9743d9f83ecdc00637f4f32f_genericnegative.pdf | |
- look at ~/Documents for system dynamics stuff; molecules? | |
~/Documents/fromZBook/old/Primordion/SystemDynamics/ | |
Donella Meadows | |
- Thinking in Systems | |
- my bathtub, pail models | |
### 25 Sept | |
#### Flow | |
- Flow's ONLY job should be to move stuff from Cloud to Stock or from Stock to Cloud or from Stock to Stock | |
- it should NEVER stop doing this unless a control system somehow prevents it from doing this | |
- it is NOT Flow's responsibility to self-control | |
- BUT I could design Flow so that it has an ON state and an OFF state; or ENABLED/DISABLED | |
- or it could be manipulated in some other way so that it is unable to function: a child node, a port that can be unlinked, etc. | |
- Blood Glucose Homeostasis used Insulin and Glucagon as message signals; their presence (whether or not these hormones are binding) controls what happens | |
- a simple way to disable it is for the control system to change flow.cloud or flow.stock to point to different objects whose amount values equal 0 or whatever | |
- BUT, what would be a way that is most consistent with how biology works? | |
- the Biology approach is physical, the physical existence of hormones and other signaling molecules | |
- things that can combine with other things; things that can change the shape of other things | |
- SO, I will use "hormones" such as HrOne, HrTwo, etc. | |
- the existence or not of these things can be used in JavaScript if and conditional statements | |
- and these things can be added, removed, moved etc. by elements of the control system | |
- best approach is to add child(ren) inside Flow | |
- it's OK that Flow will need to be a single if/conditional to determine if it has that child | |
- like having a recepter in a membrane | |
- DONE | |
### References | |
(1) Donella H. Meadows, Thinking in Systems | |
]]></Notes> | |
<_-.XholonClass> | |
<NegFeedbackSystem/> | |
<!-- Homeostasis parts, roles played by the physical parts; from "Homeostasis - Glucose Control" | |
I may or may not use these in this model | |
--> | |
<Stimulus/> | |
<Receptor/> <!-- sensor --> | |
<ControlCenter superClass="Script"/> | |
<Signal> | |
<EfferentSignal/> | |
</Signal> | |
<Effector/> | |
<SetPoint/> <!-- ex: blood needs to maintain a constant glucose level; a range; 90 mg per 100 ml of blood --> | |
<Homeostasis/> <!-- not sure if I can use this directly --> | |
<!-- ref[1] p. 26 --> | |
<SdEnvironment/> | |
<SdSystem/> <!-- a System Dynamics system --> | |
<SdControlSystem/> <!-- a System Dynamics control system --> | |
<Stock/> | |
<Flow superClass="Script"/> | |
<Cloud/> <!-- a source or sink in the environment; external to the system --> | |
<!-- hormone-like nodes, for signaling and control, Neg Feedback System (Nfs) hormones --> | |
<NfsHormone> | |
<HrOne/> | |
<HrTwo/> | |
<HrEtc/> | |
<!-- the following 2 are real hormones made in the Pancreas --> | |
<HrInsulin/> | |
<HrGlucagon/> | |
</NfsHormone> | |
<ChatGpt01 superClass="Script"/> | |
</_-.XholonClass> | |
<xholonClassDetails> | |
<Stock xhType="XhtypePurePassiveObject"/> | |
<Cloud xhType="XhtypePurePassiveObject"/> | |
<!-- set defaults for Script classes to make those classes usable in ObjFuncMapper NOT SURE IF THIS WORKS - it does work! --> | |
<Flow><DefaultContent>var beh = {postConfigure: function() {}}</DefaultContent></Flow> | |
<ControlCenter><DefaultContent>var beh = {postConfigure: function() {}}</DefaultContent></ControlCenter> | |
</xholonClassDetails> | |
<NegFeedbackSystem> | |
SdSystem_p26_1 | |
<SdSystem roleName="SdSystem_p26_1"> | |
<Cloud roleName="source" amount="1000"/> | |
<Flow roleName="inflow"><![CDATA[ | |
var me, cloud, stock, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
cloud = me.xpath("../Cloud"); | |
stock = me.xpath("../Stock"); | |
setpoint = Math.floor(Math.random() * 501); // a number between 0 and 500 | |
me.print(`${cloud.name()} --> ${me.name()} --> ${stock.name()} setpoint (goal):${setpoint}`); | |
me.println(` ${cloud.amount} ${stock.amount}`); | |
}, | |
act: function() { | |
stock.amount < setpoint ? (cloud.amount-- && stock.amount++) : null; | |
me.println(`1) ${cloud.amount} ${stock.amount}`); | |
} | |
} | |
//# sourceURL=Flow_p26_1.js | |
]]></Flow> | |
<Stock roleName="sink" amount="0"/> | |
</SdSystem> | |
SdSystem_p26_2 | |
<SdSystem roleName="SdSystem_p26_2"> | |
<Stock roleName="source" amount="1000"/> | |
<Flow roleName="outflow"><![CDATA[ | |
var me, stock, cloud, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
stock = me.xpath("../Stock"); | |
cloud = me.xpath("../Cloud"); | |
setpoint = Math.floor(Math.random() * 501); // a number between 0 and 500 | |
me.print(`${stock.name()} --> ${me.name()} --> ${cloud.name()} setpoint (goal):${setpoint}`); | |
me.println(` ${stock.amount} ${cloud.amount}`); | |
}, | |
act: function() { | |
stock.amount > setpoint ? (stock.amount-- && cloud.amount++) : null; | |
me.println(`2) ${stock.amount} ${cloud.amount}`); | |
} | |
} | |
//# sourceURL=Flow_p26_2.js | |
]]></Flow> | |
<Cloud roleName="sink" amount="0"/> | |
</SdSystem> | |
SdSystem_p26_3 | |
<!-- TODO | |
(1) new SdSystem that includes outflow and sink cloud (2) have a ControlCenter controlling what the flows do ??? | |
- maybe ControlCenter would send messages/signals to the flows (to open or close the spiggot) | |
- the input and output flows would mechanically do what they were innstructed to do | |
--> | |
<SdSystem roleName="SdSystem_p26_3"> | |
<Cloud roleName="source" amount="2000"/> | |
<Flow roleName="inflow"><![CDATA[ | |
var me, cloud, stock, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
cloud = me.xpath("../Cloud"); | |
stock = me.xpath("../Stock"); | |
setpoint = Math.floor(Math.random() * 501); // a number between 0 and 500 | |
me.print(`${cloud.name()} --> ${me.name()} --> ${stock.name()} setpoint (goal):${setpoint}`); | |
me.println(` ${cloud.amount} ${stock.amount}`); | |
}, | |
act: function() { | |
((stock.amount < setpoint) && (cloud.amount >= 0)) ? (cloud.amount-- && stock.amount++) : null; | |
me.println(`3a) ${cloud.amount} ${stock.amount}`); | |
} | |
} | |
//# sourceURL=InFlow_p26_3.js | |
]]></Flow> | |
<Stock amount="0"/> | |
<!--<ControlCenter><![CDATA[ | |
var me, cloud, stock, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
// TODO | |
}, | |
act: function() { | |
// TODO | |
} | |
} | |
//# sourceURL=ControlCenter_p26_3.js | |
]]></ControlCenter>--> | |
<Flow roleName="outflow"><![CDATA[ | |
var me, stock, cloud, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
stock = me.xpath("../Stock"); | |
cloud = me.xpath("../Cloud"); | |
setpoint = Math.floor(Math.random() * 501); // a number between 0 and 500 | |
me.print(`${stock.name()} --> ${me.name()} --> ${cloud.name()} setpoint (goal):${setpoint}`); | |
me.println(` ${stock.amount} ${cloud.amount}`); | |
}, | |
act: function() { | |
stock.amount > setpoint ? (stock.amount-- && cloud.amount++) : null; | |
me.println(`3b) ${stock.amount} ${cloud.amount}`); | |
} | |
} | |
//# sourceURL=OutFlow_p26_3.js | |
]]></Flow> | |
<Cloud roleName="sink" amount="0"/> | |
</SdSystem> | |
SdSystem_p26_4 | |
<!-- Use an Hr hormone, and separate system from control system --> | |
<SdSystem roleName="SdSystem_p26_4"> | |
<Cloud roleName="source" amount="1000"/> | |
<Flow roleName="inflow"><![CDATA[ | |
var me, cloud, stock, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
cloud = me.xpath("../Cloud"); | |
stock = me.xpath("../Stock"); | |
me.print(`${cloud.name()} --> ${me.name()} --> ${stock.name()}`); | |
me.println(` ${cloud.amount} ${stock.amount}`); | |
}, | |
act: function() { | |
// use Hr hormone to determine whether or not to act | |
// the system starts with no hormone; the ControlCenter needs to paste <HrOne/> as last child of the Flow node | |
// if <HrOne/> is present, then the following line will move stuff from cloud to stock | |
me.first()?.xhc().name() === "HrOne" ? (cloud.amount-- && stock.amount++) : null; | |
me.println(`4) ${cloud.amount} ${stock.amount}`); | |
} | |
} | |
//# sourceURL=Flow_p26_4.js | |
]]></Flow> | |
<Stock roleName="sink" amount="0"/> | |
<!-- control system that will remove HrOne when stock.amount >= setpoint --> | |
<SdControlSystem> | |
<SetPoint amount="0"/> | |
<ControlCenter><![CDATA[ | |
var me, cloud, stock, flow, setpoint, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
cloud = me.xpath("../../Cloud"); | |
stock = me.xpath("../../Stock"); | |
flow = me.xpath("../../Flow"); | |
setpoint = me.xpath("../SetPoint"); | |
setpoint.amount = Math.floor(Math.random() * 501); // a number between 0 and 500 | |
flow.append("<HrOne/>"); // HrOne hormone is an enabler | |
me.println(`${me.name()} setpoint: ${setpoint.amount}`); | |
}, | |
act: function() { | |
stock.amount >= setpoint.amount ? flow.first()?.remove() : null; // remove the HrOne node | |
} | |
} | |
//# sourceURL=ControlCenter_p26_4.js | |
]]></ControlCenter> | |
</SdControlSystem> | |
</SdSystem> | |
ObjFuncMapper | |
<Script roleName="ObjFuncMapper"><![CDATA[ | |
var me, bool01, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
me.println(me.name()); | |
bool01 = true; | |
}, | |
act: function() { | |
me.println(me.name()); | |
if (bool01) { | |
this.test01(); | |
bool01 = false; | |
} | |
}, | |
// map between Xholon Classes: appspecific classes -> function/role/abstract classes | |
test01: function() { | |
const objarr_names = ["Cloud", "Stock", "Flow"]; // NOTE: "Flow" is a Script and uses DefaultContent | |
const objarr = this.map01(objarr_names); | |
const funcarr_names = ["Stimulus","Receptor", | |
"ControlCenter", // this is a Script which uses DefaultContent | |
"Signal","EfferentSignal","Effector","SetPoint","Homeostasis" | |
]; | |
const funcarr = this.map01(funcarr_names); | |
console.log(objarr_names, funcarr_names); | |
console.log(objarr, funcarr); // an array of XholonClass nodes | |
this.map02(objarr, funcarr); | |
}, | |
map01: function(namesarr) { | |
const arr = namesarr.map((item) => { | |
const xmlstr = `<${item}/>`; | |
me.println(xmlstr); | |
me.append(xmlstr); | |
return me.first()?.remove().xhc(); | |
}, []); | |
return arr; | |
}, | |
// map items in objarr and funcarr to each other | |
map02: function(objarr, funcarr) { | |
// TODO | |
objarr[0].funk = funcarr[0]; // testing - these 2 should NOT actually be linked | |
console.log(objarr[0]); | |
} | |
} | |
//# sourceURL=ObjFuncMapper.js | |
]]></Script> | |
<!-- ChatGpt01 | |
ChatGPT Neg Feedback | |
https://chatgpt.com/c/66f5bf83-6ab0-8010-8133-4841e256b1d2 | |
me | |
Write a JavaScript program that demonstrates negative feedback. | |
ChatGPT | |
A great way to demonstrate negative feedback in JavaScript is through a simple control system, such as a thermostat regulating room temperature. | |
In this scenario, negative feedback occurs when the system senses a deviation from the desired temperature and | |
adjusts the heating or cooling accordingly to bring the temperature back to the target. | |
Here’s an example: | |
--> | |
<ChatGpt01><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode; | |
me.println(me.name()); | |
this.doExample(); | |
}, | |
doExample: function() { | |
// Target temperature we want to maintain (in degrees Celsius) | |
const targetTemperature = 22; | |
// Function to simulate the current room temperature | |
let currentTemperature = 15; // 26 Assume it's initially higher than the target | |
let heaterOn = false; | |
// Function that applies negative feedback | |
function regulateTemperature() { | |
console.log(`Current Temperature: ${currentTemperature}°C`); | |
// Negative feedback control logic | |
if (currentTemperature > targetTemperature) { | |
console.log("The room is too hot, turning off the heater..."); | |
heaterOn = false; | |
currentTemperature -= 1; // Cool the room by 1 degree | |
} else if (currentTemperature < targetTemperature) { | |
console.log("The room is too cold, turning on the heater..."); | |
heaterOn = true; | |
currentTemperature += 1; // Heat the room by 1 degree | |
} else { | |
console.log("The room is at the perfect temperature."); | |
} | |
// Log heater status | |
if (heaterOn) { | |
console.log("Heater is ON."); | |
} else { | |
console.log("Heater is OFF."); | |
} | |
} | |
// Simulate the regulation process over time | |
function runThermostat() { | |
const interval = setInterval(() => { | |
regulateTemperature(); | |
// Stop the process when the temperature stabilizes | |
if (currentTemperature === targetTemperature) { | |
clearInterval(interval); | |
console.log("Thermostat has stabilized the room temperature."); | |
} | |
}, 1000); // Run every 1 second to simulate real-time regulation | |
} | |
// Start the thermostat | |
runThermostat(); | |
} // end doExample | |
} // end beh | |
//# sourceURL=ChatGpt01.js | |
]]></ChatGpt01> | |
<!-- | |
How it works: | |
The targetTemperature is the ideal temperature we want to maintain. | |
The currentTemperature starts at a higher value (26°C), simulating a room that's too hot. | |
The regulateTemperature function applies negative feedback: | |
If the room is too hot, it "turns off" the heater (lowers the temperature). | |
If the room is too cold, it "turns on" the heater (raises the temperature). | |
This continues until the currentTemperature matches the targetTemperature. | |
This is an example of negative feedback, as the system reacts to deviations from the target state by adjusting the environment back toward the desired value. | |
--> | |
<!-- KSW thoughts on this model: | |
The base case (no control system) is where the inside temperature always just equals the outside temperature. | |
insideTemp = outsideTemp | |
For example, a simple Hut in the woods with no insulation. | |
If the hut has a thermometer, it would just always read the same as a thermometer placed outside. | |
There is no heater, cooler, thermostat, targetTemperature (setpoint), just a currentTemperature. | |
I could build other versions on top of this base case. | |
- heater is always ON; no control | |
- cooler is always ON; no control | |
- heater and cooler are both always ON | |
- Hut is buried underground so its temperature is always the average temperature of that place | |
- Hut has insulation of varying efficiencies; extrem form of this is same as being buried underground | |
- similar to cells having a membrane; a form of passive control | |
- BUT people in the hut need constant fresh air from the atmosphere | |
- see: https://climate.weather.gc.ca/index_e.html | |
- etc. | |
Regulation, regulatory (instead of the word Control) | |
- passive: insulation in a house, diffusion in a cell membrane | |
- active (regulated): heater and cooler in a house, active transport in a cell membrane | |
--> | |
</NegFeedbackSystem> | |
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml, | |
<svg width="100" height="50" xmlns="http://www.w3.org/2000/svg"> | |
<g> | |
<title>SdSystem</title> | |
<rect id="NegFeedbackSystem/SdSystem" fill="#98FB98" height="50" width="50" x="25" y="0"/> | |
<g> | |
<title>Stock</title> | |
<rect id="NegFeedbackSystem/SdSystem/Stock" fill="#6AB06A" height="50" width="10" x="80" y="0"/> | |
</g> | |
</g> | |
</svg> | |
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient> | |
</XholonWorkbook> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment