Skip to content

Commit

Permalink
feat(spectre): support AC simulation (#390)
Browse files Browse the repository at this point in the history
* feat(spectre): support AC simulation

* add test

* fix sweep points and freq range

* fix: correct impedance values in ac zin test

* fix: wrong polarity of vout
  • Loading branch information
rahulk29 authored Mar 14, 2024
1 parent 01c382d commit dc3584a
Show file tree
Hide file tree
Showing 11 changed files with 849 additions and 303 deletions.
578 changes: 298 additions & 280 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion substrate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ derive_builder = "0.12"
slotmap = "1"
downcast-rs = "1"
indexmap = { version = "2", features = ["serde"] }
num = "0.4"
num = { version = "0.4", features = ["serde"] }

config = { version = "0.2.5", registry = "substrate", path = "../config" }
examples = { version = "0.5.1", registry = "substrate", path = "../docs/examples" }
Expand Down
62 changes: 62 additions & 0 deletions substrate/src/simulation/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@ pub trait FromSaved<S: Simulator, A: Analysis> {
fn from_saved(output: &<A as Analysis>::Output, key: &Self::SavedKey) -> Self;
}

impl<S, A1, A2, O1, O2> FromSaved<S, (A1, A2)> for (O1, O2)
where
S: Simulator,
A1: Analysis,
A2: Analysis,
O1: FromSaved<S, A1>,
O2: FromSaved<S, A2>,
(A1, A2): Analysis<Output = (A1::Output, A2::Output)>,
{
type SavedKey = (
<O1 as FromSaved<S, A1>>::SavedKey,
<O2 as FromSaved<S, A2>>::SavedKey,
);

fn from_saved(output: &<(A1, A2) as Analysis>::Output, key: &Self::SavedKey) -> Self {
let o1 = <O1 as FromSaved<S, A1>>::from_saved(&output.0, &key.0);
let o2 = <O2 as FromSaved<S, A2>>::from_saved(&output.1, &key.1);
(o1, o2)
}
}

/// Gets the [`FromSaved::SavedKey`] corresponding to type `T`.
pub type SavedKey<S, A, T> = <T as FromSaved<S, A>>::SavedKey;

Expand Down Expand Up @@ -91,3 +112,44 @@ pub mod tran {
}
}
}

