Xmod Co-simulation ((free)) Direct

def run_with_iteration(self, t_start: float, t_end: float, max_iter: int = 10): """Jacobi-style fixed-point iteration at each time step.""" t = t_start outputs = {name: {} for name in self.models} while t < t_end - 1e-12: converged = False for _iter in range(max_iter): inputs_for = {name: {} for name in self.models} for fm, fp, tm, tp in self.connections: if fm in outputs and fp in outputs[fm]: inputs_for[tm][tp] = outputs[fm][fp] new_outputs = {} for name, model in self.models.items(): step_result = model.step(t, self.dt, inputs_for[name]) new_outputs[name] = step_result.outputs # Check convergence (norm of output change) diff = 0.0 for name in self.models: for port in new_outputs[name]: old_val = outputs[name].get(port, 0) diff += np.linalg.norm(new_outputs[name][port] - old_val) outputs = new_outputs if diff < 1e-8: converged = True break print(f"t={t:.3f}, iter={_iter+1}, converged={converged}") t += self.dt Demo ---------------------------------------------------------------------- if name == " main ": # Build system: controller -> spring-mass-damper plant = SpringMassDamper("mass_spring", m=1.0, k=10.0, c=0.5) ctrl = PController("controller", Kp=20.0, x_ref=1.0)

def run(self, t_start: float, t_end: float, log_callback: Callable = None): t = t_start outputs = {name: {} for name in self.models} while t < t_end - 1e-12: # Gather all inputs for each model from previous outputs inputs_for = {name: {} for name in self.models} for fm, fp, tm, tp in self.connections: if fm in outputs and fp in outputs[fm]: inputs_for[tm][tp] = outputs[fm][fp] # Step each model new_outputs = {} for name, model in self.models.items(): step_result = model.step(t, self.dt, inputs_for[name]) new_outputs[name] = step_result.outputs outputs = new_outputs t += self.dt if log_callback: log_callback(t, outputs) xmod co-simulation

def get_state(self): return {"x": self.x, "v": self.v} model in self.models.items(): step_result = model.step(t