electronic closed-loop automotive cooling system

contact: it is as if @ protonmail dot com

april 2018

this page describes the operation and implementation of the closed-loop cooling system on my roadster, in daily use since early 2017.

the code described below is available on my github page. see, hear. the Cooling computer code is here, the algorithms described below are in cooling.h on that page. an overall description of my coding strategy, fastCode, will appear eventually. finally the electronics for all of the Roadster boxes is the same.

everything is datalogged once per second, from these i produce occasional plots for analysis.

system overview

this system completely replaces the "traditional" auto cooling system components: belt-driven pump, thermostat, plumbing, etc. cooling capacity is independent of engine speed, power consumption is typically under 50 watts. the system is physically simple, all complexity is in the control software.

temperature regulation, measured at a temperature sensor in the cylinder head water jacket, is within 3 degrees of the setpoint, rising to plus or minus 6 degrees during large load changes (solution to that under test now).

temperature is measured at 10 Hz rate, with 500 mS average. regulation is extremely tight.

the systems is composed of:


i have no idea how much power (in horsepower or watts) was consumed by the belt-driven coolant pump my engine once had; but typical power consumption of this system is approximately 50 watts (under 0.07 HP) and peak maximum including radiator fan is 210 watts (0.27HP). most sigificantly, cooling capacity is completely independent of engine speed. the engine is 200 ci/3.2L, 200 HP maximum, and given it's vintage (1950's), not particularly thermally efficient (a kind way to state it).

closed-loop process description

analogous to what it took for electronic fuel injection to replace carburetors, the solution for replacing the barbaric leaky-pump/thermostat system is more complex than you'd think it ought to be. a thermostat system works surprisingly well and is about as simple as it could be.

conceptually the entire system consists of two masses, two independently operating pumps, and two sensors (and occasional hints from the rest of the chassis).

two pump heat

one mass is a heat source. the rate at which it generates heat varies widely and unpredictably (your foot on the throttle; the load on the engine). since the mass is large heat addition and removal is slow and delayed in time. this mass is of course the engine, block and head. a temperature sensor is in the head and called "head temp". holding head temp to the set point temperature ("thermostat temperature") is, more or less, the entire goal of the system.

the other mass is a heat sink; the radiator. radiator output is unpredictable, and to the software, uncontrollable. the amount of heat it removes (to the atmosphere) depends on vehicle speed, load, weather, and the velocity of coolant moving through it. to make things worse the heat content of the fluid measured (at radiator outlet) arrival at the engine's water jacket is delayed additionally dependent on pump speed.

the main coolant pump does the job of the traditional belt-driven pump, pulling fluid out of the bottom of the radiator and pushing it into the water jacket. coolant flows up through the block into the head and out the top, to the radiator. (in a traditional system the thermostat is located right at the "top" before the radiator.) coolant flow is directly proportional to electrical power put into the pump. the pump is moving fluid within a system with no artifical restrictions and so the pump can be surprisingly small and efficient.

there is an additional pump, the circulator, which does three critical tasks at once.

the circulator pump ("circ pump") pulls hot coolant from the outlet from the top of the cylinder head, and pushes it into the bottom of the block, where the main pump pushes "cold" coolant. recall that speed of each pump is independent of the other. the circ pump is operating at all times, and is independant of cooling requirements. the circ pump circulates coolant between head and block.

consider for a moment a running engine at nominal load and at operating temperature. heat of combustion warms the coolant in the head and its temperature rises. circulation, independent of cooling, ensures that there are no hot-spots in the head. second, the head and block are now thermally stable and thermally coupled; cylinders and head remain at the same temperature. third, constantly-moving coolant fluid means that the head temp sensor accurately reflects actual coolant temperature, independent of engine load and coolant flow rate.

fourth, and of major importance, is that the circulator also mixes in the variable flow and temperature of the radiator outlet coolant, making for precise temperature control. mixing is of major consequence.

radiator outlet temperature varies wildly in any cooling system. the system has very little control over the outlet temperature, and the control it does have (radiator cooling fan) effect can be delayed by as much as a minute or more. radiator outlet temperature is as dependent on the weather as it is on fan motor speed.

in a thermostat system, it is only when the thermostat begins to close does the system "notice" the change, and by that time the block and head have been filled with the cooler coolant; the thermostat closes, the temperature rises again, opens, etc. this leads to a damped temperature oscillation.

mixing dilutes the incoming colder coolant into that within block and head. temperature change is "seen" in the head sensor more rapidly and the coolant pump speed can be adjusted so that combined coolant remains at the system set point temperature.