/// AC data definitions.
pub mod ac {
use num::complex::Complex64;
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use std::sync::Arc;

/// A series of voltage vs frequency measurements from an AC simulation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Voltage(pub Arc<Vec<Complex64>>);

impl Deref for Voltage {
type Target = Vec<Complex64>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

/// A series of current vs frequency measurements from an AC simulation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Current(pub Arc<Vec<Complex64>>);

impl Deref for Current {
type Target = Vec<Complex64>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

/// The frequency points associated with an AC simulation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Freq(pub Arc<Vec<f64>>);

impl Deref for Freq {
type Target = Vec<f64>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
}
1 change: 1 addition & 0 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ spice = { version = "0.7.1", registry = "substrate", path = "../libs/spice" }
spectre = { version = "0.9.1", registry = "substrate", path = "../tools/spectre" }
ngspice = { version = "0.3.1", registry = "substrate", path = "../tools/ngspice" }
sky130pdk = { version = "0.8.1", registry = "substrate", path = "../pdks/sky130pdk" }
num = { version = "0.4.1", features = ["serde"] }

[features]
spectre = []
Expand Down
52 changes: 37 additions & 15 deletions tests/src/shared/rc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use num::complex::Complex64;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use serde::{Deserialize, Serialize};
use spectre::analysis::ac::{Ac, Sweep};
use spectre::analysis::tran::Tran;
use spectre::{Options, Spectre};
use spectre::blocks::{AcSource, Isource};
use spectre::{ErrPreset, Options, Spectre};
use substrate::block::Block;
use substrate::io::schematic::{HardwareType, Node};
use substrate::io::Signal;
use substrate::io::TestbenchIo;
use substrate::schematic::primitives::{Capacitor, Resistor};
use substrate::schematic::{Cell, CellBuilder, ExportsNestedData, Schematic};
use substrate::simulation::data::{tran, FromSaved, Save, SaveTb};
use substrate::simulation::data::{ac, tran, FromSaved, Save, SaveTb};
use substrate::simulation::options::ic;
use substrate::simulation::options::ic::InitialCondition;
use substrate::simulation::{SimulationContext, Simulator, Testbench};
Expand Down Expand Up @@ -49,22 +52,33 @@ impl Schematic<Spectre> for RcTb {
cell.connect(c.io().p, vout);
cell.connect(c.io().n, io.vss);

let isource = cell.instantiate(Isource::ac(AcSource {
dc: dec!(0),
mag: dec!(1),
phase: dec!(0),
}));
cell.connect(isource.io().p, vout);
cell.connect(isource.io().n, io.vss);

Ok(vout)
}
}

impl SaveTb<Spectre, Tran, tran::Voltage> for RcTb {
impl SaveTb<Spectre, (Tran, Ac), (tran::Voltage, ac::Voltage)> for RcTb {
fn save_tb(
ctx: &SimulationContext<Spectre>,
to_save: &Cell<Self>,
cell: &Cell<Self>,
opts: &mut <Spectre as Simulator>::Options,
) -> <tran::Voltage as FromSaved<Spectre, Tran>>::SavedKey {
tran::Voltage::save(ctx, to_save.data(), opts)
) -> <(tran::Voltage, ac::Voltage) as FromSaved<Spectre, (Tran, Ac)>>::SavedKey {
(
tran::Voltage::save(ctx, cell.data(), opts),
ac::Voltage::save(ctx, cell.data(), opts),
)
}
}

impl Testbench<Spectre> for RcTb {
type Output = (f64, f64);
type Output = (f64, f64, Complex64);
fn run(&self, sim: substrate::simulation::SimController<Spectre, Self>) -> Self::Output {
let mut opts = Options::default();
sim.set_option(
Expand All @@ -74,18 +88,26 @@ impl Testbench<Spectre> for RcTb {
},
&mut opts,
);
let vout: tran::Voltage = sim
let (tran_vout, ac_vout) = sim
.simulate(
opts,
Tran {
stop: dec!(10e-6),
..Default::default()
},
(
Tran {
stop: dec!(10e-6),
..Default::default()
},
Ac {
start: dec!(1e6),
stop: dec!(2e6),
sweep: Sweep::Linear(10),
errpreset: Some(ErrPreset::Conservative),
},
),
)
.unwrap();

let first = vout.first().unwrap();
let last = vout.last().unwrap();
(*first, *last)
let first = tran_vout.first().unwrap();
let last = tran_vout.last().unwrap();
(*first, *last, ac_vout[2])
}
}
22 changes: 17 additions & 5 deletions tests/src/sim/spectre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use crate::shared::pdk::sky130_commercial_ctx;
use crate::shared::vdivider::tb::{VdividerArrayTb, VdividerDuplicateSubcktTb};
use crate::{paths::get_path, shared::vdivider::tb::VdividerTb};
use substrate::schematic::primitives::{RawInstance, Resistor};
use substrate::simulation::data::tran::{Current, Voltage};

#[test]
fn vdivider_tran() {
Expand Down Expand Up @@ -256,7 +255,7 @@ fn spectre_can_include_sections() {
ctx: &SimulationContext<Spectre>,
cell: &Cell<Self>,
opts: &mut <Spectre as Simulator>::Options,
) -> <Voltage as FromSaved<Spectre, Tran>>::SavedKey {
) -> <tran::Voltage as FromSaved<Spectre, Tran>>::SavedKey {
tran::Voltage::save(ctx, cell.data().io().n, opts)
}
}
Expand Down Expand Up @@ -392,7 +391,7 @@ fn spectre_can_save_paths_with_flattened_instances() {
ctx: &SimulationContext<Spectre>,
cell: &Cell<Self>,
opts: &mut <Spectre as Simulator>::Options,
) -> <Current as FromSaved<Spectre, Tran>>::SavedKey {
) -> <tran::Current as FromSaved<Spectre, Tran>>::SavedKey {
tran::Current::save(ctx, cell.data().io().p, opts)
}
}
Expand Down Expand Up @@ -430,13 +429,26 @@ fn spectre_initial_condition() {
let sim_dir = get_path(test_name, "sim/");
let ctx = sky130_commercial_ctx();

let (first, _) = ctx
let (first, _, _) = ctx
.simulate(crate::shared::rc::RcTb::new(dec!(1.4)), &sim_dir)
.unwrap();
assert_relative_eq!(first, 1.4);

let (first, _) = ctx
let (first, _, _) = ctx
.simulate(crate::shared::rc::RcTb::new(dec!(2.1)), sim_dir)
.unwrap();
assert_relative_eq!(first, 2.1);
}

#[test]
fn spectre_rc_zin_ac() {
let test_name = "spectre_rc_zin_ac";
let sim_dir = get_path(test_name, "sim/");
let ctx = sky130_commercial_ctx();

let (_, _, z) = ctx
.simulate(crate::shared::rc::RcTb::new(dec!(0)), sim_dir)
.unwrap();
assert_relative_eq!(z.re, -17.286407017773225);
assert_relative_eq!(z.im, 130.3364383055986);
}
3 changes: 2 additions & 1 deletion tools/spectre/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ lazy_static = "1"
serde = { version = "1", features = ["derive"] }
tracing = "0.1"
itertools = "0.11"
psfparser = "0.1.1"
psfparser = "0.1.2"

cache = { version = "0.5.0", registry = "substrate", path = "../../libs/cache" }
scir = { version = "0.7.0", registry = "substrate", path = "../../libs/scir" }
substrate = { version = "0.8.1", registry = "substrate", path = "../../substrate" }
spice = { version = "0.7.1", registry = "substrate", path = "../../libs/spice" }
regex = "1.10.2"
num = { version = "0.4.1", features = ["serde"] }

Loading

0 comments on commit dc3584a

Please sign in to comment.