Indoor air quality engineering underwent a paradigm shift with the ratification of ANSI/ASHRAE Standard 241-2023 (Control of Infectious Aerosols). While legacy ventilation standards (such as ASHRAE Standard 62.1) dimension outdoor air intake strictly around dilution of metabolic bioeffluents and indoor volatile organic compounds (VOCs), Standard 241 establishes binding requirements for Infection Risk Management Mode (IRMM) to suppress airborne pathogen transmission.
The core computational unit of Standard 241 is Equivalent Clean Airflow ($ECA$). Rather than forcing facilities to over-condition massive volumes of 100% outdoor air, which incurs catastrophic thermal energy penalties in extreme weather, Standard 241 establishes a mathematically unified framework allowing mechanical engineers and building scientists to combine three distinct mitigation vectors:
- Pathogen-free outdoor ventilation air ($V_{\text{ot}}$)
- Central recirculated air passing through certified filtration media ($V_{\text{recirc}} \times \eta_{\text{filter}}$)
- In-room germicidal inactivation and local filtration devices (Upper-room UVGI and certified portable HEPA air cleaners adjusted for room mixing effectiveness)
In this article, we walk through building a deterministic, zero-dependency, pure TypeScript engine that implements ANSI/ASHRAE Standard 241 Table 5-1 baseline rates, Section 6 multi-source air cleaning balance equations, and automated deficit resolution recommendations.
The Mathematical Framework of ASHRAE 241
Standard 241 defines the total required Equivalent Clean Airflow for any zone ($ECA_i$) as a dual-component summation of per-person pathogen generation and per-unit-area building surface/reservoir emissions:
ECA_required = (P_z * ECA_p) + (A_z * ECA_a)
Where:
-
P_z: Peak zone occupant count (people) -
ECA_p: Minimum equivalent clean airflow per person (CFM/person or L/s·person) -
A_z: Usable zone floor area (sq ft or m²) -
ECA_a: Minimum equivalent clean airflow per unit floor area (CFM/sq ft or L/s·m²)
The total delivered clean airflow is the linear superposition of outdoor air and certified air cleaning mechanisms:
ECA_delivered = V_ot + (V_recirc * η_filter) + (CADR_inroom * k_mix) + ECA_uvc
Where:
-
V_ot: Volume flow rate of pathogen-free outdoor air (CFM) -
V_recirc: Recirculated central air handler volume flow rate (CFM) -
η_filter: Single-pass bioaerosol removal efficiency of central media for droplet nuclei (1 to 3 µm) -
CADR_inroom: Clean Air Delivery Rate of in-room portable air cleaners (CFM) -
k_mix: Room air mixing effectiveness factor (0.80 to 1.00) -
ECA_uvc: Equivalent clean airflow delivered by upper-room UV-C irradiation (CFM)
To explore the live computational model and interactive scenario generator, visit the open-access ASHRAE 241 Equivalent Clean Airflow Research Hub and download the ASHRAE 241 Multi-Zone Benchmark Dataset.
Implementing the Pure TypeScript Engine
Let us define the strict domain types and normative space configuration matrix per ANSI/ASHRAE Standard 241 Table 5-1 and Appendix A bioaerosol filtration capture efficiencies.
/**
* HVACLogic ANSI/ASHRAE Standard 241-2023 Computational Engine
* Zero-dependency, client-side TypeScript implementation.
*/
export type Ashrae241SpaceType =
| "classroom_age_5_8"
| "classroom_age_9_plus"
| "office_general"
| "conference_room"
| "healthcare_patient_room"
| "healthcare_exam_room"
| "retail_general"
| "restaurant_dining"
| "fitness_gym"
| "place_of_worship"
| "residential_common";
export type Ashrae241MervRating =
| "merv_8"
| "merv_11"
| "merv_13"
| "merv_14"
| "merv_15"
| "merv_16_hepa";
export interface SpaceStandardConfig {
id: Ashrae241SpaceType;
label: string;
category: "Educational" | "Commercial" | "Healthcare" | "Public Assembly" | "Residential";
ecaP_Lps: number;
ecaA_Lps_m2: number;
ecaP_Cfm: number;
ecaA_Cfm_sqft: number;
defaultOccupancyDensityPer1000SqFt: number;
}
// 1 L/s = 2.11888 CFM; 1 L/s/m² = 0.19685 CFM/ft²
export const ASHRAE_241_TABLE_5_1: Record<Ashrae241SpaceType, SpaceStandardConfig> = {
classroom_age_5_8: {
id: "classroom_age_5_8",
label: "Classroom (Ages 5-8)",
category: "Educational",
ecaP_Lps: 20,
ecaA_Lps_m2: 0.6,
ecaP_Cfm: 42.4,
ecaA_Cfm_sqft: 0.12,
defaultOccupancyDensityPer1000SqFt: 25,
},
classroom_age_9_plus: {
id: "classroom_age_9_plus",
label: "Classroom (Age 9+ & Lecture)",
category: "Educational",
ecaP_Lps: 20,
ecaA_Lps_m2: 0.6,
ecaP_Cfm: 42.4,
ecaA_Cfm_sqft: 0.12,
defaultOccupancyDensityPer1000SqFt: 35,
},
office_general: {
id: "office_general",
label: "General Office Space",
category: "Commercial",
ecaP_Lps: 15,
ecaA_Lps_m2: 0.6,
ecaP_Cfm: 31.8,
ecaA_Cfm_sqft: 0.12,
defaultOccupancyDensityPer1000SqFt: 5,
},
conference_room: {
id: "conference_room",
label: "Conference / Meeting Room",
category: "Commercial",
ecaP_Lps: 15,
ecaA_Lps_m2: 0.8,
ecaP_Cfm: 31.8,
ecaA_Cfm_sqft: 0.16,
defaultOccupancyDensityPer1000SqFt: 50,
},
healthcare_patient_room: {
id: "healthcare_patient_room",
label: "Healthcare Patient Room",
category: "Healthcare",
ecaP_Lps: 25,
ecaA_Lps_m2: 1.0,
ecaP_Cfm: 53.0,
ecaA_Cfm_sqft: 0.20,
defaultOccupancyDensityPer1000SqFt: 4,
},
healthcare_exam_room: {
id: "healthcare_exam_room",
label: "Outpatient Exam Room",
category: "Healthcare",
ecaP_Lps: 25,
ecaA_Lps_m2: 1.0,
ecaP_Cfm: 53.0,
ecaA_Cfm_sqft: 0.20,
defaultOccupancyDensityPer1000SqFt: 10,
},
retail_general: {
id: "retail_general",
label: "Retail & Department Store",
category: "Commercial",
ecaP_Lps: 15,
ecaA_Lps_m2: 0.6,
ecaP_Cfm: 31.8,
ecaA_Cfm_sqft: 0.12,
defaultOccupancyDensityPer1000SqFt: 15,
},
restaurant_dining: {
id: "restaurant_dining",
label: "Restaurant Dining Area",
category: "Public Assembly",
ecaP_Lps: 20,
ecaA_Lps_m2: 0.9,
ecaP_Cfm: 42.4,
ecaA_Cfm_sqft: 0.18,
defaultOccupancyDensityPer1000SqFt: 70,
},
fitness_gym: {
id: "fitness_gym",
label: "Fitness Center / Aerobics Gym",
category: "Public Assembly",
ecaP_Lps: 30,
ecaA_Lps_m2: 1.5,
ecaP_Cfm: 63.6,
ecaA_Cfm_sqft: 0.30,
defaultOccupancyDensityPer1000SqFt: 40,
},
place_of_worship: {
id: "place_of_worship",
label: "Place of Worship / Sanctuary",
category: "Public Assembly",
ecaP_Lps: 15,
ecaA_Lps_m2: 0.6,
ecaP_Cfm: 31.8,
ecaA_Cfm_sqft: 0.12,
defaultOccupancyDensityPer1000SqFt: 100,
},
residential_common: {
id: "residential_common",
label: "Residential Common Areas",
category: "Residential",
ecaP_Lps: 10,
ecaA_Lps_m2: 0.5,
ecaP_Cfm: 21.2,
ecaA_Cfm_sqft: 0.10,
defaultOccupancyDensityPer1000SqFt: 10,
},
};
/**
* Single-pass bioaerosol droplet nuclei (1 to 3 µm) removal efficiency
* Derived from ASHRAE 52.2 particle size efficiency curves and ASHRAE 241 App A.
*/
export const BIOAEROSOL_FILTER_EFFICIENCIES: Record<
Ashrae241MervRating,
{ label: string; efficiency: number; description: string }
> = {
merv_8: {
label: "MERV 8",
efficiency: 0.20,
description: "Coarse pre-filter capture; ~20% infectious aerosol removal.",
},
merv_11: {
label: "MERV 11",
efficiency: 0.50,
description: "Enhanced media; ~50% infectious bioaerosol removal.",
},
merv_13: {
label: "MERV 13",
efficiency: 0.85,
description: "ASHRAE 241 minimum baseline; ~85% droplet nuclei capture.",
},
merv_14: {
label: "MERV 14",
efficiency: 0.90,
description: "High-performance commercial media; ~90% bioaerosol removal.",
},
merv_15: {
label: "MERV 15",
efficiency: 0.95,
description: "Hospital-grade secondary filter; ~95% bioaerosol removal.",
},
merv_16_hepa: {
label: "MERV 16 / HEPA",
efficiency: 0.9997,
description: "True HEPA filtration; ≥99.97% pathogen removal efficiency.",
},
};
The Evaluation Function
The core solver calculates the target demand, sums the multi-source supply lines, determines the margin and compliance ratio, and synthesizes engineering mitigation recommendations.
export interface Ashrae241Input {
spaceType: Ashrae241SpaceType;
floorAreaSqFt: number;
occupants: number;
ceilingHeightFt?: number;
outdoorAirCfm: number;
recirculatedAirCfm: number;
centralFilterMerv: Ashrae241MervRating;
inRoomAirCleanerCadrCfm?: number;
mixingFactor?: number;
uvcEquivalentCfm?: number;
}
export interface Ashrae241Output {
spaceType: Ashrae241SpaceType;
spaceLabel: string;
floorAreaSqFt: number;
occupants: number;
roomVolumeCuFt: number;
// Required ECA targets per Section 5 & Table 5-1
requiredPeopleEcaCfm: number;
requiredAreaEcaCfm: number;
totalRequiredEcaCfm: number;
requiredAchEquiv: number;
// Delivered ECA components per Section 6
deliveredOutdoorAirCfm: number;
deliveredCentralFilterCfm: number;
deliveredInRoomCfm: number;
deliveredUvcCfm: number;
totalDeliveredEcaCfm: number;
deliveredAchEquiv: number;
// Compliance metrics
ecaMarginCfm: number;
complianceRatio: number;
isCompliant: boolean;
status: "exceeds" | "compliant" | "marginal_deficit" | "critical_deficit";
// Component contribution shares (%)
outdoorAirSharePct: number;
centralFilterSharePct: number;
inRoomSharePct: number;
uvcSharePct: number;
recommendations: string[];
}
export function calculateAshrae241Compliance(input: Ashrae241Input): Ashrae241Output {
const config = ASHRAE_241_TABLE_5_1[input.spaceType];
const ceilingHeight = input.ceilingHeightFt ?? 9;
const roomVolumeCuFt = Math.max(1, input.floorAreaSqFt * ceilingHeight);
// 1. Required ECA calculation (Section 5)
const requiredPeopleEcaCfm = Math.round(input.occupants * config.ecaP_Cfm * 10) / 10;
const requiredAreaEcaCfm = Math.round(input.floorAreaSqFt * config.ecaA_Cfm_sqft * 10) / 10;
const totalRequiredEcaCfm = Math.round((requiredPeopleEcaCfm + requiredAreaEcaCfm) * 10) / 10;
const requiredAchEquiv = Math.round(((totalRequiredEcaCfm * 60) / roomVolumeCuFt) * 10) / 10;
// 2. Delivered ECA calculation (Section 6)
const filterMeta = BIOAEROSOL_FILTER_EFFICIENCIES[input.centralFilterMerv];
const deliveredOutdoorAirCfm = Math.max(0, input.outdoorAirCfm);
const deliveredCentralFilterCfm = Math.round(Math.max(0, input.recirculatedAirCfm) * filterMeta.efficiency * 10) / 10;
const mixFactor = Math.min(1.0, Math.max(0.5, input.mixingFactor ?? 1.0));
const deliveredInRoomCfm = Math.round(Math.max(0, input.inRoomAirCleanerCadrCfm ?? 0) * mixFactor * 10) / 10;
const deliveredUvcCfm = Math.round(Math.max(0, input.uvcEquivalentCfm ?? 0) * 10) / 10;
const totalDeliveredEcaCfm = Math.round(
(deliveredOutdoorAirCfm + deliveredCentralFilterCfm + deliveredInRoomCfm + deliveredUvcCfm) * 10
) / 10;
const deliveredAchEquiv = Math.round(((totalDeliveredEcaCfm * 60) / roomVolumeCuFt) * 10) / 10;
// 3. Margin & Compliance
const ecaMarginCfm = Math.round((totalDeliveredEcaCfm - totalRequiredEcaCfm) * 10) / 10;
const complianceRatio = totalRequiredEcaCfm > 0
? Math.round((totalDeliveredEcaCfm / totalRequiredEcaCfm) * 1000) / 1000
: 1;
const isCompliant = totalDeliveredEcaCfm >= totalRequiredEcaCfm;
let status: Ashrae241Output["status"];
if (complianceRatio >= 1.25) {
status = "exceeds";
} else if (complianceRatio >= 1.0) {
status = "compliant";
} else if (complianceRatio >= 0.75) {
status = "marginal_deficit";
} else {
status = "critical_deficit";
}
// 4. Component Shares
const denom = totalDeliveredEcaCfm > 0 ? totalDeliveredEcaCfm : 1;
const outdoorAirSharePct = Math.round((deliveredOutdoorAirCfm / denom) * 1000) / 10;
const centralFilterSharePct = Math.round((deliveredCentralFilterCfm / denom) * 1000) / 10;
const inRoomSharePct = Math.round((deliveredInRoomCfm / denom) * 1000) / 10;
const uvcSharePct = Math.round((deliveredUvcCfm / denom) * 1000) / 10;
// 5. Actionable Engineering Recommendations
const recommendations: string[] = [];
if (!isCompliant) {
const deficit = Math.abs(ecaMarginCfm);
recommendations.push(
`Deficit of ${deficit} CFM equivalent clean airflow. IRMM mode requirements are unsatisfied.`
);
if (input.centralFilterMerv === "merv_8" || input.centralFilterMerv === "merv_11") {
recommendations.push(
`Upgrade central AHU filtration from ${filterMeta.label} to MERV 13 (85% bioaerosol capture) to gain up to ${Math.round(input.recirculatedAirCfm * (0.85 - filterMeta.efficiency))} CFM ECA without outdoor air energy penalties.`
);
}
const neededCadrs = Math.ceil(deficit / (mixFactor * 250));
recommendations.push(
`Deploying ${neededCadrs} portable in-room HEPA air cleaner(s) rated at 250 CFM CADR each will supply ${Math.round(neededCadrs * 250 * mixFactor)} CFM ECA to close the deficit.`
);
} else {
recommendations.push(
`Fully compliant with ANSI/ASHRAE Standard 241-2023 Table 5-1 for ${config.label}. Margin: +${ecaMarginCfm} CFM (${Math.round((complianceRatio - 1) * 100)}% buffer).`
);
}
return {
spaceType: input.spaceType,
spaceLabel: config.label,
floorAreaSqFt: input.floorAreaSqFt,
occupants: input.occupants,
roomVolumeCuFt,
requiredPeopleEcaCfm,
requiredAreaEcaCfm,
totalRequiredEcaCfm,
requiredAchEquiv,
deliveredOutdoorAirCfm,
deliveredCentralFilterCfm,
deliveredInRoomCfm,
deliveredUvcCfm,
totalDeliveredEcaCfm,
deliveredAchEquiv,
ecaMarginCfm,
complianceRatio,
isCompliant,
status,
outdoorAirSharePct,
centralFilterSharePct,
inRoomSharePct,
uvcSharePct,
recommendations,
};
}
Vitest Invariant Verification
We pair our computational engine with rigorous unit tests that assert compliance calculations against reference school classrooms and office conference suites.
import { describe, it, expect } from "vitest";
import {
calculateAshrae241Compliance,
ASHRAE_241_TABLE_5_1,
BIOAEROSOL_FILTER_EFFICIENCIES,
} from "./ashrae-241";
describe("ANSI/ASHRAE Standard 241-2023 ECA Engine", () => {
it("computes baseline classroom requirements correctly per Table 5-1", () => {
// 1000 sq ft classroom, 25 students (ages 9+), 9 ft ceilings
const result = calculateAshrae241Compliance({
spaceType: "classroom_age_9_plus",
floorAreaSqFt: 1000,
occupants: 25,
ceilingHeightFt: 9,
outdoorAirCfm: 450, // Typical ASHRAE 62.1 rate
recirculatedAirCfm: 800,
centralFilterMerv: "merv_8", // 20% efficiency
});
// Required ECA = (25 * 42.4) + (1000 * 0.12) = 1060 + 120 = 1180 CFM
expect(result.requiredPeopleEcaCfm).toBe(1060);
expect(result.requiredAreaEcaCfm).toBe(120);
expect(result.totalRequiredEcaCfm).toBe(1180);
// Delivered ECA = 450 (OA) + (800 * 0.20) = 450 + 160 = 610 CFM
expect(result.deliveredOutdoorAirCfm).toBe(450);
expect(result.deliveredCentralFilterCfm).toBe(160);
expect(result.totalDeliveredEcaCfm).toBe(610);
// Deficit & Compliance
expect(result.isCompliant).toBe(false);
expect(result.ecaMarginCfm).toBe(-570);
expect(result.status).toBe("critical_deficit");
});
it("resolves compliance deficit when upgrading to MERV 13 and portable HEPA units", () => {
const result = calculateAshrae241Compliance({
spaceType: "classroom_age_9_plus",
floorAreaSqFt: 1000,
occupants: 25,
ceilingHeightFt: 9,
outdoorAirCfm: 450,
recirculatedAirCfm: 800,
centralFilterMerv: "merv_13", // 85% efficiency -> 680 CFM ECA
inRoomAirCleanerCadrCfm: 300, // Portable HEPA -> 300 CFM ECA
mixingFactor: 0.9, // 270 CFM delivered
});
// Delivered = 450 + (800 * 0.85) + (300 * 0.9) = 450 + 680 + 270 = 1400 CFM
expect(result.totalDeliveredEcaCfm).toBe(1400);
expect(result.totalRequiredEcaCfm).toBe(1180);
expect(result.isCompliant).toBe(true);
expect(result.ecaMarginCfm).toBe(220);
expect(result.status).toBe("compliant");
});
});
Conclusion & Open Architecture
By decoupling pathogen mitigation from pure outdoor air dilution, ANSI/ASHRAE Standard 241 enables building owners to achieve infection control without sizing oversized chillers or triggering energy grid spikes.
All algorithms shown here run 100% client-side in the browser on HVACLogic. You can explore the full interactive implementation, browse reference datasets, and test multi-zone scenarios at the HVACLogic Engineering Research Library.
Top comments (0)