use crate::solar::drift_diffusion::bandgap_narrowing;
use crate::units::conversion::{BOLTZMANN, ELECTRON_CHARGE};
pub use crate::solar::drift_diffusion::bandgap_narrowing::BgnModel;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum StatisticsModel {
#[default]
Boltzmann,
FermiDirac,
}
pub const K_B: f64 = BOLTZMANN;
pub const Q: f64 = ELECTRON_CHARGE;
#[derive(Debug, Clone)]
pub struct SemiconductorMaterial {
pub band_gap_ev: f64,
pub ni_cm3: f64,
pub nc_cm3: f64,
pub nv_cm3: f64,
pub mu_n_cm2_vs: f64,
pub mu_p_cm2_vs: f64,
pub tau_n_s: f64,
pub tau_p_s: f64,
pub b_rad_cm3_s: f64,
pub cn_auger_cm6_s: f64,
pub cp_auger_cm6_s: f64,
pub eps_r: f64,
pub bgn_model: BgnModel,
pub statistics: StatisticsModel,
}
impl SemiconductorMaterial {
pub fn vt_at(&self, temp_k: f64) -> f64 {
K_B * temp_k / Q
}
pub fn dn_cm2_s(&self, temp_k: f64) -> f64 {
self.mu_n_cm2_vs * self.vt_at(temp_k)
}
pub fn dp_cm2_s(&self, temp_k: f64) -> f64 {
self.mu_p_cm2_vs * self.vt_at(temp_k)
}
pub fn nc_at(&self, temp_k: f64) -> f64 {
self.nc_cm3 * (temp_k / 300.0).powf(1.5)
}
pub fn nv_at(&self, temp_k: f64) -> f64 {
self.nv_cm3 * (temp_k / 300.0).powf(1.5)
}
pub fn is_degenerate_for_doping(&self, temp_k: f64, nd_max: f64, na_max: f64) -> bool {
nd_max > 0.5 * self.nc_at(temp_k) || na_max > 0.5 * self.nv_at(temp_k)
}
pub fn dn_cm2_s_fd(&self, temp_k: f64, n_local_cm3: f64) -> f64 {
use super::fermi_dirac::{f_half, f_minus_half, joyce_dixon_eta};
let vt = self.vt_at(temp_k);
let nc = self.nc_at(temp_k);
if n_local_cm3 < 0.1 * nc {
self.mu_n_cm2_vs * vt
} else {
let u = n_local_cm3 / nc;
let eta = joyce_dixon_eta(u);
let f12 = f_half(eta);
let fm12 = f_minus_half(eta).max(1e-30);
self.mu_n_cm2_vs * vt * 2.0 * f12 / fm12
}
}
pub fn dp_cm2_s_fd(&self, temp_k: f64, p_local_cm3: f64) -> f64 {
use super::fermi_dirac::{f_half, f_minus_half, joyce_dixon_eta};
let vt = self.vt_at(temp_k);
let nv = self.nv_at(temp_k);
if p_local_cm3 < 0.1 * nv {
self.mu_p_cm2_vs * vt
} else {
let u = p_local_cm3 / nv;
let eta = joyce_dixon_eta(u);
let f12 = f_half(eta);
let fm12 = f_minus_half(eta).max(1e-30);
self.mu_p_cm2_vs * vt * 2.0 * f12 / fm12
}
}
pub fn n_ie_squared(&self, temp_k: f64, nd_cm3: f64, na_cm3: f64) -> f64 {
let ni2 = self.ni_cm3 * self.ni_cm3;
let n_total = nd_cm3 + na_cm3;
match self.bgn_model {
BgnModel::None => ni2,
BgnModel::Slotboom => {
let de_g = bandgap_narrowing::slotboom_delta_eg_ev(n_total);
bandgap_narrowing::ni_eff_squared_cm6(self.ni_cm3, de_g, self.vt_at(temp_k))
}
BgnModel::Klaassen => {
let de_g = bandgap_narrowing::klaassen_delta_eg_ev(n_total);
bandgap_narrowing::ni_eff_squared_cm6(self.ni_cm3, de_g, self.vt_at(temp_k))
}
BgnModel::Harmon1994 => {
let is_n_type = nd_cm3 >= na_cm3;
let de_g = bandgap_narrowing::harmon1994_gaas_delta_eg_ev(n_total, is_n_type);
bandgap_narrowing::ni_eff_squared_cm6(self.ni_cm3, de_g, self.vt_at(temp_k))
}
}
}
pub fn silicon() -> Self {
SemiconductorMaterial {
band_gap_ev: 1.12,
ni_cm3: 1.0e10,
nc_cm3: 2.8e19,
nv_cm3: 1.04e19,
mu_n_cm2_vs: 1350.0,
mu_p_cm2_vs: 480.0,
tau_n_s: 1.0e-6,
tau_p_s: 1.0e-6,
b_rad_cm3_s: 2.0e-15,
cn_auger_cm6_s: 2.8e-31,
cp_auger_cm6_s: 9.9e-32,
eps_r: 11.7,
bgn_model: BgnModel::None,
statistics: StatisticsModel::Boltzmann,
}
}
pub fn gaas() -> Self {
SemiconductorMaterial {
band_gap_ev: 1.42,
ni_cm3: 1.79e6,
nc_cm3: 4.7e17,
nv_cm3: 7.0e18,
mu_n_cm2_vs: 8500.0,
mu_p_cm2_vs: 400.0,
tau_n_s: 1.0e-8,
tau_p_s: 1.0e-8,
b_rad_cm3_s: 1.0e-10,
cn_auger_cm6_s: 1.0e-30,
cp_auger_cm6_s: 1.0e-30,
eps_r: 12.9,
bgn_model: BgnModel::Harmon1994,
statistics: StatisticsModel::FermiDirac,
}
}
}