/// <summary> /// Solve the circuit for transient simulation. /// </summary> /// <param name="Analysis">Analysis from the circuit to solve.</param> /// <param name="TimeStep">Discretization timestep.</param> /// <param name="Log">Where to send output.</param> /// <returns>TransientSolution describing the solution of the circuit.</returns> public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IEnumerable <Arrow> InitialConditions, ILog Log) { Expression h = TimeStep; Log.WriteLine(MessageType.Info, "Building solution for h={0}", TimeStep.ToString()); // Analyze the circuit to get the MNA system and unknowns. List <Equal> mna = Analysis.Equations.ToList(); List <Expression> y = Analysis.Unknowns.ToList(); LogExpressions(Log, MessageType.Verbose, "System of " + mna.Count + " equations and " + y.Count + " unknowns = {{ " + String.Join(", ", y) + " }}", mna); // Evaluate for simulation functions. // Define T = step size. Analysis.Add("T", h); // Define d[t] = delta function. Analysis.Add(ExprFunction.New("d", Call.If((0 <= t) & (t < h), 1, 0), t)); // Define u[t] = step function. Analysis.Add(ExprFunction.New("u", Call.If(t >= 0, 1, 0), t)); mna = mna.Resolve(Analysis).OfType <Equal>().ToList(); // Find out what variables have differential relationships. List <Expression> dy_dt = y.Where(i => mna.Any(j => j.DependsOn(D(i, t)))).Select(i => D(i, t)).ToList(); // Find steady state solution for initial conditions. List <Arrow> initial = InitialConditions.ToList(); Log.WriteLine(MessageType.Info, "Performing steady state analysis..."); SystemOfEquations dc = new SystemOfEquations(mna // Derivatives, t, and T are zero in the steady state. .Evaluate(dy_dt.Select(i => Arrow.New(i, 0)).Append(Arrow.New(t, 0), Arrow.New(T, 0))) // Use the initial conditions from analysis. .Evaluate(Analysis.InitialConditions) // Evaluate variables at t=0. .OfType <Equal>(), y.Select(j => j.Evaluate(t, 0))); // Solve partitions independently. foreach (SystemOfEquations i in dc.Partition()) { try { List <Arrow> part = i.Equations.Select(j => Equal.New(j, 0)).NSolve(i.Unknowns.Select(j => Arrow.New(j, 0))); initial.AddRange(part); LogExpressions(Log, MessageType.Verbose, "Initial conditions:", part); } catch (Exception) { Log.WriteLine(MessageType.Warning, "Failed to find partition initial conditions, simulation may be unstable."); } } // Transient analysis of the system. Log.WriteLine(MessageType.Info, "Performing transient analysis..."); SystemOfEquations system = new SystemOfEquations(mna, dy_dt.Concat(y)); // Solve the diff eq for dy/dt and integrate the results. system.RowReduce(dy_dt); system.BackSubstitute(dy_dt); IEnumerable <Equal> integrated = system.Solve(dy_dt) .NDIntegrate(t, h, IntegrationMethod.Trapezoid) // NDIntegrate finds y[t + h] in terms of y[t], we need y[t] in terms of y[t - h]. .Evaluate(t, t - h).Cast <Arrow>() .Select(i => Equal.New(i.Left, i.Right)).Buffer(); system.AddRange(integrated); LogExpressions(Log, MessageType.Verbose, "Integrated solutions:", integrated); LogExpressions(Log, MessageType.Verbose, "Discretized system:", system.Select(i => Equal.New(i, 0))); // Solving the system... List <SolutionSet> solutions = new List <SolutionSet>(); // Partition the system into independent systems of equations. foreach (SystemOfEquations F in system.Partition()) { // Find linear solutions for y. Linear systems should be completely solved here. F.RowReduce(); IEnumerable <Arrow> linear = F.Solve(); if (linear.Any()) { linear = Factor(linear); solutions.Add(new LinearSolutions(linear)); LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linear); } // If there are any variables left, there are some non-linear equations requiring numerical techniques to solve. if (F.Unknowns.Any()) { // The variables of this system are the newton iteration updates. List <Expression> dy = F.Unknowns.Select(i => NewtonIteration.Delta(i)).ToList(); // Compute JxF*dy + F(y0) == 0. SystemOfEquations nonlinear = new SystemOfEquations( F.Select(i => i.Gradient(F.Unknowns).Select(j => new KeyValuePair <Expression, Expression>(NewtonIteration.Delta(j.Key), j.Value)) .Append(new KeyValuePair <Expression, Expression>(1, i))), dy); // ly is the subset of y that can be found linearly. List <Expression> ly = dy.Where(j => !nonlinear.Any(i => i[j].DependsOn(NewtonIteration.DeltaOf(j)))).ToList(); // Find linear solutions for dy. nonlinear.RowReduce(ly); IEnumerable <Arrow> solved = nonlinear.Solve(ly); solved = Factor(solved); // Initial guess for y[t] = y[t - h]. IEnumerable <Arrow> guess = F.Unknowns.Select(i => Arrow.New(i, i.Evaluate(t, t - h))).ToList(); guess = Factor(guess); // Newton system equations. IEnumerable <LinearCombination> equations = nonlinear.Equations; equations = Factor(equations); solutions.Add(new NewtonIteration(solved, equations, nonlinear.Unknowns, guess)); LogExpressions(Log, MessageType.Verbose, String.Format("Non-linear Newton's method updates ({0}):", String.Join(", ", nonlinear.Unknowns)), equations.Select(i => Equal.New(i, 0))); LogExpressions(Log, MessageType.Verbose, "Linear Newton's method updates:", solved); } } Log.WriteLine(MessageType.Info, "System solved, {0} solution sets for {1} unknowns.", solutions.Count, solutions.Sum(i => i.Unknowns.Count())); return(new TransientSolution( h, solutions, initial)); }
/// <summary> /// Solve the circuit for transient simulation. /// </summary> /// <param name="Analysis">Analysis from the circuit to solve.</param> /// <param name="TimeStep">Discretization timestep.</param> /// <param name="Log">Where to send output.</param> /// <returns>TransientSolution describing the solution of the circuit.</returns> public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IEnumerable<Arrow> InitialConditions, ILog Log) { Expression h = TimeStep; Log.WriteLine(MessageType.Info, "Building solution for h={0}", TimeStep.ToString()); // Analyze the circuit to get the MNA system and unknowns. List<Equal> mna = Analysis.Equations.ToList(); List<Expression> y = Analysis.Unknowns.ToList(); LogExpressions(Log, MessageType.Verbose, "System of " + mna.Count + " equations and " + y.Count + " unknowns = {{ " + String.Join(", ", y) + " }}", mna); // Evaluate for simulation functions. // Define T = step size. Analysis.Add("T", h); // Define d[t] = delta function. Analysis.Add(ExprFunction.New("d", Call.If((0 <= t) & (t < h), 1, 0), t)); // Define u[t] = step function. Analysis.Add(ExprFunction.New("u", Call.If(t >= 0, 1, 0), t)); mna = mna.Resolve(Analysis).OfType<Equal>().ToList(); // Find out what variables have differential relationships. List<Expression> dy_dt = y.Where(i => mna.Any(j => j.DependsOn(D(i, t)))).Select(i => D(i, t)).ToList(); // Find steady state solution for initial conditions. List<Arrow> initial = InitialConditions.ToList(); Log.WriteLine(MessageType.Info, "Performing steady state analysis..."); SystemOfEquations dc = new SystemOfEquations(mna // Derivatives, t, and T are zero in the steady state. .Evaluate(dy_dt.Select(i => Arrow.New(i, 0)).Append(Arrow.New(t, 0), Arrow.New(T, 0))) // Use the initial conditions from analysis. .Evaluate(Analysis.InitialConditions) // Evaluate variables at t=0. .OfType<Equal>(), y.Select(j => j.Evaluate(t, 0))); // Solve partitions independently. foreach (SystemOfEquations i in dc.Partition()) { try { List<Arrow> part = i.Equations.Select(j => Equal.New(j, 0)).NSolve(i.Unknowns.Select(j => Arrow.New(j, 0))); initial.AddRange(part); LogExpressions(Log, MessageType.Verbose, "Initial conditions:", part); } catch (Exception) { Log.WriteLine(MessageType.Warning, "Failed to find partition initial conditions, simulation may be unstable."); } } // Transient analysis of the system. Log.WriteLine(MessageType.Info, "Performing transient analysis..."); SystemOfEquations system = new SystemOfEquations(mna, dy_dt.Concat(y)); // Solve the diff eq for dy/dt and integrate the results. system.RowReduce(dy_dt); system.BackSubstitute(dy_dt); IEnumerable<Equal> integrated = system.Solve(dy_dt) .NDIntegrate(t, h, IntegrationMethod.Trapezoid) // NDIntegrate finds y[t + h] in terms of y[t], we need y[t] in terms of y[t - h]. .Evaluate(t, t - h).Cast<Arrow>() .Select(i => Equal.New(i.Left, i.Right)).Buffer(); system.AddRange(integrated); LogExpressions(Log, MessageType.Verbose, "Integrated solutions:", integrated); LogExpressions(Log, MessageType.Verbose, "Discretized system:", system.Select(i => Equal.New(i, 0))); // Solving the system... List<SolutionSet> solutions = new List<SolutionSet>(); // Partition the system into independent systems of equations. foreach (SystemOfEquations F in system.Partition()) { // Find linear solutions for y. Linear systems should be completely solved here. F.RowReduce(); IEnumerable<Arrow> linear = F.Solve(); if (linear.Any()) { linear = Factor(linear); solutions.Add(new LinearSolutions(linear)); LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linear); } // If there are any variables left, there are some non-linear equations requiring numerical techniques to solve. if (F.Unknowns.Any()) { // The variables of this system are the newton iteration updates. List<Expression> dy = F.Unknowns.Select(i => NewtonIteration.Delta(i)).ToList(); // Compute JxF*dy + F(y0) == 0. SystemOfEquations nonlinear = new SystemOfEquations( F.Select(i => i.Gradient(F.Unknowns).Select(j => new KeyValuePair<Expression, Expression>(NewtonIteration.Delta(j.Key), j.Value)) .Append(new KeyValuePair<Expression, Expression>(1, i))), dy); // ly is the subset of y that can be found linearly. List<Expression> ly = dy.Where(j => !nonlinear.Any(i => i[j].DependsOn(NewtonIteration.DeltaOf(j)))).ToList(); // Find linear solutions for dy. nonlinear.RowReduce(ly); IEnumerable<Arrow> solved = nonlinear.Solve(ly); solved = Factor(solved); // Initial guess for y[t] = y[t - h]. IEnumerable<Arrow> guess = F.Unknowns.Select(i => Arrow.New(i, i.Evaluate(t, t - h))).ToList(); guess = Factor(guess); // Newton system equations. IEnumerable<LinearCombination> equations = nonlinear.Equations; equations = Factor(equations); solutions.Add(new NewtonIteration(solved, equations, nonlinear.Unknowns, guess)); LogExpressions(Log, MessageType.Verbose, String.Format("Non-linear Newton's method updates ({0}):", String.Join(", ", nonlinear.Unknowns)), equations.Select(i => Equal.New(i, 0))); LogExpressions(Log, MessageType.Verbose, "Linear Newton's method updates:", solved); } } Log.WriteLine(MessageType.Info, "System solved, {0} solution sets for {1} unknowns.", solutions.Count, solutions.Sum(i => i.Unknowns.Count())); return new TransientSolution( h, solutions, initial); }