# AHU v0.1 — sequence and model contract

Implemented 2026-09-12. A dependency-free single-zone recirculating AHU at
`ahu-simulator.html`, with independent code in `js/ahu/`. FCU and VAV engineering
are unchanged. This is a simplified teaching model, not physically validated,
a Delta CO firmware emulator, or a standards/equipment-protection sequence.

## System and configurable inputs

Outdoor air + return air → mixing box → supply fan → heating coil → cooling coil
→ supply air → room. RAT equals RT exactly; no return duct temperature offset.
The return fraction is 1 − outside fraction, and an equal outdoor-air volume is
implicitly relieved from the room. Return/relief fans and pressure balance are not modeled.

The user can set fan On/Off, Manual speed or Auto static pressure, pressure SP,
pressure PI tuning, duct resistance, room SP and initial RT, OAT, room load,
SAT source (room reset or manual), SAT reset limits, mixed-air damper source
(manual or simple economizer), manual damper position and minimum OA percentage.
Coils use automatic SAT feedback or explicit manual HCV/CCV commands, with mutual
exclusion. SAT P/PI, proportional band and integral gain are adjustable. Advanced
inputs include full-speed airflow, envelope conductance, water temperatures, coil
conductances and damper travel time. CFM/L/s changes preserve canonical m³/s values.

All defaults and bounds live in `config.js`. Defaults: fan 60%, full-speed flow
5000 CFM, RT 26°C, Room SP 22°C, OAT 30°C, internal load 10 kW, envelope UA 400 W/K,
manual OA damper 20%, SAT room reset between 12 and 35°C, manual SAT 16°C, PI PB
20°C and Ki 1.2 percentage points/(°C·min), hot/chilled water 60/7°C, heating/cooling
UA 2000/2500 W/K, damper travel 60 seconds, duration 120 minutes. They are teaching
choices, not manufacturer tuning or ventilation requirements.

Pressure defaults: Manual speed retains the existing startup behavior; Auto is
selectable. SP 180 Pa, PB 1000 Pa, Ki 0.2 percentage points/(Pa·min), duct resistance
multiplier 1. The illustrative fan rating is 500 Pa at rated full-speed airflow;
shutoff pressure is twice that rating. Pressure SP accepts 10–1000 Pa, intentionally
including targets above available capacity. Resistance accepts 0.25–4.

## Control sequence

The existing room-reset sequence is explicitly labeled **Cascade · RT → SAT SP →
valves** in the UI as of 2026-09-13. Select it under SAT setpoint source and keep
coil valves in Auto, then Apply settings. The source/helper labels identify manual
valve bypass separately; no new AHU control equation was introduced for this label.

Room reset is a conventional signed PI using error RT − Room SP, PB 4°C and Ki
0.15 percentage points/(°C·min). Its output d is bounded −100 to +100:

```
d >= 0: SAT SP = Room SP − d/100 × (Room SP − minimum SAT)
d < 0:  SAT SP = Room SP − d/100 × (maximum SAT − Room SP)
```

Manual SAT bypasses that reset. The room integral resets while fan is commanded
off, while manual SAT is selected, or while manual valves bypass SAT feedback.
Reactivation initializes it at zero. Room SP must be inside the reset limits.

SAT feedback uses error SAT − SAT SP and an independent signed P/PI:
P = 100 × error / PB; I increment = error × Ki × dt / 60. Positive output opens
CCV, negative output opens HCV. Output is limited to ±100, and both commands cannot
be positive together. These are conventional error-magnitude PI algorithms, not
the fixed-rate integral algorithm used by the documented Delta CO objects.

Integral increments into an output limit are held, reverse increments allow
recovery, and boundary-crossing increments are accepted only up to the limit.
State is explicit. P mode clears integral. Tuning changes preserve PI integral
but do not integrate on their first observation. Nonzero D is not implemented.

Manual valves bypass SAT feedback; both-positive manual commands are rejected
atomically. Fan Off or zero commanded fan speed inhibits both coils immediately,
even during physical fan rundown. Coils also inhibit below 20 CFM; this is a
teaching model operating threshold, not a validated flow-proving interlock.

Manual mixed-air damper uses its requested position. In economizer mode, if OAT
is more than 1°C below RAT and SAT SP < RAT, target OA fraction is
`limit((RAT − SAT SP)/(RAT − OAT), minimum OA fraction, 1)`; otherwise minimum OA
applies. The threshold is a teaching choice. Fan Off parks the target at zero.
Actual position follows its full-stroke time. Mechanical cooling can supplement
outdoor air; the SAT loop remains the final coil controller. There is no enthalpy,
humidity, freeze-stat, low-MAT protection, or code-required ventilation calculation.

## Physical model

- Fan actual speed follows the command at 100/full-travel-seconds percentage points
  per second, with a 20-second full stroke. Airflow and pressure follow the fan/duct
  intersection below. At resistance 1 this preserves the previous linear flow/speed
  relationship. Fan heat is omitted.
- Outdoor fraction equals actual coordinated damper position / 100, an explicit
  idealization rather than a real damper characteristic. MAT = fraction × OAT +
  (1 − fraction) × RAT. OA and return airflow sum to supply airflow.
- Coil air capacity rate is flow × 1206 J/(m³·K). Heating approaches the fixed hot
  water temperature by effectiveness `1 − exp(−heatingUA × HCVfraction/capacity)`;
  cooling similarly approaches chilled water temperature. Heating cannot reduce
  temperature and cooling cannot increase it. The resulting steady outlet target
  drives an 8-second first-order discharge-temperature response, approximating
  coil/measurement dynamics without claiming measured equipment behavior.
