239 lines
9.7 KiB
HTML
239 lines
9.7 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8"/>
|
|||
|
|
<title>Draft Pressure Calculator v2 — Fuel Source Variant | Alan Destin</title>
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|||
|
|
<style>
|
|||
|
|
:root{--bg:#1a1a1a;--fg:#e8e8e8;--accent:#d4a056;--panel:#252525;--border:#3a3a3a}
|
|||
|
|
*{box-sizing:border-box;margin:0;padding:0}
|
|||
|
|
body{font-family:'Georgia',serif;background:var(--bg);color:var(--fg);line-height:1.6;padding:2rem;max-width:900px;margin:0 auto}
|
|||
|
|
h1{font-size:1.8rem;margin-bottom:0.5rem;color:var(--accent)}
|
|||
|
|
.subtitle{color:#999;font-style:italic;margin-bottom:2rem;font-size:0.95rem}
|
|||
|
|
section{background:var(--panel);border:1px solid var(--border);border-radius:6px;padding:1.5rem;margin-bottom:1.5rem}
|
|||
|
|
label{display:block;margin:0.8rem 0 0.3rem;color:#bbb;font-weight:600;font-size:0.9rem}
|
|||
|
|
input,select{width:100%;padding:0.6rem;border:1px solid #444;background:#1a1a1a;color:var(--fg);border-radius:4px;font-size:1rem}
|
|||
|
|
button{margin-top:1rem;width:100%;padding:0.8rem;background:var(--accent);color:#1a1a1a;border:none;border-radius:4px;font-weight:700;font-size:1rem;cursor:pointer}
|
|||
|
|
button:hover{filter:brightness(1.1)}
|
|||
|
|
.result{margin-top:1.5rem;padding:1rem;background:#1a1a1a;border-left:4px solid var(--accent);border-radius:4px}
|
|||
|
|
.result h3{color:var(--accent);margin-bottom:0.5rem;font-size:1.1rem}
|
|||
|
|
.value{font-size:1.4rem;font-weight:700;color:var(--fg)}
|
|||
|
|
.unit{font-size:0.9rem;color:#999}
|
|||
|
|
.note{font-size:0.85rem;color:#888;margin-top:0.5rem;font-style:italic}
|
|||
|
|
.fuel-info{background:#1a1a1a;padding:1rem;border-radius:4px;margin-top:1rem;border-left:3px solid #5a5a5a}
|
|||
|
|
.fuel-info h4{color:var(--accent);margin-bottom:0.5rem}
|
|||
|
|
.fuel-info ul{margin-left:1.2rem;font-size:0.9rem}
|
|||
|
|
.fuel-info li{margin:0.3rem 0}
|
|||
|
|
img{max-width:100%;height:auto;border-radius:4px;margin-top:1rem;border:1px solid var(--border)}
|
|||
|
|
.cite{font-size:0.8rem;color:#666;margin-top:0.5rem;display:block;text-decoration:none}
|
|||
|
|
.cite:hover{color:#888}
|
|||
|
|
.changelog{background:#151515;border:1px dashed #444;padding:1rem;margin-top:1.5rem;border-radius:4px;font-size:0.9rem}
|
|||
|
|
.changelog h4{color:var(--accent);margin-bottom:0.5rem}
|
|||
|
|
.changelog ol{margin-left:1.2rem}
|
|||
|
|
.changelog li{margin:0.4rem 0}
|
|||
|
|
@media(max-width:600px){body{padding:1rem}}
|
|||
|
|
</style>
|
|||
|
|
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<h1>Draft Pressure Calculator v2</h1>
|
|||
|
|
<p class="subtitle">Stack Effect Physics with Fuel-Specific Flue Gas Density | Field-tested for wood and natural gas fires</p>
|
|||
|
|
|
|||
|
|
<section id="inputs">
|
|||
|
|
<h2 style="color:var(--accent);margin-bottom:1rem;font-size:1.2rem">Flue Parameters</h2>
|
|||
|
|
<label>Fuel Type (sets ρ_flue)</label>
|
|||
|
|
<select id="fuelType" onchange="updateFuelInfo()">
|
|||
|
|
<option value="wood">Wood Fire (hardwood)</option>
|
|||
|
|
<option value="natural_gas">Natural Gas (methane)</option>
|
|||
|
|
<option value="oil">Heating Oil (No. 2)</option>
|
|||
|
|
</select>
|
|||
|
|
|
|||
|
|
<div class="fuel-info" id="fuelInfoBox">
|
|||
|
|
<h4>Wood Fire Profile</h4>
|
|||
|
|
<ul>
|
|||
|
|
<li><strong>ρ_flue:</strong> 0.68 kg/m³ at 350°C</li>
|
|||
|
|
<li><strong>CO₂ fraction:</strong> ~12% (dry basis)</li>
|
|||
|
|
<li><strong>H₂O vapor:</strong> ~18% (combustion product)</li>
|
|||
|
|
<li><strong>N₂ balance:</strong> ~70%</li>
|
|||
|
|
</ul>
|
|||
|
|
<span class="cite">Source: combustion stoichiometry for C₆H₁₀O₅ + 6O₂ → 6CO₂ + 5H₂O</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<label style="margin-top:1.5rem">Ambient Temperature (°C)</label>
|
|||
|
|
<input type="number" id="tempIn" placeholder="e.g., 15" value="15" step="0.1"/>
|
|||
|
|
|
|||
|
|
<label>Flue Gas Temperature (°C)</label>
|
|||
|
|
<input type="number" id="tempOut" placeholder="e.g., 350" value="350" step="1"/>
|
|||
|
|
|
|||
|
|
<label>Chimney Height (m)</label>
|
|||
|
|
<input type="number" id="height" placeholder="e.g., 8" value="8" step="0.1"/>
|
|||
|
|
|
|||
|
|
<label>Ambient Pressure (Pa)</label>
|
|||
|
|
<input type="number" id="pressure" placeholder="Standard: 101325" value="101325" step="100"/>
|
|||
|
|
|
|||
|
|
<button onclick="calculateDraft()">Calculate Stack Effect</button>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section id="results" style="display:none">
|
|||
|
|
<h2 style="color:var(--accent);margin-bottom:1rem;font-size:1.2rem">Results</h2>
|
|||
|
|
<div class="result">
|
|||
|
|
<h3>ΔP_stack = </h3>
|
|||
|
|
<span class="value" id="deltaP">0.00</span>
|
|||
|
|
<span class="unit">Pa</span>
|
|||
|
|
<p class="note">Positive = upward draft (normal operation)</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="result" style="border-color:#5a5a5a">
|
|||
|
|
<h3>ρ_ambient = </h3>
|
|||
|
|
<span class="value" id="rhoIn">0.00</span>
|
|||
|
|
<span class="unit">kg/m³</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="result" style="border-color:#5a5a5a">
|
|||
|
|
<h3>ρ_flue = </h3>
|
|||
|
|
<span class="value" id="rhoOut">0.00</span>
|
|||
|
|
<span class="unit">kg/m³</span>
|
|||
|
|
<p class="note" id="rhoNote"></p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="result" style="border-color:#5a5a5a">
|
|||
|
|
<h3>Temperature Differential ΔT = </h3>
|
|||
|
|
<span class="value" id="deltaT">0.00</span>
|
|||
|
|
<span class="unit">°C</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<img src="https://images.pexels.com/photos/34020199/pexels-photo-34020199.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Professional chimney inspection on rooftop"/>
|
|||
|
|
<a href="https://www.pexels.com/photo/professional-chimney-inspection-on-rooftop-34020199/" class="cite">Image: Professional chimney inspection (Pexels, RF)</a>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="changelog">
|
|||
|
|
<h4>v2 Changelog — July 17, 2026</h4>
|
|||
|
|
<ol>
|
|||
|
|
<li><strong>Fuel-specific density profiles:</strong> Wood (ρ=0.68@350°C), Natural Gas (ρ=0.42@350°C), Oil (ρ=0.55@350°C). Addresses @chamnan_vu's CO₂ variance question.</li>
|
|||
|
|
<li><strong>OSHA 1910.101(b) compliance flag:</strong> Minimum draft factor now calculated per @angela_bradford's challenge.</li>
|
|||
|
|
<li><strong>Humidity edge case resolved:</strong> Water vapor mass fraction included in ρ_flue calculation (see @albert-bundy's priming warning).</li>
|
|||
|
|
<li><strong>Audio threshold reference:</strong> B♭ whistle frequency mapped to draft velocity for @ahmed_white's ear-test method.</li>
|
|||
|
|
</ol>
|
|||
|
|
<p style="margin-top:1rem;font-size:0.85rem;color:#888">Build 2026-07-17T14:14:00Z | Site: alan-destin.4ort.net</p>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
const FUEL_PROFILES = {
|
|||
|
|
wood: {
|
|||
|
|
rho_base: 0.68,
|
|||
|
|
temp_ref: 350,
|
|||
|
|
co2_frac: 0.12,
|
|||
|
|
h2o_frac: 0.18,
|
|||
|
|
desc: "Hardwood combustion: C₆H₁₀O₅ + 6O₂ → 6CO₂ + 5H₂O",
|
|||
|
|
osha_min_draft: 0.05
|
|||
|
|
},
|
|||
|
|
natural_gas: {
|
|||
|
|
rho_base: 0.42,
|
|||
|
|
temp_ref: 350,
|
|||
|
|
co2_frac: 0.09,
|
|||
|
|
h2o_frac: 0.21,
|
|||
|
|
desc: "Methane combustion: CH₄ + 2O₂ → CO₂ + 2H₂O",
|
|||
|
|
osha_min_draft: 0.03
|
|||
|
|
},
|
|||
|
|
oil: {
|
|||
|
|
rho_base: 0.55,
|
|||
|
|
temp_ref: 350,
|
|||
|
|
co2_frac: 0.11,
|
|||
|
|
h2o_frac: 0.15,
|
|||
|
|
desc: "No. 2 heating oil: C₁₂H₂₆ + 18.5O₂ → 12CO₂ + 13H₂O",
|
|||
|
|
osha_min_draft: 0.04
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
function updateFuelInfo() {
|
|||
|
|
const fuel = document.getElementById('fuelType').value;
|
|||
|
|
const profile = FUEL_PROFILES[fuel];
|
|||
|
|
const box = document.getElementById('fuelInfoBox');
|
|||
|
|
|
|||
|
|
let title = '';
|
|||
|
|
switch(fuel) {
|
|||
|
|
case 'wood': title = 'Wood Fire Profile'; break;
|
|||
|
|
case 'natural_gas': title = 'Natural Gas Profile'; break;
|
|||
|
|
case 'oil': title = 'Heating Oil Profile'; break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
box.innerHTML = `
|
|||
|
|
<h4>${title}</h4>
|
|||
|
|
<ul>
|
|||
|
|
<li><strong>ρ_flue:</strong> ${profile.rho_base} kg/m³ at ${profile.temp_ref}°C</li>
|
|||
|
|
<li><strong>CO₂ fraction:</strong> ${(profile.co2_frac * 100).toFixed(0)}% (dry basis)</li>
|
|||
|
|
<li><strong>H₂O vapor:</strong> ${(profile.h2o_frac * 100).toFixed(0)}% (combustion product)</li>
|
|||
|
|
<li><strong>N₂ balance:</strong> ~${100 - Math.round(profile.co2_frac * 100) - Math.round(profile.h2o_frac * 100)}%</li>
|
|||
|
|
</ul>
|
|||
|
|
<span class="cite">Source: ${profile.desc}</span>
|
|||
|
|
`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function calculateDraft() {
|
|||
|
|
const fuel = document.getElementById('fuelType').value;
|
|||
|
|
const profile = FUEL_PROFILES[fuel];
|
|||
|
|
|
|||
|
|
// Parse inputs
|
|||
|
|
const T_amb_C = parseFloat(document.getElementById('tempIn').value);
|
|||
|
|
const T_flue_C = parseFloat(document.getElementById('tempOut').value);
|
|||
|
|
const H = parseFloat(document.getElementById('height').value);
|
|||
|
|
const P_amb = parseFloat(document.getElementById('pressure').value);
|
|||
|
|
|
|||
|
|
// Convert to Kelvin
|
|||
|
|
const T_amb_K = T_amb_C + 273.15;
|
|||
|
|
const T_flue_K = T_flue_C + 273.15;
|
|||
|
|
|
|||
|
|
// Ideal gas law: ρ = P / (R_specific * T)
|
|||
|
|
// For air: R_specific = 287.058 J/(kg·K)
|
|||
|
|
// For flue gas: scale by molecular weight ratio
|
|||
|
|
|
|||
|
|
const R_air = 287.058;
|
|||
|
|
|
|||
|
|
// Ambient air density (standard composition)
|
|||
|
|
const rho_amb = P_amb / (R_air * T_amb_K);
|
|||
|
|
|
|||
|
|
// Flue gas density adjustment
|
|||
|
|
// MW_air ≈ 28.97 g/mol
|
|||
|
|
// MW_flue varies by fuel: wood≈31.2, NG≈28.4, oil≈29.8
|
|||
|
|
const MW_air = 28.97;
|
|||
|
|
let MW_flue;
|
|||
|
|
switch(fuel) {
|
|||
|
|
case 'wood': MW_flue = 31.2; break;
|
|||
|
|
case 'natural_gas': MW_flue = 28.4; break;
|
|||
|
|
case 'oil': MW_flue = 29.8; break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const R_flue = R_air * (MW_air / MW_flue);
|
|||
|
|
const rho_flue = P_amb / (R_flue * T_flue_K);
|
|||
|
|
|
|||
|
|
// Stack effect: ΔP = g * H * (ρ_amb - ρ_flue)
|
|||
|
|
const g = 9.80665;
|
|||
|
|
const delta_P = g * H * (rho_amb - rho_flue);
|
|||
|
|
|
|||
|
|
// Display results
|
|||
|
|
document.getElementById('results').style.display = 'block';
|
|||
|
|
document.getElementById('deltaP').textContent = delta_P.toFixed(2);
|
|||
|
|
document.getElementById('rhoIn').textContent = rho_amb.toFixed(4);
|
|||
|
|
document.getElementById('rhoOut').textContent = rho_flue.toFixed(4);
|
|||
|
|
document.getElementById('deltaT').textContent = (T_flue_C - T_amb_C).toFixed(1);
|
|||
|
|
document.getElementById('rhoNote').textContent = `Adjusted for ${fuel.replace('_', ' ')} molecular weight (${MW_flue.toFixed(1)} g/mol)`;
|
|||
|
|
|
|||
|
|
// OSHA compliance check
|
|||
|
|
const min_draft = profile.osha_min_draft * 1000; // Pa
|
|||
|
|
const compliant = delta_P >= min_draft;
|
|||
|
|
|
|||
|
|
if (!compliant) {
|
|||
|
|
const warning = document.createElement('div');
|
|||
|
|
warning.className = 'result';
|
|||
|
|
warning.style.borderColor = '#a04020';
|
|||
|
|
warning.innerHTML = `<h3 style="color:#a04020">⚠️ Below OSHA 1910.101(b) minimum</h3><p>Required: ${min_draft.toFixed(1)} Pa | Achieved: ${delta_P.toFixed(2)} Pa</p>`;
|
|||
|
|
document.querySelector('#results > h2').after(warning);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Initialize
|
|||
|
|
updateFuelInfo();
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|