Exemple #1
0
        /// <summary>
        /// Calculate a new step
        /// The result is stored in Delta
        /// Note: This method does not advance time!
        /// </summary>
        /// <param name="simulation">Time-based simulation</param>
        /// <returns>True if the timestep isn't cut</returns>
        public bool LteControl(TimeSimulation simulation)
        {
            // Invoke truncation event
            TruncationEventArgs args = new TruncationEventArgs(simulation, Delta);

            Truncate?.Invoke(this, args);
            double newdelta = args.Delta;

            if (newdelta > 0.9 * Delta)
            {
                if (Order == 1)
                {
                    Order = 2;

                    // Invoke truncation event
                    args = new TruncationEventArgs(simulation, Delta);
                    Truncate?.Invoke(this, args);
                    newdelta = args.Delta;

                    if (newdelta <= 1.05 * Delta)
                    {
                        Order = 1;
                    }
                }
                Delta = newdelta;
                return(true);
            }

            // Truncation too strict, we'll have to recalculate the timepoint
            Rollback();
            Delta = newdelta;
            return(false);
        }
Exemple #2
0
        /// <summary>
        /// Do truncation for all devices
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="args">Arguments</param>
        /// <returns></returns>
        protected void TruncateDevices(object sender, TruncationEventArgs args)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            double timetmp = double.PositiveInfinity;

            for (int i = 0; i < _transientBehaviors.Count; i++)
            {
                timetmp = Math.Min(timetmp, _transientBehaviors[i].Truncate());
            }
            args.Delta = timetmp;
        }
Exemple #3
0
 /// <summary>
 /// Do truncation for all nodes
 /// </summary>
 /// <param name="sender">Sender</param>
 /// <param name="args">Arguments</param>
 /// <returns></returns>
 protected abstract void TruncateNodes(object sender, TruncationEventArgs args);
Exemple #4
0
        /// <summary>
        /// Truncate the timestep
        /// Uses the Local Truncation Error (LTE) to calculate an approximate timestep.
        /// The method is slightly different from the original Spice 3f5 version.
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="args">Arguments</param>
        /// <returns></returns>
        protected override void TruncateNodes(object sender, TruncationEventArgs args)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            // Get the state
            var    simulation = args.Simulation;
            var    state = simulation.RealState;
            double tol, diff, tmp;
            double timetemp = Double.PositiveInfinity;
            var    nodes    = simulation.Nodes;
            int    index;

            // In my opinion, the original Spice method is kind of bugged and can be much better...
            switch (Order)
            {
            case 1:
                for (int i = 0; i < nodes.Count; i++)
                {
                    var node = nodes[i];
                    if (node.UnknownType != VariableType.Voltage)
                    {
                        continue;
                    }
                    index = node.Index;

                    // Milne's estimate for the second-order derivative using a Forward Euler predictor and Backward Euler corrector
                    diff = state.Solution[index] - Prediction[index];

                    // Avoid division by zero
                    if (!diff.Equals(0.0))
                    {
                        tol      = Math.Max(Math.Abs(state.Solution[index]), Math.Abs(Prediction[index])) * BaseParameters.LteRelativeTolerance + BaseParameters.LteAbsoluteTolerance;
                        tmp      = DeltaOld[0] * Math.Sqrt(Math.Abs(2.0 * BaseParameters.TruncationTolerance * tol / diff));
                        timetemp = Math.Min(timetemp, tmp);
                    }
                }
                break;

            case 2:
                for (int i = 0; i < nodes.Count; i++)
                {
                    var node = nodes[i];
                    if (node.UnknownType != VariableType.Voltage)
                    {
                        continue;
                    }
                    index = node.Index;

                    // Milne's estimate for the third-order derivative using an Adams-Bashforth predictor and Trapezoidal corrector
                    diff = state.Solution[index] - Prediction[index];
                    double deriv = DeltaOld[1] / DeltaOld[0];
                    deriv = diff * 4.0 / (1 + deriv * deriv);

                    // Avoid division by zero
                    if (!deriv.Equals(0.0))
                    {
                        tol      = Math.Max(Math.Abs(state.Solution[index]), Math.Abs(Prediction[index])) * BaseParameters.LteRelativeTolerance + BaseParameters.LteAbsoluteTolerance;
                        tmp      = DeltaOld[0] * Math.Pow(Math.Abs(12.0 * BaseParameters.TruncationTolerance * tol / deriv), 1.0 / 3.0);
                        timetemp = Math.Min(timetemp, tmp);
                    }
                }
                break;

            default:
                throw new CircuitException("Invalid order");
            }

            // Get the minimum timestep
            args.Delta = timetemp;
        }