HVAC noise rating & psychrometric state
Two HVAC Voici dashboards: an octave-band Noise Criterion (NC) rating evaluator, and a moist-air psychrometric state solver with a live psychrometric-chart plot.
4.5 · HVAC noise rating (NC/NR curve evaluator)
$$\mathrm{rating}=\max_{i}\left\{f(L_{p,i},\,f_i)\right\}$$
Standard method: overlay the measured octave-band spectrum on the family of NC curves; the reported NC rating is the highest NC curve touched or exceeded by any single band — one loud band anywhere in the spectrum sets the whole rating, even if every other band is quiet. Table: classic Beranek NC curves (ASHRAE Fundamentals Ch. 48 / Engineering ToolBox); values interpolated linearly between the tabulated 5-point steps and extrapolated beyond NC-15/NC-65 using the end-segment slope.
| NC rating | — | |
| Controlling octave band | — |
import numpy as np, matplotlib.pyplot as plt freqs = [63,125,250,500,1000,2000,4000,8000] for nc in [15,25,35,45,55,65]: plt.semilogx(freqs, nc_table[nc], color='gray') plt.semilogx(freqs, measured_spl, color='red', marker='o')
4.8 · Psychrometric state & Mollier chart calculator
$$p_v=\phi\cdot p_{ws}(T),\quad W=0.62198\frac{p_v}{p-p_v},\quad h=1.006T+W(2501+1.805T)$$
Properties computed with PsychroLib (MIT license, vendored at psychrolib.js) rather than a hand-rolled solver — it's the same open-source ASHRAE Handbook Ch. 1 implementation used across Python/C/C#/R/JS psychrometric tooling, so results here match what a real engineering script would return. Dry air, standard atmospheric pressure 101.325 kPa.
| Saturation pressure pws(Tdb) | — | |
| Vapor pressure pv | — | |
| Relative humidity φ | — | |
| Humidity ratio W | — | |
| Dew point Tdp | — | |
| Wet-bulb Twb | — | |
| Enthalpy h | — |
import numpy as np, matplotlib.pyplot as plt Tdb = np.linspace(0, 45, 200) W_sat = 0.62198 * pws(Tdb) / (p_atm - pws(Tdb)) plt.plot(Tdb, W_sat*1000); plt.scatter([Tdb_input],[W_input*1000], color='red', zorder=3)
Process performance: the common HVAC air-side cycles
$$\dot Q_{\text{total}}=\dot m_{da}(h_2-h_1),\quad \dot Q_{\text{sens}}=\dot m_{da}(h_{2,\text{sens}}-h_1),\quad \text{sensible heat ratio}=\frac{\dot Q_{\text{sens}}}{\dot Q_{\text{total}}}$$
The four processes an air-handling engineer actually plots on a psych chart day to day: a plain sensible change, a cooling coil (sensible + latent, with apparatus dew point and bypass factor), a heating/humidifying process, and adiabatic mixing of two airstreams (economizer/return-air mixing). The sensible/latent split holds W fixed at the entering value while T moves to the leaving value — h2,sens is the enthalpy of that hypothetical fixed-humidity point — which is exactly how coil selection software reports Sensible Heat Ratio. Apparent Dew Point (ADP) extends the coil's process line straight to the saturation curve; Bypass Factor is how close the leaving state sits to that projected coil surface temperature (low BF = most of the air actually contacted the coil). Evaporative cooling is treated as the standard constant-wet-bulb approximation. Properties via PsychroLib, same as above.
| State 1 / A | — | |
| State 2 / B | — | |
| Result state (leaving / mixed) | — | |
| Dry-air mass flow | — | |
| Sensible heat rate | — | |
| Latent heat rate | — | |
| Total heat rate | — | |
| Sensible heat ratio (SHR) | — | |
| Apparatus dew point / bypass factor | — |
import psychrolib, numpy as np, matplotlib.pyplot as plt psychrolib.SetUnitSystem(psychrolib.SI) state1 = psychrolib.CalcPsychrometricsFromRelHum(Tdb1, RH1, P) state2 = psychrolib.CalcPsychrometricsFromRelHum(Tdb2, RH2, P) Q_sens, Q_lat, SHR = coil_load(state1, state2, mdot_da) # split at fixed-W enthalpy