diff --git a/crates/applications/multi_core_inverter/src/main.rs b/crates/applications/multi_core_inverter/src/main.rs index 9ee49af..42c7990 100644 --- a/crates/applications/multi_core_inverter/src/main.rs +++ b/crates/applications/multi_core_inverter/src/main.rs @@ -36,13 +36,14 @@ //! $ pushd crates/coremem; cargo run --release --bin viewer ../../out/applications/multi_core_inverter/0/ ; popd //! ``` +use coremem::cross::compound::list::{self, Prependable}; use coremem::geom::{Coord as _, Meters, Torus}; use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor}; use coremem::meas; use coremem::real::{self, Real as _}; use coremem::sim::spirv::{self, SpirvSim}; use coremem::sim::units::Seconds; -use coremem::stim::{CurlStimulus, Exp, Gated, Sinusoid1, TimeVarying as _}; +use coremem::stim::{CurlStimulus, Exp, Gated, Shifted}; use coremem::Driver; type R = real::R32; @@ -60,6 +61,52 @@ enum DriveType { Float, } +struct HoldHigh; +struct ReleaseHigh; +struct HoldLow; +struct ReleaseLow; +struct Float; + +impl HoldHigh { + fn stim( + &self, prev: P, p: Params, cycle: u32, r: Torus + ) -> list::Prepended { + prev.prepend(control_signal_hold(p, r, cycle, DriveType::HoldHigh)) + } +} + +impl ReleaseHigh { + fn stim( + &self, prev: P, p: Params, cycle: u32, r: Torus + ) -> list::Prepended { + prev.prepend(control_signal_release(p, r, cycle, DriveType::ReleaseHigh)) + } +} + +impl HoldLow { + fn stim( + &self, prev: P, p: Params, cycle: u32, r: Torus + ) -> list::Prepended { + prev.prepend(control_signal_hold(p, r, cycle, DriveType::HoldLow)) + } +} + +impl ReleaseLow { + fn stim( + &self, prev: P, p: Params, cycle: u32, r: Torus + ) -> list::Prepended { + prev.prepend(control_signal_release(p, r, cycle, DriveType::ReleaseLow)) + } +} + +impl Float { + fn stim