the end result of a closed-loop system is that rarely are there large temperature or heat-content differences; from idle to full load heat production the pumps' speed increases slowly and in response to small temperature changes. a major side effect is that the pump required to cool the engine during even the largest heat production is surprisingly small.

the cooling algorithm

closed loop all

the illustration above includes all of the major components, but leaves out the radiator cooling fan for simplicity. it has a similar but simpler algorithm driving it. in addition to the metal and plastic above, the control system itself consists of custom electronics, an off the shelf controller (Arduino Mega 2560) and code.

my code is structured in a coding strategy i call fastCode. fastCode is a method for designing cooperative, single-threaded multitasking based on timers and inter-process communication, with ideas borrowed from John Day's PATTERNS IN NETWORK ARCHITECTURE and delta-T).

the cooling code consists of two major task loops, and a number of smaller, simpler support tasks. process() is the "inner loop" that handles closed-loop temperature regulation (the point of the discussion here). the other major task loop is stateChange() that handles startup, engine running/cooldown, shutdown, etc.

stateChange() can be thought of as enclosing process(). stateChange() decides when or if process() is run. most of this discussion is about the core algorithms within process().

support task loops read, smooth and filter the two temperature sensors, control pump and fan motor slew rates, generate reports, handle communication, etc. these won't be discussed here; see the code.

