#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IgbtParams {
pub vth: f64,
pub k: f64,
pub vce_sat: f64,
}
impl Default for IgbtParams {
fn default() -> Self {
Self {
vth: 5.0,
k: 5.0,
vce_sat: 2.0,
}
}
}
pub struct IgbtCompanion {
pub gm: f64,
pub g_ce: f64,
pub ids: f64,
pub i_eq: f64,
}
pub fn igbt_companion(vge: f64, vce: f64, params: &IgbtParams) -> IgbtCompanion {
let vgs_eff = vge - params.vth;
if vgs_eff <= 0.0 {
return IgbtCompanion {
gm: 0.0,
g_ce: 0.0,
ids: 0.0,
i_eq: 0.0,
};
}
let ids = if vce >= vgs_eff {
0.5 * params.k * vgs_eff * vgs_eff
} else {
params.k * (vgs_eff - vce / 2.0) * vce
};
let ids = ids.max(0.0);
let gm = if vce >= vgs_eff {
params.k * vgs_eff } else {
params.k * vce };
let gm = gm.max(0.0);
let g_ce = if params.vce_sat > 0.0 && ids > 0.0 {
ids / params.vce_sat
} else {
0.0
};
let i_eq = ids - gm * vge - g_ce * vce;
IgbtCompanion {
gm,
g_ce,
ids,
i_eq,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn igbt_cutoff_when_vge_below_vth() {
let params = IgbtParams::default(); let c = igbt_companion(0.0, 10.0, ¶ms);
assert_eq!(c.ids, 0.0);
assert_eq!(c.gm, 0.0);
assert_eq!(c.g_ce, 0.0);
assert_eq!(c.i_eq, 0.0);
}
#[test]
fn igbt_cutoff_at_threshold() {
let params = IgbtParams::default(); let c = igbt_companion(5.0, 10.0, ¶ms);
assert_eq!(c.ids, 0.0);
assert_eq!(c.gm, 0.0);
}
#[test]
fn igbt_conducts_in_saturation() {
let params = IgbtParams::default(); let c = igbt_companion(10.0, 8.0, ¶ms);
assert!(
c.ids > 0.0,
"ids should be positive in saturation, got {}",
c.ids
);
assert!(
c.gm > 0.0,
"gm should be positive in saturation, got {}",
c.gm
);
let expected_ids = 0.5 * 5.0 * 5.0_f64.powi(2);
assert!(
(c.ids - expected_ids).abs() < 1e-9,
"ids={} expected {}",
c.ids,
expected_ids
);
}
#[test]
fn igbt_conducts_in_triode() {
let params = IgbtParams::default(); let c = igbt_companion(10.0, 2.0, ¶ms);
assert!(
c.ids > 0.0,
"ids should be positive in triode, got {}",
c.ids
);
let expected_ids = 5.0 * (5.0 - 2.0 / 2.0) * 2.0;
assert!(
(c.ids - expected_ids).abs() < 1e-9,
"ids={} expected {}",
c.ids,
expected_ids
);
}
#[test]
fn igbt_g_ce_is_ids_over_vce_sat() {
let params = IgbtParams::default(); let c = igbt_companion(10.0, 8.0, ¶ms);
let expected_g_ce = c.ids / params.vce_sat;
assert!(
(c.g_ce - expected_g_ce).abs() < 1e-9,
"g_ce={} expected ids/vce_sat={}",
c.g_ce,
expected_g_ce
);
}
}