( + &self, prev: P, _p: Params, _cycle: u32, _r: Torus + ) -> P { + prev + } +} + impl DriveType { fn direction(&self) -> i32 { use DriveType::*; @@ -83,6 +130,40 @@ impl DriveType { } } +#[derive(Copy, Clone)] +struct Params { + input_magnitude: f32, + clock_phase_duration: f32, + clock_decay: f32, // exp decay half-life +} + +type HoldStim = CurlStimulus>; +type ReleaseStim = CurlStimulus>>>; +fn control_signal_hold(params: Params, region: Torus, cycle: u32, ty: DriveType) -> HoldStim { + let area = region.cross_section(); + let amp = ty.direction() as f32 * params.input_magnitude / area; + let start = params.clock_phase_duration * cycle as f32; + // simple square wave: + let wave = Gated::new(amp, start, start + params.clock_phase_duration); + CurlStimulus::new( + region.clone(), + wave.clone(), + ) +} + +fn control_signal_release(params: Params, region: Torus, cycle: u32, ty: DriveType) -> ReleaseStim { + let area = region.cross_section(); + let amp = ty.direction() as f32 * params.input_magnitude / area; + let start = params.clock_phase_duration * cycle as f32; + // decaying exponential wave: + let wave = Exp::new_at(amp, start, params.clock_decay); + CurlStimulus::new( + region.clone(), + wave.clone(), + ) +} + + fn main() { coremem::init_logging(); // coremem::init_debug(); @@ -91,9 +172,11 @@ fn main() { let ps = |n| n as f32 * 1e-12; let feat_size = um(10); - let input_magnitude = 1.0e9; - let clock_phase_duration = ps(4000); - let clock_decay = ps(250); // exp decay half-life + let params = Params { + input_magnitude: 1.0e9, + clock_phase_duration: ps(4000), + clock_decay: ps(250), + }; // 's' = core (ferromagnetic part) let s_major = um(160); @@ -123,83 +206,56 @@ fn main() { 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 control_signal = |driver: &mut Driver, region: &Torus, cycle: u32, ty: DriveType| { - let area = region.cross_section(); - let amp = ty.direction() as f32 * input_magnitude / area; - let start = clock_phase_duration * cycle as f32; - if ty.is_hold() { - // simple square wave: - let wave = Gated::new(amp, start, start + clock_phase_duration); - let stim = CurlStimulus::new( - region.clone(), - wave.clone(), - ); - driver.add_stimulus(stim); - } else if ty.is_release() { - // decaying exponential wave: - let wave = Exp::new_at(amp, start, clock_decay); - let stim = CurlStimulus::new( - region.clone(), - wave.clone(), - ); - driver.add_stimulus(stim); - } // else: Float - // sine wave (untested): - // 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); - }; - + //////// define the control signals/transitions // each row N denotes the drive currents at clock cycle N. // each col M denotes the drive current at core M. - use DriveType::*; // let s0_init_state = HoldHigh; // logic high let s0_init_state = HoldLow; // logic low let s0_rel_state = ReleaseLow; - let drive_map = [ + let drive_map = ( // charge each device to '1' - [s0_init_state,HoldHigh, HoldHigh, HoldHigh, HoldHigh], + (s0_init_state,HoldHigh, HoldHigh, HoldHigh, HoldHigh), // this is when we'd ordinarily open S0 for write - [s0_rel_state, HoldHigh, HoldHigh, HoldHigh, HoldHigh], + (s0_rel_state, HoldHigh, HoldHigh, HoldHigh, HoldHigh), // this is when S0 would ordinarily receive a write - [Float, HoldHigh, HoldHigh, HoldHigh, HoldHigh], + (Float, HoldHigh, HoldHigh, HoldHigh, HoldHigh), // open S1 for write - [Float, ReleaseHigh, HoldHigh, HoldHigh, HoldHigh], + (Float, ReleaseHigh, HoldHigh, HoldHigh, HoldHigh), // write S0' => S1 - [HoldLow, Float, HoldHigh, HoldHigh, HoldHigh], + (HoldLow, Float, HoldHigh, HoldHigh, HoldHigh), // open S2 for write - [HoldLow, Float, ReleaseHigh, HoldHigh, HoldHigh], + (HoldLow, Float, ReleaseHigh, HoldHigh, HoldHigh), // write S1' => S2 - [HoldLow, HoldLow, Float, HoldHigh, HoldHigh], + (HoldLow, HoldLow, Float, HoldHigh, HoldHigh), // open S3 for write - [HoldLow, HoldLow, Float, ReleaseHigh, HoldHigh], + (HoldLow, HoldLow, Float, ReleaseHigh, HoldHigh), // write S2' => S3; RESET S0 - [HoldHigh, HoldLow, HoldLow, Float, HoldHigh], + (HoldHigh, HoldLow, HoldLow, Float, HoldHigh), // open S4 for write - [HoldHigh, HoldLow, HoldLow, Float, ReleaseHigh], + (HoldHigh, HoldLow, HoldLow, Float, ReleaseHigh), // write S3' => S4; RESET S1 - [HoldHigh, HoldHigh, HoldLow, HoldLow, Float], + (HoldHigh, HoldHigh, HoldLow, HoldLow, Float), // open S0 for write - [ReleaseHigh, HoldHigh, HoldLow, HoldLow, Float], + (ReleaseHigh, HoldHigh, HoldLow, HoldLow, Float), // write S4' => output; RESET S2 - [Float, HoldHigh, HoldHigh, HoldLow, HoldLow], + (Float, HoldHigh, HoldHigh, HoldLow, HoldLow), // open S1 for write - [Float, ReleaseHigh, HoldHigh, HoldLow, HoldLow], - ]; + (Float, ReleaseHigh, HoldHigh, HoldLow, HoldLow), + ); + let num_cores = 5; + let num_cycles = 14; let wire_mat = IsomorphicConductor::new(1e6f32.cast::()); // let ferro_mat = wire_mat; let ferro_mat = Ferroxcube3R1MH::new(); - let num_cores = drive_map[0].len(); let last_core = num_cores - 1; let mut driver = Driver::new(Sim::new( @@ -246,17 +302,96 @@ fn main() { } - let cycles = drive_map.len() as u32; - let duration = Seconds(clock_phase_duration * (cycles + 3) as f32); + let duration = Seconds(params.clock_phase_duration * (num_cycles + 3) as f32); - for cycle in 0..cycles { - for core in 0..num_cores { - // current polarity of the drive wires is inverted in this model v.s. the blog article, - // so invert our currents in order to achieve the magnetic states of the article. - let sig = drive_map[cycle as usize][core as usize]; - control_signal(&mut driver, &ctl(core), cycle, sig); - } - } + let stim = list::Empty::default(); + + let stim = drive_map.0.0.stim(stim, params, 0, ctl(0)); + let stim = drive_map.0.1.stim(stim, params, 0, ctl(1)); + let stim = drive_map.0.2.stim(stim, params, 0, ctl(2)); + let stim = drive_map.0.3.stim(stim, params, 0, ctl(3)); + let stim = drive_map.0.4.stim(stim, params, 0, ctl(4)); + + let stim = drive_map.1.0.stim(stim, params, 1, ctl(0)); + let stim = drive_map.1.1.stim(stim, params, 1, ctl(1)); + let stim = drive_map.1.2.stim(stim, params, 1, ctl(2)); + let stim = drive_map.1.3.stim(stim, params, 1, ctl(3)); + let stim = drive_map.1.4.stim(stim, params, 1, ctl(4)); + + let stim = drive_map.2.0.stim(stim, params, 2, ctl(0)); + let stim = drive_map.2.1.stim(stim, params, 2, ctl(1)); + let stim = drive_map.2.2.stim(stim, params, 2, ctl(2)); + let stim = drive_map.2.3.stim(stim, params, 2, ctl(3)); + let stim = drive_map.2.4.stim(stim, params, 2, ctl(4)); + + let stim = drive_map.3.0.stim(stim, params, 3, ctl(0)); + let stim = drive_map.3.1.stim(stim, params, 3, ctl(1)); + let stim = drive_map.3.2.stim(stim, params, 3, ctl(2)); + let stim = drive_map.3.3.stim(stim, params, 3, ctl(3)); + let stim = drive_map.3.4.stim(stim, params, 3, ctl(4)); + + let stim = drive_map.4.0.stim(stim, params, 4, ctl(0)); + let stim = drive_map.4.1.stim(stim, params, 4, ctl(1)); + let stim = drive_map.4.2.stim(stim, params, 4, ctl(2)); + let stim = drive_map.4.3.stim(stim, params, 4, ctl(3)); + let stim = drive_map.4.4.stim(stim, params, 4, ctl(4)); + + let stim = drive_map.5.0.stim(stim, params, 5, ctl(0)); + let stim = drive_map.5.1.stim(stim, params, 5, ctl(1)); + let stim = drive_map.5.2.stim(stim, params, 5, ctl(2)); + let stim = drive_map.5.3.stim(stim, params, 5, ctl(3)); + let stim = drive_map.5.4.stim(stim, params, 5, ctl(4)); + + let stim = drive_map.6.0.stim(stim, params, 6, ctl(0)); + let stim = drive_map.6.1.stim(stim, params, 6, ctl(1)); + let stim = drive_map.6.2.stim(stim, params, 6, ctl(2)); + let stim = drive_map.6.3.stim(stim, params, 6, ctl(3)); + let stim = drive_map.6.4.stim(stim, params, 6, ctl(4)); + + let stim = drive_map.7.0.stim(stim, params, 7, ctl(0)); + let stim = drive_map.7.1.stim(stim, params, 7, ctl(1)); + let stim = drive_map.7.2.stim(stim, params, 7, ctl(2)); + let stim = drive_map.7.3.stim(stim, params, 7, ctl(3)); + let stim = drive_map.7.4.stim(stim, params, 7, ctl(4)); + + let stim = drive_map.8.0.stim(stim, params, 8, ctl(0)); + let stim = drive_map.8.1.stim(stim, params, 8, ctl(1)); + let stim = drive_map.8.2.stim(stim, params, 8, ctl(2)); + let stim = drive_map.8.3.stim(stim, params, 8, ctl(3)); + let stim = drive_map.8.4.stim(stim, params, 8, ctl(4)); + + let stim = drive_map.9.0.stim(stim, params, 9, ctl(0)); + let stim = drive_map.9.1.stim(stim, params, 9, ctl(1)); + let stim = drive_map.9.2.stim(stim, params, 9, ctl(2)); + let stim = drive_map.9.3.stim(stim, params, 9, ctl(3)); + let stim = drive_map.9.4.stim(stim, params, 9, ctl(4)); + + let stim = drive_map.10.0.stim(stim, params, 10, ctl(0)); + let stim = drive_map.10.1.stim(stim, params, 10, ctl(1)); + let stim = drive_map.10.2.stim(stim, params, 10, ctl(2)); + let stim = drive_map.10.3.stim(stim, params, 10, ctl(3)); + let stim = drive_map.10.4.stim(stim, params, 10, ctl(4)); + + let stim = drive_map.11.0.stim(stim, params, 11, ctl(0)); + let stim = drive_map.11.1.stim(stim, params, 11, ctl(1)); + let stim = drive_map.11.2.stim(stim, params, 11, ctl(2)); + let stim = drive_map.11.3.stim(stim, params, 11, ctl(3)); + let stim = drive_map.11.4.stim(stim, params, 11, ctl(4)); + + let stim = drive_map.12.0.stim(stim, params, 12, ctl(0)); + let stim = drive_map.12.1.stim(stim, params, 12, ctl(1)); + let stim = drive_map.12.2.stim(stim, params, 12, ctl(2)); + let stim = drive_map.12.3.stim(stim, params, 12, ctl(3)); + let stim = drive_map.12.4.stim(stim, params, 12, ctl(4)); + + let stim = drive_map.13.0.stim(stim, params, 13, ctl(0)); + let stim = drive_map.13.1.stim(stim, params, 13, ctl(1)); + let stim = drive_map.13.2.stim(stim, params, 13, ctl(2)); + let stim = drive_map.13.3.stim(stim, params, 13, ctl(3)); + let stim = drive_map.13.4.stim(stim, params, 13, ctl(4)); + assert_eq!(num_cycles, 14); + assert_eq!(num_cores, 5); + let mut driver = driver.with_stimulus(stim); let prefix = "out/applications/multi_core_inverter/13/"; let _ = std::fs::create_dir_all(&prefix);