Using Spaxiom for Intelligent Ventilation and Health Risk Monitoring
Joe Scanlin
November 2025
Spaxiom is a sensor abstraction layer and runtime that translates billions of heterogeneous sensor streams into structured, semantic events. It provides a spatial-temporal DSL for defining zones, entities, and conditions, making it easy to build context-aware applications across industries.
INTENT (Intelligent Network for Temporal & Embodied Neuro-symbolic Tasks) is Spaxiom's high-level event vocabulary. Instead of overwhelming AI agents with raw sensor data, Spaxiom emits compact, meaningful events that agents can immediately understand and act upon.
Poor indoor air quality in offices, schools, and conference rooms affects health, cognitive performance, and disease transmission. Most buildings have CO₂ sensors and HVAC systems, but they're only used for basic comfort control and don't account for how many people are actually in each space. The challenge is that building management systems, occupancy sensors, and HVAC controllers are siloed in separate systems with incompatible data formats that AI agents can't easily access or reason about.
Spaxiom acts as a "ventilation and health cortex" that combines CO₂ sensors, occupancy tracking, temperature, humidity, and HVAC data into one intelligent system. Instead of just monitoring CO₂ levels, it calculates actual outdoor air per person and tracks "ventilation debt" when spaces are under-ventilated. The system sends simple alerts like "Conference Room A has stale air" or "High-risk gathering detected in Classroom 204" so facility managers can adjust ventilation, schedule meetings differently, or open windows before air quality becomes a health concern.
Indoor air quality (IAQ) and ventilation are increasingly recognized as critical to health, cognitive performance, and resilience to airborne disease. Most commercial buildings already have a wealth of signals (CO2 sensors, temperature, humidity, HVAC control points), but they are typically used only for crude comfort bands. There is rarely a unified, spatially aware representation of:
Spaxiom can act as a ventilation and health cortex for buildings, fusing IAQ sensors, occupancy estimates, and HVAC state into intelligible INTENT events like StaleAirEpisode, VentilationDebt, and HighRiskGathering.
For a zone z (e.g., conference room, open office bay, classroom), typical signals include:
We assume each Zone in Spaxiom is wired to one or more of these signals and that zones can be grouped into higher-level areas for policy and analytics.
We define several IAQ- and health-related INTENT events:
StaleAirEpisode: CO2 sustained above a threshold (e.g., 1000 ppm) for more than a minimum duration;VentilationDebt: integrated shortfall of outdoor air per person relative to recommended rates;HighRiskGathering: high occupancy combined with poor ventilation and adverse IAQ (CO2, PM, humidity).Let us formalize some of these.
Ventilation per person. For zone z, at time t, the outdoor airflow per person can be approximated as:
where FOAz(t) is the fraction of supply air that is outdoor air, and V̇supz(t) is the total supply airflow.
Given a recommended per-person outdoor airflow qrec (e.g., from a standard), we define a ventilation deficit rate:
Over a monitoring window [t0, t1] of length Δt, the ventilation debt is:
CO2 excursion and stale air. Let Cstale be a CO2 threshold (e.g., 1000 ppm). Define an indicator:
and the duration of stale air in the window:
Composite health risk score. A simple IAQ/health risk score for zone z over [t0, t1] can be defined as:
where:
Normalization (e.g., dividing by window length or baseline values) can map RIAQz into a dimensionless score in [0,1].
In the Spaxiom DSL, a zone-level IAQ tracker can encapsulate sensor histories and risk computation:
from spaxiom import Zone, Condition
from spaxiom.temporal import within
from spaxiom.logic import on
class IaqZone:
def __init__(self, name, co2, temp, rh, oa_frac, sup_flow, occupancy):
self.zone = Zone.named(name)
self.co2 = co2 # ppm sensor
self.temp = temp # degC
self.rh = rh # %RH
self.oa_frac = oa_frac # 0..1
self.sup_flow = sup_flow # m^3/s
self.occupancy = occupancy # persons
# Configurable thresholds / recommendations
self.q_rec = 10.0 / 3600.0 # 10 m^3/h/person -> m^3/s/person
self.co2_stale = 1000.0 # ppm
self.pm_threshold = 25.0 # ug/m^3 (example)
self.rh_low = 30.0 # %
self.rh_high = 60.0 # %
def history(self, sensor, window_s: float):
return sensor.history(window_s=window_s) # [(dt, value), ...]
def ventilation_debt(self, window_s: float) -> float:
series_oa = self.history(self.oa_frac, window_s)
series_flow = self.history(self.sup_flow, window_s)
series_occ = self.history(self.occupancy, window_s)
# Assume aligned histories or interpolate in real implementation
total_debt = 0.0
for ((dt, oa), (_, flow), (_, occ)) in zip(series_oa, series_flow, series_occ):
q = oa * flow / max(occ, 1.0)
d = max(0.0, self.q_rec - q)
total_debt += d * dt
return total_debt
def stale_air_duration(self, window_s: float) -> float:
series = self.history(self.co2, window_s)
total = 0.0
for dt, c in series:
if c > self.co2_stale:
total += dt
return total
def rh_excursion(self, window_s: float) -> float:
series = self.history(self.rh, window_s)
total = 0.0
for dt, r in series:
if r < self.rh_low or r > self.rh_high:
total += dt
return total
def risk_score(self, window_s: float) -> float:
D = self.ventilation_debt(window_s)
S = self.stale_air_duration(window_s)
RH = self.rh_excursion(window_s)
alpha, beta, gamma, delta = 1.0, 0.5, 0.0, 0.2 # PM omitted here
score = alpha * D + beta * S + delta * RH
# Example squashing to [0,1]
return 1.0 - (1.0 / (1.0 + score * 1e-4))
# Wire a specific conference room
conf_A = IaqZone(
name="Conf_Room_A",
co2=co2_conf_A,
temp=temp_conf_A,
rh=rh_conf_A,
oa_frac=oa_conf_A,
sup_flow=flow_conf_A,
occupancy=occ_conf_A,
)
# Condition: high risk over the last 2 hours
high_risk_iaq = Condition(lambda: conf_A.risk_score(window_s=2 * 3600) > 0.7)
@on(within(300, high_risk_iaq)) # check every 5 minutes
def iaq_agent():
snapshot = {
"zone": conf_A.zone.name,
"risk": conf_A.risk_score(window_s=2 * 3600),
"vent_debt": conf_A.ventilation_debt(2 * 3600),
"stale_air_s": conf_A.stale_air_duration(2 * 3600),
"rh_excursion_s": conf_A.rh_excursion(2 * 3600),
}
# An LLM or rules engine can:
# - suggest schedule changes,
# - recommend window opening where applicable,
# - adjust ventilation setpoints if allowed.
propose_iaq_actions(snapshot)
This example shows how Spaxiom:
risk_score;high_risk_iaq) for agents to react on.Figure A.3: IAQ and ventilation risk for Conference Room A over a workday. Panel 1 shows CO2 concentration (red) exceeding the stale threshold (1000 ppm) during two meetings. Panel 2 shows outdoor air per person (blue) dropping below recommended levels during those same periods. Panel 3 shows the composite IAQ risk score RIAQz (purple) crossing into high-risk territory during meetings with poor ventilation. Shaded regions indicate StaleAirEpisode and HighRiskGathering INTENT events.