/// <summary> /// Destroys the simulation. /// </summary> protected override void Unsetup() { // Remove references for (var i = 0; i < _transientBehaviors.Count; i++) { _transientBehaviors[i].Unsetup(this); } _transientBehaviors = null; for (var i = 0; i < _acceptBehaviors.Count; i++) { _acceptBehaviors[i].Unsetup(this); } _acceptBehaviors = null; // Destroy the integration method Method.Unsetup(this); Method = null; // Destroy the initial conditions AfterLoad -= LoadInitialConditions; foreach (var ic in _initialConditions) { ic.Unsetup(); } _initialConditions.Clear(); base.Unsetup(); }
/// <summary> /// Compute expressions for y[t + h] in terms of y[t], the resulting expressions will be implicit for implicit methods. /// </summary> /// <param name="dy_dt">Equations to solve.</param> /// <param name="y">Functions to solve for.</param> /// <param name="t">Independent variable.</param> /// <param name="h">Step size.</param> /// <param name="method">Integration method to use for differential equations.</param> /// <returns>Expressions for y[t + h].</returns> public static IEnumerable<Arrow> NDIntegrate(this IEnumerable<Arrow> dy_dt, Expression t, Expression h, IntegrationMethod method) { switch (method) { // y[t + h] = y[t] + h*f[t, y[t]] case IntegrationMethod.Euler: return dy_dt.Select(i => Arrow.New( DOf(i.Left).Evaluate(t, t + h), DOf(i.Left) + h * i.Right)); // y[t + h] = y[t] + h*f[t + h, y[t + h]] case IntegrationMethod.BackwardEuler: return dy_dt.Select(i => Arrow.New( DOf(i.Left).Evaluate(t, t + h), DOf(i.Left) + h * i.Right.Evaluate(t, t + h))); // y[t + h] = y[t] + (h/2)*(f[t, y[t]] + f[t + h, y[t + h]]) case IntegrationMethod.Trapezoid: return dy_dt.Select(i => Arrow.New( DOf(i.Left).Evaluate(t, t + h), DOf(i.Left) + (h / 2) * (i.Right + i.Right.Evaluate(t, t + h)))); default: throw new NotImplementedException(method.ToString()); } }
/// <summary> /// Applies device impact on the circuit equation system. If behavior of the device is nonlinear, this method is /// called once every Newton-Raphson iteration. /// </summary> /// <param name="context">Context of current simulation.</param> public override void ApplyModelValues(ISimulationContext context) { vt = Parameters.EmissionCoefficient * PhysicalConstants.Boltzmann * PhysicalConstants.CelsiusToKelvin(Parameters.NominalTemperature) / PhysicalConstants.DevicearyCharge; gmin = Parameters.MinimalResistance ?? context.SimulationParameters.MinimalResistance; smallBiasTreshold = -5 * vt; capacitanceTreshold = Parameters.ForwardBiasDepletionCapacitanceCoefficient * Parameters.JunctionPotential; var vd = Voltage - Parameters.SeriesResistance * Current; var(id, geq, cd) = GetModelValues(vd); var ieq = id - geq * vd; // Diode stamper.Stamp(geq, -ieq); // Capacitance var(cieq, cgeq) = IntegrationMethod.GetEquivalents(cd / context.TimeStep); if (initialConditionCapacitor) // initial condition { capacitorStamper.Stamp(0, 0); } else { capacitorStamper.Stamp(cieq, cgeq); } Current = id + ic; Conductance = geq; }
/// <summary> /// Create states /// </summary> /// <param name="method"></param> public void CreateStates(IntegrationMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } QCap = method.CreateDerivative(); }
/// <summary> /// Create states /// </summary> /// <param name="method"></param> public override void CreateStates(IntegrationMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } CapCharge = method.CreateDerivative(); }
/// <summary> /// Bind the behavior. /// </summary> /// <param name="simulation">The simulation.</param> /// <param name="context">The data provider.</param> public override void Bind(Simulation simulation, BindingContext context) { base.Bind(simulation, context); // Get parameters _bp = context.GetParameterSet <BaseParameters>(); // Get behaviors _tran = context.GetBehavior <TransientBehavior>(); _method = ((TimeSimulation)simulation).Method; }
/// <summary> /// Notifies model class that DC bias for given timepoint is established (i.e after Newton-Raphson iterations /// converged). /// </summary> /// <param name="context">Context of current simulation.</param> public override void OnDcBiasEstablished(ISimulationContext context) { base.OnDcBiasEstablished(context); ic = capacitorStamper.GetCurrent(); if (Math.Abs(context.TimeStep) < double.Epsilon) // set initial condition for the capacitor { ic = Current; } vc = Voltage; IntegrationMethod.SetState(ic, vc); initialConditionCapacitor = false; // capacitor no longer needs initial condition }
/// <summary> /// Create states /// </summary> /// <param name="method"></param> public override void CreateStates(IntegrationMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } // We just need a history without integration here StateChargeBe = method.CreateDerivative(); StateChargeBc = method.CreateDerivative(); StateChargeCs = method.CreateDerivative(); // Spice 3f5 does not include this state for LTE calculations StateChargeBx = method.CreateDerivative(false); StateExcessPhaseCurrentBc = method.CreateHistory(); }
/// <summary> /// Create states /// </summary> /// <param name="method"></param> public override void CreateStates(IntegrationMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } VoltageBs = method.CreateHistory(); VoltageGs = method.CreateHistory(); VoltageDs = method.CreateHistory(); CapGs = method.CreateHistory(); CapGd = method.CreateHistory(); CapGb = method.CreateHistory(); ChargeGs = method.CreateDerivative(); ChargeGd = method.CreateDerivative(); ChargeGb = method.CreateDerivative(); ChargeBd = method.CreateDerivative(); ChargeBs = method.CreateDerivative(); }
/// <summary> /// Create states /// </summary> /// <param name="method"></param> public override void CreateStates(IntegrationMethod method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } _vgs = method.CreateHistory(); _vds = method.CreateHistory(); _vbs = method.CreateHistory(); _capgs = method.CreateHistory(); _capgd = method.CreateHistory(); _capgb = method.CreateHistory(); _qgs = method.CreateDerivative(); _qgd = method.CreateDerivative(); _qgb = method.CreateDerivative(); _qbd = method.CreateDerivative(); _qbs = method.CreateDerivative(); }
/// <summary> /// Accept the current time point /// </summary> /// <param name="ckt"></param> public override void Accept(Circuit ckt) { // Should not be here if (ckt.Method == null) { return; } IntegrationMethod method = ckt.Method; var breaks = method.Breaks; // Find the time relative to the first period double time = method.Time - td; double basetime = 0.0; if (time >= per) { basetime = per * Math.Floor(time / per); time -= basetime; } if (basetime == lastbasetime) { return; } lastbasetime = basetime; // Add all breakpoints for this period breaks.SetBreakpoint(basetime + td); breaks.SetBreakpoint(basetime + td + tr); breaks.SetBreakpoint(basetime + td + tr + pw); breaks.SetBreakpoint(basetime + td + tr + pw + tf); breaks.SetBreakpoint(basetime + td + per); // Start of the next period /* * NOTE: * Originally Spice only adds a breakpoint when the previous one has been reached. * The problem is that if the next breakpoint is too close (< MinBreak), it will * not be added which means that any subsequent breakpoints will be lost too. * * The same problem here will only occur if a whole period is < MinBreak. */ }
public PhysicsEngine(Game1 g, IntegrationMethod integrationMethod) : base(g) { game = g; physicsObjects = new List<IPhysicsObject>(); t = 0.0f; switch (integrationMethod) { case IntegrationMethod.Euler: this.integrator = new EulerIntegrator(); break; case IntegrationMethod.RungeKutta4: this.integrator = new RK4Integrator(); break; default: this.integrator = new EulerIntegrator(); break; } }
/// <summary> /// Setup behavior /// </summary> /// <param name="simulation">Simulation</param> /// <param name="provider">Data provider</param> public override void Setup(Simulation simulation, SetupDataProvider provider) { if (provider == null) { throw new ArgumentNullException(nameof(provider)); } // Get parameters _bp = provider.GetParameterSet <BaseParameters>(); _mbp = provider.GetParameterSet <ModelBaseParameters>("model"); // Get behaviors _temp = provider.GetBehavior <TemperatureBehavior>(); _load = provider.GetBehavior <LoadBehavior>(); _modeltemp = provider.GetBehavior <ModelTemperatureBehavior>("model"); if (simulation is TimeSimulation ts) { _method = ts.Method; } }
/// <summary> /// Set up the simulation. /// </summary> /// <param name="circuit">The circuit that will be used.</param> /// <exception cref="ArgumentNullException">circuit</exception> /// <exception cref="SpiceSharp.CircuitException"> /// {0}: No time configuration".FormatString(Name) /// or /// {0}: No integration method specified".FormatString(Name) /// </exception> protected override void Setup(Circuit circuit) { if (circuit == null) { throw new ArgumentNullException(nameof(circuit)); } // Get base behaviors base.Setup(circuit); // Get behaviors and configurations var config = Configurations.Get <TimeConfiguration>() ?? throw new CircuitException("{0}: No time configuration".FormatString(Name)); _useIc = config.UseIc; Method = config.Method ?? throw new CircuitException("{0}: No integration method specified".FormatString(Name)); _transientBehaviors = SetupBehaviors <BaseTransientBehavior>(circuit.Entities); // Allow all transient behaviors to allocate equation elements and create states for (var i = 0; i < _transientBehaviors.Count; i++) { _transientBehaviors[i].GetEquationPointers(RealState.Solver); _transientBehaviors[i].CreateStates(Method); } Method.Setup(this); // TODO: Compatibility - initial conditions from nodes instead of configuration should be removed eventually if (config.InitialConditions.Count == 0) { foreach (var ns in Variables.InitialConditions) { _initialConditions.Add(new ConvergenceAid(ns.Key, ns.Value)); } } // Set up initial conditions foreach (var ic in config.InitialConditions) { _initialConditions.Add(new ConvergenceAid(ic.Key, ic.Value)); } }
/// <summary> /// Численное итегрирование. /// </summary> /// <param name="func">Функция, для которой нужно вычислить интеграл.</param> /// <param name="boundaries">Отрезок, на котором выполняется интегрирование.</param> /// <param name="n">Количество разбиений отрезка.</param> /// <param name="integrationMethod">Метод интегрирования.</param> /// <returns>Результат интегрирования.</returns> public static double Integrate(Func <double, object[], double> func, object[] args, Boundaries boundaries, IntegrationMethod integrationMethod) { double result; switch (integrationMethod) { case IntegrationMethod.Rectangles: result = RectangleIntegration(func, args, boundaries); break; case IntegrationMethod.Trapezium: result = TrapeziumIntegration(func, args, boundaries); break; default: result = double.MinValue; break; } return(result); }
/// <summary> /// Creates all necessary states for the transient behavior. /// </summary> /// <param name="method">The integration method.</param> public void CreateStates(IntegrationMethod method) { }
/// <summary> /// Creates all necessary states for the transient behavior. /// </summary> /// <param name="method">The integration method.</param> /// <exception cref="ArgumentNullException">method</exception> public virtual void CreateStates(IntegrationMethod method) { // Do nothing (for now) }
/// <summary> /// Creates all necessary states for the transient behavior. /// </summary> /// <param name="method">The integration method.</param> public void CreateStates(IntegrationMethod method) { Signal = new DelayedSignal(1, BaseParameters.Delay); }
/// <summary> /// Create states /// </summary> /// <param name="method"></param> public void CreateStates(IntegrationMethod method) { method.ThrowIfNull(nameof(method)); QCap = method.CreateDerivative(); }
/// <summary> /// Compute expressions for y[t] in terms of y[t - h], the resulting expressions will be implicit for implicit methods. /// </summary> /// <param name="dy_dt">Equations to solve.</param> /// <param name="y">Functions to solve for.</param> /// <param name="t">Independent variable.</param> /// <param name="h">Step size.</param> /// <param name="method">Integration method to use for differential equations.</param> /// <returns>Expressions for y[t].</returns> public static IEnumerable <Arrow> NDIntegrate(this IEnumerable <Arrow> dy_dt, Expression t, Expression h, IntegrationMethod method) { switch (method) { // y[t] = y[t - h] + h*f[t - h, y[t - h]] case IntegrationMethod.Euler: return(dy_dt.Select(i => Arrow.New( DOf(i.Left), DOf(i.Left).Substitute(t, t - h) + h * i.Right.Substitute(t, t - h)))); // y[t] = y[t - h] + h*f[t, y[t]] case IntegrationMethod.BackwardEuler: return(dy_dt.Select(i => Arrow.New( DOf(i.Left), DOf(i.Left).Substitute(t, t - h) + h * i.Right))); // y[t] = y[t - h] + (h/2)*(f[t - h, y[t - h]] + f[t, y[t]]) case IntegrationMethod.Trapezoid: return(dy_dt.Select(i => Arrow.New( DOf(i.Left), DOf(i.Left).Substitute(t, t - h) + (h / 2) * (i.Right.Substitute(t, t - h) + i.Right)))); // y[t] = (4/3)*y[t - h] - (1/3)y[t - 2h] + (2h/3)*f[t, y[t]] case IntegrationMethod.BackwardDifferenceFormula2: return(dy_dt.Select(i => Arrow.New( DOf(i.Left), 4 * DOf(i.Left).Substitute(t, t - h) / 3 - DOf(i.Left).Substitute(t, t - 2 * h) / 3 + 2 * h * i.Right / 3))); // y[t] = (2/11)*y[t - 3h] - (9/11)*y[t - 2h] + (18/11)*y[t - h] + (6h/11)*f[t, y[t]] case IntegrationMethod.BackwardDifferenceFormula3: return(dy_dt.Select(i => Arrow.New( DOf(i.Left), 2 * DOf(i.Left).Substitute(t, t - 3 * h) / 11 - 9 * DOf(i.Left).Substitute(t, t - 2 * h) / 11 + 18 * DOf(i.Left).Substitute(t, t - h) / 11 + 6 * h * i.Right / 11))); default: throw new NotImplementedException(method.ToString()); } }
/// <summary> /// Partially solve a linear system of differential equations for y[t] in terms of y[t - h]. See SolveExtensions.PartialSolve for more information. /// </summary> /// <param name="f">Equations to solve.</param> /// <param name="y">Functions to solve for.</param> /// <param name="t">Independent variable.</param> /// <param name="h">Step size.</param> /// <param name="method">Integration method to use for differential equations.</param> /// <returns>Expressions for y[t].</returns> public static List <Arrow> NDPartialSolve(this IEnumerable <Equal> f, IEnumerable <Expression> y, Expression t, Expression h, IntegrationMethod method) { // Find y' in terms of y. List <Arrow> dy_dt = f.Solve(y.Select(i => D(i, t))); // If dy/dt appears on the right side of the system, the differential equation is not linear. Can't handle these. if (dy_dt.Any(i => i.Right.DependsOn(dy_dt.Select(j => j.Left)))) { throw new ArgumentException("Differential equation is singular or not linear."); } return(NDIntegrate(dy_dt, t, h, method) .Select(i => Equal.New(i.Left, i.Right)) .PartialSolve(y)); }
/// <summary> /// Accept the current time point /// </summary> /// <param name="ckt"></param> public override void Accept(Circuit ckt) { // Should not be here if (ckt.Method == null) { return; } // Are we at a breakpoint? IntegrationMethod method = ckt.Method; var breaks = method.Breaks; if (!method.Break) { return; } // Find the time relative to the first period double time = method.Time - td; double basetime = 0.0; if (time >= per) { basetime = per * Math.Floor(time / per); time -= basetime; } double tol = 1e-7 * pw; // Are we at the start of a breakpoint? if (time <= 0 || time >= tr + pw + tf) { if (Math.Abs(time - 0) <= tol) { breaks.SetBreakpoint(basetime + tr + td); } else if (Math.Abs(tr + pw + tf - time) <= tol) { breaks.SetBreakpoint(basetime + per + td); } else if ((time == -td)) { breaks.SetBreakpoint(basetime + td); } else if (Math.Abs(per - time) <= tol) { breaks.SetBreakpoint(basetime + td + tr + per); } } else if (time >= tr && time <= tr + pw) { if (Math.Abs(time - tr) <= tol) { breaks.SetBreakpoint(basetime + td + tr + pw); } else if (Math.Abs(tr + pw - time) <= tol) { breaks.SetBreakpoint(basetime + td + tr + pw + tf); } } else if (time > 0 && time < tr) { if (Math.Abs(time - 0) <= tol) { breaks.SetBreakpoint(basetime + td + tr); } else if (Math.Abs(time - tr) <= tol) { breaks.SetBreakpoint(basetime + td + tr + pw); } } else { if (Math.Abs(tr + pw - time) <= tol) { breaks.SetBreakpoint(basetime + td + tr + pw + tf); } else if (Math.Abs(tr + pw + tf - time) <= tol) { breaks.SetBreakpoint(basetime + td + per); } } }
/// <summary> /// Compute expressions for y[t + h] in terms of y[t], the resulting expressions will be implicit for implicit methods. /// </summary> /// <param name="dy_dt">Equations to solve.</param> /// <param name="y">Functions to solve for.</param> /// <param name="t">Independent variable.</param> /// <param name="h">Step size.</param> /// <param name="method">Integration method to use for differential equations.</param> /// <returns>Expressions for y[t + h].</returns> public static IEnumerable <Arrow> NDIntegrate(this IEnumerable <Arrow> dy_dt, Expression t, Expression h, IntegrationMethod method) { switch (method) { // y[t + h] = y[t] + h*f[t, y[t]] case IntegrationMethod.Euler: return(dy_dt.Select(i => Arrow.New( DOf(i.Left).Evaluate(t, t + h), DOf(i.Left) + h * i.Right))); // y[t + h] = y[t] + h*f[t + h, y[t + h]] case IntegrationMethod.BackwardEuler: return(dy_dt.Select(i => Arrow.New( DOf(i.Left).Evaluate(t, t + h), DOf(i.Left) + h * i.Right.Evaluate(t, t + h)))); // y[t + h] = y[t] + (h/2)*(f[t, y[t]] + f[t + h, y[t + h]]) case IntegrationMethod.Trapezoid: return(dy_dt.Select(i => Arrow.New( DOf(i.Left).Evaluate(t, t + h), DOf(i.Left) + (h / 2) * (i.Right + i.Right.Evaluate(t, t + h))))); default: throw new NotImplementedException(method.ToString()); } }
/// <summary> /// Creates all necessary states for the transient behavior. /// </summary> /// <param name="method">The integration method.</param> public void CreateStates(IntegrationMethod method) { Qgs = method.CreateDerivative(); Qgd = method.CreateDerivative(); }
/// <summary> /// Accept the current time point /// </summary> /// <param name="simulation">Time-based simulation</param> public override void Accept(TimeSimulation simulation) { if (simulation == null) { throw new ArgumentNullException(nameof(simulation)); } // Should not be here if (simulation.Method == null) { return; } // Are we at a breakpoint? IntegrationMethod method = simulation.Method; var breaks = method.Breaks; if (!method.Break) { return; } // Find the time relative to the first period double time = method.Time - _td; double basetime = 0.0; if (time >= _per) { basetime = _per * Math.Floor(time / _per); time -= basetime; } double tol = 1e-7 * _pw; // Are we at the start of a breakpoint? if (time <= 0 || time >= _tr + _pw + _tf) { if (Math.Abs(time - 0) <= tol) { breaks.SetBreakpoint(basetime + _tr + _td); } else if (Math.Abs(_tr + _pw + _tf - time) <= tol) { breaks.SetBreakpoint(basetime + _per + _td); } else if (time <= -_td) { breaks.SetBreakpoint(basetime + _td); } else if (Math.Abs(_per - time) <= tol) { breaks.SetBreakpoint(basetime + _td + _tr + _per); } } else if (time >= _tr && time <= _tr + _pw) { if (Math.Abs(time - _tr) <= tol) { breaks.SetBreakpoint(basetime + _td + _tr + _pw); } else if (Math.Abs(_tr + _pw - time) <= tol) { breaks.SetBreakpoint(basetime + _td + _tr + _pw + _tf); } } else if (time > 0 && time < _tr) { if (Math.Abs(time - 0) <= tol) { breaks.SetBreakpoint(basetime + _td + _tr); } else if (Math.Abs(time - _tr) <= tol) { breaks.SetBreakpoint(basetime + _td + _tr + _pw); } } else { if (Math.Abs(_tr + _pw - time) <= tol) { breaks.SetBreakpoint(basetime + _td + _tr + _pw + _tf); } else if (Math.Abs(_tr + _pw + _tf - time) <= tol) { breaks.SetBreakpoint(basetime + _td + _per); } } }
/// <summary> /// Solve a linear system of differential equations for y[t + h] in terms of y[t]. /// </summary> /// <param name="f">Equations to solve.</param> /// <param name="y">Functions to solve for.</param> /// <param name="t">Independent variable.</param> /// <param name="h">Step size.</param> /// <param name="method">Integration method to use for differential equations.</param> /// <returns>Expressions for y[t + h].</returns> public static List<Arrow> NDSolve(this IEnumerable<Equal> f, IEnumerable<Expression> y, Expression t, Expression h, IntegrationMethod method) { // Find y' in terms of y. List<Arrow> dy_dt = f.Solve(y.Select(i => D(i, t))); // If dy/dt appears on the right side of the system, the differential equation is not linear. Can't handle these. if (dy_dt.Any(i => i.Right.DependsOn(dy_dt.Select(j => j.Left)))) throw new ArgumentException("Differential equation is singular or not linear."); return NDIntegrate(dy_dt, t, h, method) .Select(i => Equal.New(i.Left, i.Right)) .Solve(y.Evaluate(t, t + h)); }