2026-09-14 18:03:00 +02:00
|
|
|
|
//! Ventilasjon og infiltrasjon.
|
|
|
|
|
|
|
|
|
|
|
|
use crate::modell::lost::Lost;
|
|
|
|
|
|
use crate::modell::{Skjerming, VentilasjonType};
|
|
|
|
|
|
|
|
|
|
|
|
/// Infiltrasjonsluftmengde, m³/h, etter NS-EN 15242 slik NS 3031 anvender den:
|
|
|
|
|
|
///
|
|
|
|
|
|
/// `n_inf = n50 · e / (1 + (f/e) · ((q_til − q_fra) / (V · n50))²)`
|
|
|
|
|
|
///
|
|
|
|
|
|
/// `e` er skjermingskoeffisienten og `f` en anleggskoeffisient. Ved balansert ventilasjon
|
|
|
|
|
|
/// faller ubalanseleddet bort, og infiltrasjonen blir `n50 · e`.
|
|
|
|
|
|
pub fn infiltrasjonsluftmengde(l: &Lost) -> f64 {
|
|
|
|
|
|
let e = match l.skjerming {
|
|
|
|
|
|
Skjerming::Skjermet => 0.03,
|
|
|
|
|
|
Skjerming::Moderat => 0.07,
|
|
|
|
|
|
Skjerming::Utsatt => 0.10,
|
|
|
|
|
|
};
|
|
|
|
|
|
let f = 15.0;
|
|
|
|
|
|
let v = l.volum;
|
|
|
|
|
|
let q_snitt = l.ventilasjon.luftmengde * l.bra;
|
|
|
|
|
|
let (q_til, q_fra) = match l.ventilasjon.typ {
|
|
|
|
|
|
VentilasjonType::Balansert => (q_snitt, q_snitt),
|
|
|
|
|
|
VentilasjonType::Avtrekk => (0.0, q_snitt),
|
|
|
|
|
|
VentilasjonType::Naturlig => (0.0, 0.0),
|
|
|
|
|
|
};
|
|
|
|
|
|
let ubalanse = (q_til - q_fra).abs();
|
|
|
|
|
|
let nevner = if l.n50 * v > 1e-9 {
|
|
|
|
|
|
1.0 + (f / e) * (ubalanse / (v * l.n50)).powi(2)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
1.0
|
|
|
|
|
|
};
|
|
|
|
|
|
let n_inf = l.n50 * e / nevner;
|
|
|
|
|
|
n_inf * v
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-15 20:05:20 +02:00
|
|
|
|
/// Om ventilasjonen går med driftsluftmengde i time `t` av året.
|
|
|
|
|
|
pub fn i_drift(l: &Lost, t: usize) -> bool {
|
|
|
|
|
|
l.laster.driftsdag(t) && l.ventilasjon.driftstid.aktiv(t % 24)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Ventilasjonsluftmengde i time `t` av året, m³/h.
|
|
|
|
|
|
pub fn luftmengde(l: &Lost, t: usize) -> f64 {
|
|
|
|
|
|
let spesifikk = if i_drift(l, t) {
|
2026-09-14 18:03:00 +02:00
|
|
|
|
l.ventilasjon.luftmengde
|
|
|
|
|
|
} else {
|
|
|
|
|
|
l.ventilasjon.luftmengde_natt
|
|
|
|
|
|
};
|
|
|
|
|
|
spesifikk * l.bra
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Tilluftstemperatur etter varmegjenvinner (uten ettervarming), °C.
|
2026-09-15 20:05:20 +02:00
|
|
|
|
///
|
|
|
|
|
|
/// Gjenvinneren reguleres ned når den ellers ville varmet tilluften over settpunktet, slik
|
|
|
|
|
|
/// en roterende gjenvinner med turtallsregulering eller et omløpsspjeld gjør. Når det er
|
|
|
|
|
|
/// varmere ute enn inne, kjøler gjenvinneren tilluften og går for fullt.
|
2026-09-14 18:03:00 +02:00
|
|
|
|
pub fn tilluftstemperatur(l: &Lost, t_ute: f64, t_avtrekk: f64) -> f64 {
|
|
|
|
|
|
match l.ventilasjon.typ {
|
2026-09-15 20:05:20 +02:00
|
|
|
|
VentilasjonType::Balansert => {
|
|
|
|
|
|
let gjenvunnet = t_ute + l.ventilasjon.gjenvinning * (t_avtrekk - t_ute);
|
|
|
|
|
|
if gjenvunnet > t_ute {
|
|
|
|
|
|
gjenvunnet.min(l.ventilasjon.tilluft_settpunkt.max(t_ute))
|
|
|
|
|
|
} else {
|
|
|
|
|
|
gjenvunnet
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-09-14 18:03:00 +02:00
|
|
|
|
_ => t_ute,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-15 20:05:20 +02:00
|
|
|
|
/// Vifteeffekt i time `t` av året, W.
|
|
|
|
|
|
pub fn vifteeffekt(l: &Lost, t: usize) -> f64 {
|
2026-09-14 18:03:00 +02:00
|
|
|
|
if matches!(l.ventilasjon.typ, VentilasjonType::Naturlig) {
|
|
|
|
|
|
return 0.0;
|
|
|
|
|
|
}
|
2026-09-15 20:05:20 +02:00
|
|
|
|
let q = luftmengde(l, t) / 3600.0; // m³/s
|
2026-09-14 18:03:00 +02:00
|
|
|
|
l.ventilasjon.sfp * 1000.0 * q
|
|
|
|
|
|
}
|