use dune_raw::VarType;
use crate::circuit::{Circuit, VarKind};
use crate::engine::{Engine, TranParams};
use crate::error::Error;
use crate::options::Options;
use crate::solution::Solution;
#[derive(Clone, Debug)]
pub struct Tran {
pub solution: Solution,
pub notes: Vec<String>,
}
impl Circuit {
pub fn tran(
&self,
opts: &Options,
tstep: f64,
tstop: f64,
tstart: f64,
tmax: Option<f64>,
uic: bool,
) -> Result<Tran, Error> {
let step_ok = tstep > 0.0 && tstep.is_finite();
if !step_ok {
return Err(Error::Build(".tran step must be positive".into()));
}
let times_ok = tstop > 0.0 && tstop.is_finite() && tstop > tstart && tstart >= 0.0;
if !times_ok {
return Err(Error::Build(".tran times are inconsistent".into()));
}
if let Some(d) = opts.tmax_divisor
&& !(d >= 1.0 && d.is_finite())
{
return Err(Error::Build(format!(
"tmax divisor must be a finite number >= 1, got {d}"
)));
}
let (noise_opts, noise_note) = self.noise_tran_options(opts, tstep, tstop, tstart, tmax)?;
let opts = noise_opts.as_ref().unwrap_or(opts);
let built = self.build(opts)?;
let mut notes = built.notes.clone();
notes.extend(noise_note);
let mut engine = Engine::new(built);
if opts.dev_noise {
let nt = opts.dev_noise_step.unwrap_or(tstep);
engine.set_dev_noise(crate::devnoise::DevNoise::new(
nt,
opts.seed,
opts.temp,
tstop,
engine.vars.len(),
));
}
let rows = engine.tran(
opts,
&TranParams {
tstep,
tstop,
tstart,
tmax,
uic,
},
)?;
notes.extend(engine.tran_notes());
notes.extend(engine.dev_noise_notes());
let mut variables = vec![("time".to_string(), VarType::Time)];
let mut columns = vec![rows.iter().map(|(t, _)| *t).collect::<Vec<f64>>()];
for i in 1..engine.vars.len() {
let name = &engine.vars.names[i];
match engine.vars.kinds[i] {
VarKind::Node if crate::circuit::saved_node(name) => {
variables.push((format!("v({name})"), VarType::Voltage));
columns.push(rows.iter().map(|(_, sol)| sol[i]).collect());
}
VarKind::Branch => {
variables.push((format!("i({name})"), VarType::Current));
columns.push(rows.iter().map(|(_, sol)| sol[i]).collect());
}
_ => {}
}
}
Ok(Tran {
solution: Solution {
plotname: "Transient Analysis".to_string(),
variables,
data: dune_raw::Data::Real(columns),
scale: Some(0),
},
notes,
})
}
}