- The room has 30 MJ/K thermal capacity. Each one-second step uses mean flow and
  the exact time-average first-order SAT response. Room energy is supplied-air
  sensible exchange + internal load + envelopeUA × (OAT − RT). Coil energy is
  not added a second time. The aggregate discharge lag is not a validated coil
  metal/water energy-storage model.
- Zero flow yields unavailable MAT/SAT and zero supplied-air room energy. The
  internal discharge state relaxes toward the mixed-air target while stopped.
  Invalid/nonfinite physical results stop the engine, preserving the last valid
  physical state. Lack of coil capacity leaves SAT targets unmet rather than
  forcing SAT to match. No humidity, latent cooling, condensate, water hydraulics,
  building pressure network, return fan control or equipment protection is modeled.

## Duct static pressure and fan feedback — added 2026-09-13

Select **Fan speed control → Auto · static pressure**, set a target in Pa and
Apply settings. The separate conventional pressure PI compares measured duct static
pressure with SP. It never derives a fan command by inverting the physical model.
Positive error increases speed, negative error reduces speed. With error SP − pressure:

```
P = 100 × error / pressurePB
I increment = error × pressureKi × dt / 60
fan command = limit(P + I, 0, 100)
```

Integral state and simulated dt are explicit. Auto entry seeds I from actual fan
speed; proportional error can cause a step, so bumpless transfer is not claimed.
Integration farther into either output limit is held; reverse-error recovery and
partial increments at a boundary are supported. PB/Ki changes retain I and skip
integration for the first evaluation. Ki 0 holds I. Manual speed and Fan Off clear
the loop. The saved manual speed has no authority in Auto, including a saved 0%.
Fan Off takes priority; coils inhibit immediately and actual fan/pressure run down.
Existing SAT/room logic and manual valve ownership are unchanged.

The physical model uses one duct pressure node relative to a room held at zero
gauge pressure. Let n = actual fan speed/100, q = airflow/rated airflow, R = duct
resistance multiplier and Pr = 500 Pa:

```
fan available static pressure = Pr × (2 n² − q²)
duct pressure                = Pr × R × q²
intersection: q              = n × sqrt(2 / (R + 1))
```

These curves are illustrative choices, not a manufacturer's measured fan curve.
Air settles algebraically at each speed/resistance; fan travel supplies the dynamics.
Resistance changes take effect in the next physical step. The sensor represents the
supply node upstream of the lumped resistance, not an arbitrary downstream duct tap.
Higher R at fixed speed reduces flow and raises this node pressure; pressure Auto
then reduces speed to restore SP. Mixed-air fraction remains idealized separately.
There is no branch network, wind/stack pressure, duct storage, fan stall, filter
model, proof switch, or minimum operating-speed requirement in this version.

The square-law system resistance and fan/system operating-point concept follow
[Greenheck's fan performance guide](https://webcontent.greenheck.com/atg-cms-prod/docs/default-source/pdf-downloads/application-articles/perf_basics.pdf?sfvrsn=6df9b7ac_16).
Our curve coefficients and tuning are teaching choices. At R=1, 60% speed yields
3000 CFM and 180 Pa for the default 5000 CFM rating. At 100% speed pressure tops out
at 500 Pa; an 800 Pa target remains unmet rather than forcing the result. The UI
reports shortfall when full fan command is more than 1 Pa below target (a display
tolerance). Pressure is displayed even in Manual; active SP is unavailable in Manual
or Off. Pressure/SP trends use their own Pa axis and share the existing time controls.

## Operation, trends and validation

Classic deferred scripts and relative links preserve direct file-URL operation;
no dependencies, server, fetch or build step. Configuration, controller, physical
model, engine and rendering remain separate. AHU shares only base presentation
styles, with its own engine/trend/UI modules; it does not instantiate FCU or VAV.

Start captures a detached baseline. Pause/Resume retains state. Reset restores
run-start configuration and clears history/events. Initial RT and duration lock
after Start. Apply in READY reinitializes without advancing time; live edits queue
atomically for the next step, including while paused. Boundary before/after samples
share a timestamp, and controller evaluation on that boundary has dt=0. Numerical
steps remain one simulated second, with a final fractional step when needed.

The combined selectable trend includes SAT/SP, RT/SP, RAT, OAT, MAT, HCV, CCV,
actual fan speed/command, actual OA damper/command, supply flow and OA flow. Colored
swatches match traces; airflow, temperature and output use separate labeled axes.
Zoom/pan freezes the view; All time follows the full run. Plot settings never change
the recorded history or simulation. Background visibility pauses playback; a
wall-clock interruption over 30 seconds also pauses. Events retain the latest 100.

`node tests/ahu-tests.cjs` passes 46 numerical and actual-page DOM checks, including
mixing endpoints, PI action/anti-windup, valve exclusion, fan inhibition, economizer,
energy accounting, capacity shortfall, 24-hour summer/winter room stability,
overrides, atomic edits, lifecycle, units, playback speed and trend navigation.
Pressure tests cover invalid inputs, square-law operating points, PI action and
anti-windup, tuning, upward/downward target steps, resistance disturbances,
unreachable targets/recovery, manual/off/restart, paused UI changes, Pa traces,
and 24-hour summer/winter runs with simultaneous pressure and temperature control.
The 24-hour default and winter cases settle within 0.05°C of Room SP, a software
result for these teaching scenarios only. Browser visual and
console verification remains separate from Node DOM checks under the previously
observed local file-URL tool restriction. None of these checks establish physical
validation, firmware parity or compliance with a mechanical/control standard.

See [AHU next steps](ahu-next-steps.md) for proposed feedback/fault and
air-quality extensions. Those proposals are not implemented features.
