use super::material::SemiconductorMaterial;
pub fn srh_rate(n: f64, p: f64, ni: f64, tau_n: f64, tau_p: f64) -> f64 {
let denom = tau_p * (n + ni) + tau_n * (p + ni);
if denom < 1e-300 {
return 0.0;
}
(n * p - ni * ni) / denom
}
pub fn srh_dn(n: f64, p: f64, ni: f64, tau_n: f64, tau_p: f64) -> f64 {
let denom = tau_p * (n + ni) + tau_n * (p + ni);
if denom < 1e-300 {
return 0.0;
}
let np_ni2 = n * p - ni * ni;
(p * denom - np_ni2 * tau_p) / (denom * denom)
}
pub fn srh_dp(n: f64, p: f64, ni: f64, tau_n: f64, tau_p: f64) -> f64 {
let denom = tau_p * (n + ni) + tau_n * (p + ni);
if denom < 1e-300 {
return 0.0;
}
let np_ni2 = n * p - ni * ni;
(n * denom - np_ni2 * tau_n) / (denom * denom)
}
pub fn radiative_rate(n: f64, p: f64, ni: f64, b_rad: f64) -> f64 {
b_rad * (n * p - ni * ni)
}
pub fn radiative_dn(p: f64, b_rad: f64) -> f64 {
b_rad * p
}
pub fn radiative_dp(n: f64, b_rad: f64) -> f64 {
b_rad * n
}
pub fn auger_rate(n: f64, p: f64, ni: f64, cn: f64, cp: f64) -> f64 {
(cn * n + cp * p) * (n * p - ni * ni)
}
pub fn auger_dn(n: f64, p: f64, ni: f64, cn: f64, cp: f64) -> f64 {
let np_ni2 = n * p - ni * ni;
cn * np_ni2 + (cn * n + cp * p) * p
}
pub fn auger_dp(n: f64, p: f64, ni: f64, cn: f64, cp: f64) -> f64 {
let np_ni2 = n * p - ni * ni;
cp * np_ni2 + (cn * n + cp * p) * n
}
pub fn total_recombination(n: f64, p: f64, ni: f64, mat: &SemiconductorMaterial) -> f64 {
srh_rate(n, p, ni, mat.tau_n_s, mat.tau_p_s)
+ radiative_rate(n, p, ni, mat.b_rad_cm3_s)
+ auger_rate(n, p, ni, mat.cn_auger_cm6_s, mat.cp_auger_cm6_s)
}
pub fn total_recombination_dn(n: f64, p: f64, ni: f64, mat: &SemiconductorMaterial) -> f64 {
srh_dn(n, p, ni, mat.tau_n_s, mat.tau_p_s)
+ radiative_dn(p, mat.b_rad_cm3_s)
+ auger_dn(n, p, ni, mat.cn_auger_cm6_s, mat.cp_auger_cm6_s)
}
pub fn total_recombination_dp(n: f64, p: f64, ni: f64, mat: &SemiconductorMaterial) -> f64 {
srh_dp(n, p, ni, mat.tau_n_s, mat.tau_p_s)
+ radiative_dp(n, mat.b_rad_cm3_s)
+ auger_dp(n, p, ni, mat.cn_auger_cm6_s, mat.cp_auger_cm6_s)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::solar::drift_diffusion::material::SemiconductorMaterial;
#[test]
fn srh_rate_at_equilibrium_is_zero() {
let ni = 1e10_f64;
let tau = 1e-6;
let n = ni;
let p = ni;
let r = srh_rate(n, p, ni, tau, tau);
assert!(r.abs() < 1e-6, "R_SRH at equilibrium = {r}");
}
#[test]
fn srh_minority_carrier_limit() {
let ni = 1e10_f64;
let nd = 1e16_f64;
let n = nd; let delta_p = 1e12_f64;
let p = ni * ni / nd + delta_p;
let tau_n = 1e-6;
let tau_p = 1e-6;
let r = srh_rate(n, p, ni, tau_n, tau_p);
let r_approx = delta_p / tau_p;
let rel = (r - r_approx).abs() / r_approx;
assert!(rel < 0.05, "SRH minority approx rel err = {rel}");
}
#[test]
fn total_recombination_matches_sum() {
let mat = SemiconductorMaterial::silicon();
let ni = mat.ni_cm3;
let n = 1e15_f64;
let p = 1e15_f64;
let r_total = total_recombination(n, p, ni, &mat);
let r_srh = srh_rate(n, p, ni, mat.tau_n_s, mat.tau_p_s);
let r_rad = radiative_rate(n, p, ni, mat.b_rad_cm3_s);
let r_aug = auger_rate(n, p, ni, mat.cn_auger_cm6_s, mat.cp_auger_cm6_s);
let diff = (r_total - (r_srh + r_rad + r_aug)).abs();
assert!(
diff < 1e-10 * r_total.abs().max(1e-20),
"total != sum, diff={diff}"
);
}
}