diff --git a/crates/applications/stacked_cores/scripts/inverter_characteristics.py b/crates/applications/stacked_cores/scripts/inverter_characteristics.py index 7c643a9..790b4ec 100644 --- a/crates/applications/stacked_cores/scripts/inverter_characteristics.py +++ b/crates/applications/stacked_cores/scripts/inverter_characteristics.py @@ -125,6 +125,13 @@ class Piecewise: def slope_df(self, from_: float = 0.0, to: float = 1.0, points: int = 101) -> DataFrame: return self.df_for(from_, to, points, self.get_slope) + def min_max_slope(self): + slope = [self.get_slope(0.01*x) for x in range(101)] + return min(slope), max(slope) + + def max_abs_slope(self) -> float: + return max(abs(s) for s in self.min_max_slope()) + def plot_for(self, from_: float, to: float, title: str, f): df = self.df_for(from_, to, points=101, f=f) fig = px.line(df, x="x", y="y", title=title) diff --git a/crates/applications/stacked_cores/scripts/plot_inverters.py b/crates/applications/stacked_cores/scripts/plot_inverters.py index 5982500..3f62b29 100755 --- a/crates/applications/stacked_cores/scripts/plot_inverters.py +++ b/crates/applications/stacked_cores/scripts/plot_inverters.py @@ -118,12 +118,14 @@ of_interest += [(p, get_meas(p)) for p in # plot all viable inverters -# of_interest += filter_meas(run="41", rad_um=400, viable_inverter=True) +of_interest += filter_meas(run="41", viable_inverter=True) # of_interest += filter_meas(run="42", rad_um=400, couplings=4) # of_interest += filter_meas(run="42", rad_um=400, couplings=9) # of_interest += filter_meas(run="42", rad_um=400, couplings=2) # of_interest += filter_meas(run="42", rad_um=400, couplings=6) -of_interest += filter_meas(run="43") +# of_interest += filter_meas(run="43") + +of_interest.sort(key=lambda i: -i[1].max_abs_slope()) for (params, curve) in of_interest: if not params.is_inverter: diff --git a/crates/applications/stacked_cores/scripts/stacked_cores_40xx_db.py b/crates/applications/stacked_cores/scripts/stacked_cores_40xx_db.py index e283efb..b71b406 100755 --- a/crates/applications/stacked_cores/scripts/stacked_cores_40xx_db.py +++ b/crates/applications/stacked_cores/scripts/stacked_cores_40xx_db.py @@ -72,6 +72,11 @@ class SimParams: ) return self.tuple == match_tuple + def ensure_inverter(self, curve): + if not self.is_inverter: + return curve.logically_inverted() + return curve + class SimParams40(SimParams): @property def run(self) -> str: @@ -260,7 +265,7 @@ def filter_meas(run: str = None, rad_um: int = None, drive: float = None, coupli if p.matches(run, rad_um, drive, couplings, wrappings) \ and get_meas(p) \ and get_meas(p).num_pieces > 0 \ - and matches(get_meas(p).logically_inverted().is_viable_inverter(), viable_inverter) + and matches(p.ensure_inverter(get_meas(p)).is_viable_inverter(), viable_inverter) ], key = lambda v: v[0].tuple ) diff --git a/crates/applications/stacked_cores/src/main.rs b/crates/applications/stacked_cores/src/main.rs index cb27218..d5ad6d5 100644 --- a/crates/applications/stacked_cores/src/main.rs +++ b/crates/applications/stacked_cores/src/main.rs @@ -1240,6 +1240,28 @@ fn asymmetric_inverter_name(p: &Params, sim_id: &str, windings: u32, init_flt: f format!("{sim_id}-{s_major}rad-{coupling_loops}coupling-{windings}_1_winding-{input_leading}e{input_exp}-drive-{init_level}") } + +fn asymmetric_inverter_name_v2(p: &Params, sim_id: &str, ctl_loops: u32, coupling_loops: u32, windings: u32, init_flt: f32) -> String { + let init_int = (init_flt.abs() * 100.0 + 0.5) as u32; + let init_level = if init_flt > 0.0 { + format!("p{init_int:03}") + } else if init_flt < 0.0 { + format!("n{init_int:03}") + } else { + "000".to_owned() + }; + + let s_major = p.s_major; + + let mut input_leading = p.input_magnitude as u64; + let mut input_exp = 0; + while input_leading != 0 && input_leading % 10 == 0 { + input_leading /= 10; + input_exp += 1; + } + format!("{sim_id}-{s_major}rad-{ctl_loops}ctl-{coupling_loops}coupling-{windings}_1_winding-{input_leading}e{input_exp}-drive-{init_level}") +} + /// couple `sender` to the `sender+1` core by using `loops` loops, including a crossover so that /// when the sender goes high -> low, the receiver *also* goes high -> low ("inverting"). /// `loops` must be >= 1. @@ -4637,7 +4659,7 @@ fn main() { } } } - if true { + if false { let p44xx = params_v2 .with_clock_phase_duration(ps(1000)) .with_clock_decay(ps(50)) @@ -4698,6 +4720,95 @@ fn main() { } } } + + if true { + let p45xx = params_v2 + .with_clock_phase_duration(ps(1000)) + .with_clock_decay(ps(50)) + .with_ctl_conductivity(5e2) + .with_coupling_conductivity(5e3) + ; + for init_set in [ + &[ + // establish the domain/range + 1.00, + ][..], + &[ + -1.00, + ][..], + &[ + 0.00, + 0.20, + -0.20, + 0.10, + -0.10, + 0.35, + -0.35, + ][..], + ] { + for (staggered, ctl_loops, coupling_loops, s0_loops, s_major, cur_flt) in [ + (true, 2, 5, 1, um(400), 5e10), // verified geom. M0: 16800, M1 -> 950 + (true, 3, 5, 1, um(400), 33e9), // M0: 16800, M1 -> 410 + (true, 1, 5, 1, um(400), 1e11), // M0: 16500, M1 -> 1970 + (true, 4, 5, 1, um(400), 25e9), // M0: 16800, M1 -> 310 + (true, 5, 5, 1, um(400), 2e10), // M0: 16800, M1 -> 640 + + (false, 2, 5, 1, um(400), 5e10), // verified geom. M0: 16800, M1 -> 775 + (false, 3, 5, 1, um(400), 33e9), // M0: 16800, M1 -> 605 + (false, 1, 5, 1, um(400), 1e11), // M0: 16800, M1 -> 1300 + (false, 4, 5, 1, um(400), 25e9), + (false, 5, 5, 1, um(400), 2e10), + // (5, 1, um(400), 3e9), + // (5, 1, um(400), 5e9), + // (5, 1, um(400), 8e9), + // (5, 1, um(400), 1e10), + // (5, 1, um(400), 4e10), + // (5, 1, um(400), 2e9), + ] { + for &init_flt in init_set { + let slots_per_asym = 2*s0_loops; + // coupling loops (M0 -> M1) + (M1 -> M2) + control slots + assert!(ctl_loops <= coupling_loops); // else change this `+ 1` + let slots_per_cycle = 2 * slots_per_asym + 1; + let net_slots = coupling_loops * slots_per_cycle; + let mut params = p45xx + .with_s_major(s_major) + .with_input_magnitude(cur_flt); + for i in 0..ctl_loops { + // TODO: re-introduce current measurement for control loops? + let i = i * coupling_loops / ctl_loops; // distribute evenly + let (stagger1, stagger2) = if staggered { + (coupling_loops / ctl_loops / 2, coupling_loops / ctl_loops) + } else { + (0, 0) + }; + params = params + .with_coupling(0, 0, i*slots_per_cycle, net_slots, CouplingMethod::Control) + .with_coupling(1, 1, (i + stagger1)*slots_per_cycle, net_slots, CouplingMethod::Control) + .with_coupling(2, 2, (i + stagger2)*slots_per_cycle, net_slots, CouplingMethod::Control) + ; + } + for i in 0..coupling_loops { + let cycle_off = i*slots_per_cycle; + params = couple_asymmetric_inverter(¶ms, 0 /* sender core */, s0_loops, cycle_off + 1 /* slot offset */, net_slots); + params = couple_asymmetric_inverter(¶ms, 1 /* sender core */, s0_loops, cycle_off + 1 + slots_per_asym /* slot offset */, net_slots); + } + + let base = if staggered { + "45-staggered1" + } else { + "45" + }; + let name = asymmetric_inverter_name_v2(¶ms, base, ctl_loops, coupling_loops, 2*s0_loops + 1, init_flt); + run_sim( + &name, + drive_map_3stack_with_init_43(init_flt), + params, + ); + } + } + } + } }