#[inline]
pub fn pvwatts_ac(pdc: f64, pdc0: f64, eta_inv_nom: f64, eta_inv_ref: f64) -> f64 {
if pdc <= 0.0 || pdc0 <= 0.0 {
return 0.0;
}
let pac0 = eta_inv_nom * pdc0;
let zeta = pdc / pdc0;
let eta = (eta_inv_nom / eta_inv_ref) * (-0.0162 * zeta - 0.0059 / zeta + 0.9858);
let power_ac = eta * pdc;
power_ac.clamp(0.0, pac0)
}
#[inline]
pub fn pvwatts_multi(pdc: &[f64], pdc0: f64, eta_inv_nom: f64, eta_inv_ref: f64) -> f64 {
let total_pdc: f64 = pdc.iter().sum();
pvwatts_ac(total_pdc, pdc0, eta_inv_nom, eta_inv_ref)
}
#[allow(clippy::too_many_arguments)]
fn sandia_eff(
v_dc: f64, p_dc: f64,
p_aco: f64, p_dco: f64, v_dco: f64, p_so: f64,
c0: f64, c1: f64, c2: f64, c3: f64,
) -> f64 {
let a = p_dco * (1.0 + c1 * (v_dc - v_dco));
let b = p_so * (1.0 + c2 * (v_dc - v_dco));
let c = c0 * (1.0 + c3 * (v_dc - v_dco));
let mut denom = a - b;
if denom.abs() < 1e-6 {
denom = 1e-6; }
(p_aco / denom - c * denom) * (p_dc - b) + c * (p_dc - b).powi(2)
}
#[allow(clippy::too_many_arguments)]
#[inline]
pub fn sandia(
v_dc: f64, p_dc: f64,
p_aco: f64, p_dco: f64, v_dco: f64, p_so: f64,
c0: f64, c1: f64, c2: f64, c3: f64, p_nt: f64,
) -> f64 {
let power_ac = sandia_eff(v_dc, p_dc, p_aco, p_dco, v_dco, p_so, c0, c1, c2, c3);
sandia_limits(power_ac, p_dc, p_aco, p_nt, p_so)
}
fn sandia_limits(power_ac: f64, p_dc: f64, p_aco: f64, p_nt: f64, p_so: f64) -> f64 {
if p_dc < p_so {
return -p_nt.abs();
}
power_ac.min(p_aco)
}
#[allow(clippy::too_many_arguments)]
#[inline]
pub fn sandia_multi(
v_dc: &[f64], p_dc: &[f64],
p_aco: f64, p_dco: f64, v_dco: f64, p_so: f64,
c0: f64, c1: f64, c2: f64, c3: f64, p_nt: f64,
) -> f64 {
assert_eq!(v_dc.len(), p_dc.len(), "v_dc and p_dc must have the same length");
let power_dc_total: f64 = p_dc.iter().sum();
if power_dc_total == 0.0 {
return sandia_limits(0.0, power_dc_total, p_aco, p_nt, p_so);
}
let mut power_ac = 0.0;
for (vdc_i, pdc_i) in v_dc.iter().zip(p_dc.iter()) {
let weight = pdc_i / power_dc_total;
power_ac += weight * sandia_eff(*vdc_i, power_dc_total, p_aco, p_dco, v_dco, p_so, c0, c1, c2, c3);
}
sandia_limits(power_ac, power_dc_total, p_aco, p_nt, p_so)
}
#[inline]
pub fn adr(
v_dc: f64,
p_dc: f64,
p_nom: f64,
v_nom: f64,
pac_max: f64,
p_nt: f64,
adr_coeffs: [f64; 9],
) -> f64 {
if v_dc <= 0.0 || p_dc <= 0.0 {
return -p_nt.abs();
}
let pdc = p_dc / p_nom;
let vdc = v_dc / v_nom;
let poly = [
1.0,
pdc,
pdc * pdc,
vdc - 1.0,
pdc * (vdc - 1.0),
pdc * pdc * (vdc - 1.0),
1.0 / vdc - 1.0,
pdc * (1.0 / vdc - 1.0),
pdc * pdc * (1.0 / vdc - 1.0),
];
let p_loss: f64 = adr_coeffs
.iter()
.zip(poly.iter())
.map(|(c, p)| c * p)
.sum();
let power_ac = p_nom * (pdc - p_loss);
power_ac.clamp(-p_nt.abs(), pac_max)
}