multi_core_inverter: add some stimuli and measurements
This commit is contained in:
@@ -37,23 +37,30 @@
|
|||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use coremem::geom::{Coord as _, Meters, Torus};
|
use coremem::geom::{Coord as _, Meters, Torus};
|
||||||
|
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor};
|
||||||
|
use coremem::meas;
|
||||||
use coremem::real::{self, Real as _};
|
use coremem::real::{self, Real as _};
|
||||||
use coremem::sim::spirv::{self, SpirvSim};
|
use coremem::sim::spirv::{self, SpirvSim};
|
||||||
use coremem::sim::units::Seconds;
|
use coremem::sim::units::Seconds;
|
||||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor};
|
use coremem::stim::{CurlStimulus, Gated, Sinusoid1, TimeVarying as _};
|
||||||
use coremem::Driver;
|
use coremem::Driver;
|
||||||
|
|
||||||
type R = real::R32;
|
type R = real::R32;
|
||||||
type Mat = IsoConductorOr<R, Ferroxcube3R1MH>;
|
type Mat = IsoConductorOr<R, Ferroxcube3R1MH>;
|
||||||
|
// type Backend = spirv::CpuBackend;
|
||||||
type Backend = spirv::WgpuBackend;
|
type Backend = spirv::WgpuBackend;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
coremem::init_logging();
|
coremem::init_logging();
|
||||||
coremem::init_debug();
|
coremem::init_debug();
|
||||||
let um = |n| n as f32 * 1e-6;
|
let um = |n| n as f32 * 1e-6;
|
||||||
let ns = |n| n as f32 * 1e-9;
|
// let ns = |n| n as f32 * 1e-9;
|
||||||
|
let ps = |n| n as f32 * 1e-12;
|
||||||
let feat_size = um(10);
|
let feat_size = um(10);
|
||||||
|
|
||||||
|
let input_magnitude = 1.0e9;
|
||||||
|
let clock_phase_duration = ps(1000);
|
||||||
|
|
||||||
let s_major = um(160);
|
let s_major = um(160);
|
||||||
let s_minor = um(30);
|
let s_minor = um(30);
|
||||||
let io_major = um(80);
|
let io_major = um(80);
|
||||||
@@ -64,42 +71,106 @@ fn main() {
|
|||||||
let sx = |n| um((n+1) * 400);
|
let sx = |n| um((n+1) * 400);
|
||||||
let sy = um(400);
|
let sy = um(400);
|
||||||
let sz = um(280);
|
let sz = um(280);
|
||||||
let couplingx = |n| sx(n) - um(200);
|
let couplingx = |n| sx(n) + um(200);
|
||||||
|
|
||||||
let sim_bounds = Meters::new(sx(4), sy * 2.0, sz * 2.0);
|
let sim_bounds = Meters::new(sx(4), sy * 2.0, sz * 2.0);
|
||||||
let sim_padding = Meters::new(um(80), um(80), um(80));
|
let sim_padding = Meters::new(um(80), um(80), um(80));
|
||||||
let duration = Seconds(ns(1));
|
|
||||||
|
|
||||||
let drive0 = Torus::new_xz(Meters::new(sx(0) - s_major, sy, sz), io_major, io_minor);
|
let drive0 = Torus::new_xz(Meters::new(sx(0) - s_major, sy, sz), io_major, io_minor);
|
||||||
let sense3 = Torus::new_xz(Meters::new(sx(3) + s_major, sy, sz), io_major, io_minor);
|
let sense3 = Torus::new_xz(Meters::new(sx(3) + s_major, sy, sz), io_major, io_minor);
|
||||||
let ctl = |n| Torus::new_yz(Meters::new(sx(n), sy + s_major, sz), io_major, io_minor);
|
let ctl = |n| Torus::new_yz(Meters::new(sx(n), sy + s_major, sz), io_major, io_minor);
|
||||||
let s = |n| Torus::new_xy(Meters::new(sx(n), sy, sz), s_major, s_minor);
|
let s = |n| Torus::new_xy(Meters::new(sx(n), sy, sz), s_major, s_minor);
|
||||||
|
// coupling(n) is the wire which couples core n into core n+1
|
||||||
let coupling = |n| Torus::new_xz(Meters::new(couplingx(n), sy, sz), coupling_major, coupling_minor);
|
let coupling = |n| Torus::new_xz(Meters::new(couplingx(n), sy, sz), coupling_major, coupling_minor);
|
||||||
|
|
||||||
|
let input = |region: &Torus, cycle: u32, direction: i32| {
|
||||||
|
let area = region.cross_section();
|
||||||
|
let amp = direction as f32 * input_magnitude / area;
|
||||||
|
let start = clock_phase_duration * cycle as f32;
|
||||||
|
let wave = Gated::new(amp, start, start + clock_phase_duration);
|
||||||
|
// let wave = Sinusoid1::from_wavelength(direction as f32 * input_magnitude / area, clock_phase_duration * 2.0)
|
||||||
|
// .half_cycle()
|
||||||
|
// .shifted(clock_phase_duration * cycle as f32);
|
||||||
|
CurlStimulus::new(
|
||||||
|
region.clone(),
|
||||||
|
wave.clone(),
|
||||||
|
region.center(),
|
||||||
|
region.axis(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>());
|
let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>());
|
||||||
let ferro_mat = wire_mat;
|
// let ferro_mat = wire_mat;
|
||||||
// let ferro_mat = Ferroxcube3R1MH::new(); // uncomment when ready to simulate for real
|
let ferro_mat = Ferroxcube3R1MH::new();
|
||||||
|
|
||||||
let mut driver = Driver::new(SpirvSim::<R, Mat, Backend>::new(
|
let mut driver = Driver::new(SpirvSim::<R, Mat, Backend>::new(
|
||||||
sim_bounds.to_index(feat_size), feat_size,
|
sim_bounds.to_index(feat_size), feat_size,
|
||||||
));
|
));
|
||||||
driver.add_classical_boundary_explicit::<R, _>(sim_padding);
|
driver.add_classical_boundary_explicit::<R, _>(sim_padding);
|
||||||
|
|
||||||
|
//////// create the wires and toroids
|
||||||
driver.fill_region(&drive0, wire_mat);
|
driver.fill_region(&drive0, wire_mat);
|
||||||
driver.fill_region(&sense3, wire_mat);
|
driver.fill_region(&sense3, wire_mat);
|
||||||
for core in 0..4 {
|
for core in 0..4 {
|
||||||
driver.fill_region(&s(core), ferro_mat);
|
driver.fill_region(&s(core), ferro_mat);
|
||||||
driver.fill_region(&ctl(core), wire_mat);
|
driver.fill_region(&ctl(core), wire_mat);
|
||||||
if core != 0 {
|
if core != 3 {
|
||||||
driver.fill_region(&coupling(core), wire_mat);
|
driver.fill_region(&coupling(core), wire_mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix = "out/applications/multi_core_inverter/0/";
|
//////// monitor some measurements
|
||||||
|
// driver.add_measurement(meas::CurrentLoop::new("drv0", drive0.clone()));
|
||||||
|
for core in 0..4 {
|
||||||
|
driver.add_measurement(meas::CurrentLoop::new(
|
||||||
|
&format!("drive{}", core),
|
||||||
|
ctl(core),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for core in 0..3 {
|
||||||
|
driver.add_measurement(meas::CurrentLoop::new(
|
||||||
|
&format!("sense{}", core),
|
||||||
|
coupling(core),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
for core in 0..4 {
|
||||||
|
driver.add_measurement(meas::MagneticLoop::new(
|
||||||
|
&format!("state{}", core),
|
||||||
|
s(core),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
driver.add_measurement(meas::CurrentLoop::new("sense3", sense3.clone()));
|
||||||
|
|
||||||
|
//////// create the stimuli
|
||||||
|
// CTL{n} effectively leads CTL{n-1}
|
||||||
|
// or: at time t, CTL{n} is at cycle[t+n]
|
||||||
|
// where cycle[t] is defined by CTL[0](t):
|
||||||
|
// 0, +Vdd, +Vdd, +Vdd
|
||||||
|
// TODO: this is wrong (as is the diagram in the blog)! CTL0, being an inverter,
|
||||||
|
// needs -Vdd to recharge to +polarization
|
||||||
|
let cycles = 1;
|
||||||
|
let duration = Seconds(clock_phase_duration * (cycles + 2) as f32);
|
||||||
|
for cycle in 0..cycles {
|
||||||
|
for core in 0..1 { // TODO: core 0
|
||||||
|
let dir = 1;
|
||||||
|
//let dir = if (cycle+core) % 4 == 0 {
|
||||||
|
// 0
|
||||||
|
//} else {
|
||||||
|
// 1
|
||||||
|
//};
|
||||||
|
if dir != 0 {
|
||||||
|
// micro opt/safety: don't place zero-magnitude stimuli
|
||||||
|
driver.add_stimulus(input(&ctl(core), cycle, dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let prefix = "out/applications/multi_core_inverter/2/";
|
||||||
let _ = std::fs::create_dir_all(&prefix);
|
let _ = std::fs::create_dir_all(&prefix);
|
||||||
// driver.add_state_file(&*format!("{}state.bc", prefix), 9600);
|
// driver.add_state_file(&*format!("{}state.bc", prefix), 9600);
|
||||||
driver.add_serializer_renderer(&*format!("{}frame-", prefix), 36000, None);
|
driver.add_serializer_renderer(&*format!("{}frame-", prefix), 400, None);
|
||||||
driver.add_csv_renderer(&*format!("{}meas.csv", prefix), 400, None);
|
driver.add_csv_renderer(&*format!("{}meas.csv", prefix), 100, None);
|
||||||
driver.set_steps_per_stim(200);
|
driver.set_steps_per_stim(100);
|
||||||
|
|
||||||
driver.step_until(duration);
|
driver.step_until(duration);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user