the point of all this is to hold the cylinder head temperature as close as possible to the set point temperature (currently 170F on my engine). in practice the instantaneous temperature is + or - 3 degrees, and rarely exceeds + or - 5 degrees (and i'm working on those corner cases). note that these are instantaneous temps, meaning measured at the task loop rate of 100 milliseconds.


in fact there are two closed loops within process; one for the main pump ("pump") and one for the radiator cooling fan ("fan"). circulator pump control is a side effect of the pump process.

pump and fan began life as PID controllers (proportional integral derivative). PID is a standard control process that uses feedback to stabilize changing systems. however, classical PID makes two assumptions about the error correction term that make it unsuitable for engine thermal control: that process changes effected by the error term are not delayed (much) and/or have fixed delay, and that a given error-correction value has a constant effect. in this process the error term E, the number of degrees deviation from the set point, applied as feedback has an effect dependent on a number of factors, and worse, that effect is significantly and variably delayed in time. for these reasons the P (proportional) term that usually dominates PID feedback correction is of no use here. (in many systems, such as an electric furnace control, one "unit" of error term E always maps to some physical unit, volts, amperes, etc which will have predictable effect.)

a major distortion is that correction for temperature error, eg. too hot or too cold, is asymmetrical. we can only remove heat from the engine; we cannot (and would not want to) add heat. to "add heat", we wait. as long as the engine is running temperature will rise. the same is true of the radiator, with the difference that the cooling fan actually has some effect, though greatly delayed.

these asymmetries and nonlinearities make the closed loop complex.

pump sub-process

the pump process is a fairly straightforward closed-loop ID controller. error correction is positive domain only ("too hot"), negative values ("too cold") are clipped to zero. P is useless due to the arbitrary phase error. D "seems to" stabilize short term correction, it's traditional function. it may be voodoo at this point, the D gain is small and i haven't looked at it in a year.

if radiator outlet temperature were constant, then the ID output would directly control pump speed. however it is is not, and requires enthalpy correction. hot radiator coolant removes less heat than cold radiator coolant, and so more of it (increased coolant pump speed) is required. all the nasty bits (volume dependent) fall out or can be ignored with the closed loop control. heat content is then linearly proportional to temperature under these conditions and so a simple multiplier on the pump speed sufficies.

the main coolant pump speed is then the sum of the pump ID output, scaled proportionately by enthalpy compensation. numerically, this is 0 (pump stopped) to 255 (pump maximum speed). recently added to this term is decelleration overcool, see below.

circulation pump control

the pump process also controls the circulator pump. the circ pump runs constantly at fixed speed, except by ad hoc reasoning, when (if, i've never seen it happen) the main coolant pump approaches 80% rate, the circ pump speed slows proportionally, to 0 at full coolant pump speed.

decelleration overcool

a fairly new and experimental sub-process has been added to deal with a somewhat common corner case that i (incorrectly) call decelleration overcool. it might be better named de-load overcool. the condition occurs when a long duration moderate to high engine load (high heat production), with the system comfortably in closed loop control, is suddenly removed (eg. pulled off the freeway into slow surface street traffic). unlike heat production, where temperature rate-of-increase of the mass is fixed, over-cooling can happen much faster than the ID process runs down (integrating all those 0's); for a brief period the system over cools while the integrator runs down.

decel overcool operates in the negative-error domain ("too cold"). in most closed-loop operation head temp hovers around the set point, plus and minus, and decel overcool's integrator hovers around 0. when the process is caught up in overcool due to the conditions stated above, decel's integrator "pumps up" to a significant value, and this is subracted from the ID output that determines pump speed.

what makes this work is the fact that the decel overcool time constant is much shorter, currently 20% of the pump process time. this means its output both rises and falls more rapidly, making it a short-term correction.

decel overcool also adds to stability, since each (pump ID, decel overcool integrator) are in opposite domains, each damps the other.

fan sub-process

the fan process is also ID, has a much longer time constant, some 1200 seconds, and relaxed operating conditions, and overshoot ("too cold") is acceptable. the ideal goal of the fan process, when conditions are right, is to hold rad outlet temp to something like 20 degrees below set point. that difference is optimal in that it causes the main pump to run about 25%, nicely within it's optimum servo range, and low power and (electronic) heat production. too-cold coolant actually worsens regulation, since such a small amount of it needs to be introduced into the engine (via the circ/mixer) to maintain closed loop.

the fan motor speed is slewed to it's calculated target speed at a fairly slow rate. the fan motor is the largest electrical load, another reason to limit the outlet temperature differential to a practical maximum -- it is quieter. the cooling fan is turned off when vehicle speed reaches 45 MPH.


there are two temperature sensors, one in the head and one in the radiator outlet circuit. these are typical NTC resistor type sensors (Stewart Warner, 33..240 ohm 100..280F) in a precision (1%) circuit. analog readings are despeckled (shot noise filter; hey this is an automobile) and averaged with a relatively fast low-pass filter (100 to 500 mS). this is an order of magnitude faster, at least, than typical temperature guages.

i spent considerable time in the last decade messing with cylinder head thermal issues, including head dissection to determine optimum sensor placement. this was before i even considered this system, with it's circulator. with the circ pump sensor placement is largely unimportant as long as circ'ed coolant passes by it.

radiator outlet temperature is also not critical, for more or less the opposite reason: there is simply no good place to measure it. mine's simply stuck in the flow, before the main pump, about 6" past the lower radiator tank. the circ pump mixing effect partially moots the, again, phase error of measurement vs. arrival at the head sensor. we want coolant temp regulated everywhere, not just at the point of the sensor, and circulation helps approach this ideal.

engine oil cooling

there is also an engine-oil cooling loop that runs a fan attached to the remote oil cooler, via simple proportional control. starting at it's own set point (205F i think) the fan runs at a minimum speed; fan speed increases to maximum by 220F. the oil cooling fan is turned off when vehicle speed exceeds 45MPH.


aka motors and pumps. the processes above calculate pump and fan goal speeds, but do not directly control the motors. the motorSlew() loop causes the motor speed(s) to change to the goal speed at a low, slow slew rate. everything here has mass, rapid change is not needed, and a long slew rate means that there are no sudden electrical surges or load dumps. power consumption is much lowered. electronic components remain cool and unstressed, and it is overall quieter.


managing the overall operating state is as important as regulating operating temperature. closed-loop operation occurs only during a very narrow range of operating conditions. the initial state of the engine, thermally, is unknown when the car is turned on. it could be stone cold from overnight parking, or at peak heat from a brief stop after a long hard run.

"wrapped around" the engine cooling algorithms described above is the state control machine. loosely speaking, the car is turned on, probably started and run, is driven/warms up, operates for some time and then the engine is turned off. at a minimum the car is turned on, then turned off. stateChange() must follow actual conditions at all time.

state changes are easy to describe in the most common operating sequence outlined above, each state id described below in order of typical execution. though none of this sequencing is rocket science, many of the details are critical to operation.

notes for state descriptions

the following are true for all operation below, and are mentioned here, once, for clarity.

if power is removed (key off) at any time, in any state, control always returns to the STOP state.

it follows then that for all states after IDLE, that the controller and software assumes that the engine is running and producing heat. it is entirely possible for this to not be true; you can stall the engine or run out of gas. but as long as ignition power remains on, the cooling system continues to operate. there is no serious downside to this. since the cooling system is independent, it will simply run until the temperature of the cylinder head is brought (down) to the set point, at which time the cooling system would become quiescent anyway. the circulator will remain running however as long as the cooling system is operating (it draws about 2 amps).


any change to power off (ignition off, car off, etc) begins here, including initial power on of the cooling computer. motor goals are set to zero, the various closed-loop parameters are reset and errors are cleared. this is a transient state, control is immediately passed to IDLE.


idle state is simple: nothing happens. the cooling system is off, quiecent. if power ("ignition") is turned on control passes to the next state, DEFER.


defer imposes an initial delay between key-on/power on and cooling operation. this addresses real-world operation... the engine may be cranked and started, immediately or after a delay; the key may turn off, or may simply be left on without running the engine. defer delays later cooling system operation until it is better known what is likely to happen. defer minimizes electrical loads during the high-load-condition engine cranking/start sequence. there's no instant need for cooling in any case.

defer switches to the next, EXCH, state if either 10 seconds passes or if it sees the engine is running (rpm > minimum). [note: in the Roadster engine RPM arrives from the chassis computer via IPC.]


EXCH, or exchange, is a critical state that determines the thermal content of the engine and cooling system. when power is turned on, the engine could have been run hot and turned off, or cold overnight, or in between. after intermediate time periods, the radiator may be cool from a breeze, with the engine hot; thermal siphoning means the heat is hotter the the block...

exchange is simple: both pumps are run at a moderate fixed rate for a fixed period. this distributes coolant and heat amongst all components, allowing for a rational measurement of heat content.

an additional heuristic is applied: while the head temperature is above closed loop operating range (eg. engine hot) the radiator cooling fan is turned on. this need not be accurate.

exch terminates after a fixed interval and control passes to EVALUATE.


EVAL is a transient state; a decision is made on how to enter close-loop operation here. the outcome of EVAL is to select one of two possible next states: WUP (warmup) or RUN (closed loop).

though the pump ID controller will 'close the loop' with any initial starting conditions, we want to enter closed loop smoothly without any spikes or oscillations in regulated temperature. if the ID controller integratoer equals zero for an already-warm engine, then engine temperature is likely to overshoot (cooling system undershoot) until the integrator "pumps up" to accommodate the initially-unknown temperature error.

the purpose of EVAL, for the case where the engine already contains heat, is to pre-set the ID controller integrator with a value that is "close enough" to lock into closed loop operation without excessive over or undershoot.

EVAL is a simple decision: if the cylinder head temperature after EXCH is within the close-loop operating range, then the "large" preset is made and control passes to RUN state. if the engine is deemed "cold", and needing warmup, control passes to the WUP state, next. (in other words, if the engine is already warmed up, skip the warmup state).


warm-up has two internal thresholds. it is assumed that the engine is running, producing heat, and that temperature will eventually rise. when the head temp reaches a minimum threshold, the circulator pump is turned on nominally, immediately improving temperature measurement accuracy (until this point conduction/convection is "good enough" to detect "warm enough"). the second temperature threshold, the lower limit of closed loop operation, then presets the pump ID controller to the "small" preset value, and passes control to RUN.


the cooling system run state controls engine oeprating temperature until the ignition is turned off. the code involved in stateChange() does nothing, in fact, except watch for power-off. the process() code itself watches operating state and when it is RUN, performs its closed-loop calculations.

when power turns off control passes to DONE.


this is a transient state. conditions are set to evaluate post-shut-off cooldown requirements; though in closed loop, the engine has a variable amount of heat that may need to be removed. the two pumps are set to nominal speed, and if the radiator fan was on, it is set to a nominal speed (it was removing heat at power-off, assume continue). control passes to DISTRIB.


analogous to the earlier EVAL state, this state simply distributes coolant between head, radiator and block to determine heat remaining. this state persists for a fixed time, but if temperature drops below a lower threshold the state is terminated. the latter is fairly common, and occurs on short runs where the engine just reaches operating temperature but the contents of the radiator are cool/cold, such as in cold weather. often distrib negates any need for a cooldown cycle. when complete (due to time or temperature) control passes to COOLDOWN.


the cooldown cycle extracts engine (underhood) heat and prevents heat soak of underhood components. plenty of heat is left if the engine is subsequently re-started. DISTRIB and cooldown prevent head hot spots from forming (from yet-extracted combistion heat still in the metal after shutdown) and eliminates vapor lock. there are plenty of hot exhaust side components dumping heat under the hood.

cooldown persists until a predetermined engine-cool temperature is reached, a preset time passes, or battery voltage drops below a threshold.

upon termination control passes back to the STOP state.


there exists a manual control state, that runs pumps and fan at various fixed speeds, mainly for test purposes. these states are reach via IPC messages from instrument panel controllers.