diff --git a/Circuit/Analysis.cs b/Circuit/Analysis.cs
index ba49a030..9dc3c7b3 100644
--- a/Circuit/Analysis.cs
+++ b/Circuit/Analysis.cs
@@ -238,7 +238,11 @@ public Expression AddUnknownEqualTo(string Name, Expression Eq)
///
///
///
- public Expression AddUnknownEqualTo(Expression Eq) { return AddUnknownEqualTo(AnonymousName(), Eq); }
+ public Expression AddUnknownEqualTo(Expression x) {
+ if (x is Constant) return x;
+ if (x is Call c && c.Target is UnknownFunction) return x;
+ return AddUnknownEqualTo(AnonymousName(), x);
+ }
///
/// Add initial conditions to the system.
@@ -253,6 +257,55 @@ public Expression AddUnknownEqualTo(string Name, Expression Eq)
///
public string AnonymousName() { return context.AnonymousName(); }
+ ///
+ /// Describes a parameter for the circuit.
+ ///
+ public class Parameter
+ {
+ private Component of;
+ ///
+ /// Component the parameter affects.
+ ///
+ public Component Of { get { return of; } }
+
+ private Expression expr;
+ ///
+ /// Expression for the parameter in the system of equations for this analysis.
+ ///
+ public Expression Expression { get { return expr; } }
+
+ Func getter;
+ ///
+ /// Current value of the parameter.
+ ///
+ public double Value { get { return getter(); } }
+
+ public Parameter(Component Of, Expression Expression, Func Getter)
+ {
+ of = Of;
+ expr = Expression;
+ getter = Getter;
+ }
+ }
+
+ private List parameters = new List();
+ ///
+ /// Enumerates the parameters in this analysis.
+ ///
+ public IEnumerable Parameters { get { return parameters; } }
+
+ ///
+ /// Create an expression for a parameter in the current context.
+ ///
+ ///
+ ///
+ public Expression AddParameter(Component Of, string Name, Func Getter)
+ {
+ Expression expr = Variable.New(context.Prefix + Name);
+ parameters.Add(new Parameter(Of, expr, Getter));
+ return expr;
+ }
+
private void AddKcl(Dictionary kcl, Expression V, Expression i)
{
if (kcl.TryGetValue(V, out var sumi))
diff --git a/Circuit/Component.cs b/Circuit/Component.cs
index 87c028b5..f05f90e6 100644
--- a/Circuit/Component.cs
+++ b/Circuit/Component.cs
@@ -21,7 +21,7 @@ public interface IGroupableComponent
///
/// Interface for components that expose a pot controlled value.
///
- public interface IPotControl: IGroupableComponent
+ public interface IPotControl : IGroupableComponent
{
///
/// The value of the pot.
@@ -32,7 +32,7 @@ public interface IPotControl: IGroupableComponent
///
/// Interface for components that expose a button controlled value.
///
- public interface IButtonControl: IGroupableComponent
+ public interface IButtonControl : IGroupableComponent
{
void Click();
int Position { get; set; }
diff --git a/Circuit/Components/Capacitor.cs b/Circuit/Components/Capacitor.cs
index fe77ba6c..c8d98f66 100644
--- a/Circuit/Components/Capacitor.cs
+++ b/Circuit/Components/Capacitor.cs
@@ -25,7 +25,7 @@ public static Expression Analyze(Analysis Mna, string Name, Node Anode, Node Cat
V = Mna.AddUnknownEqualTo("V" + Name, V);
// i = C*dV/dt
Expression i = C * D(V, t);
- //i = Mna.AddUnknownEqualTo("i" + Name, i);
+ i = Mna.AddUnknownEqualTo("i" + Name, i);
Mna.AddPassiveComponent(Anode, Cathode, i);
return i;
}
diff --git a/Circuit/Components/Potentiometer.cs b/Circuit/Components/Potentiometer.cs
index 278ab974..c028e368 100644
--- a/Circuit/Components/Potentiometer.cs
+++ b/Circuit/Components/Potentiometer.cs
@@ -63,7 +63,7 @@ public void ConnectTo(Node A, Node C, Node W)
public override void Analyze(Analysis Mna)
{
- Expression P = VariableResistor.AdjustWipe(wipe, sweep);
+ Expression P = Mna.AddParameter(this, Name, () => VariableResistor.AdjustWipe(Wipe, Sweep));
Expression R1 = Resistance * P;
Expression R2 = Resistance * (1 - P);
diff --git a/Circuit/Components/VacuumTubes/Triode.cs b/Circuit/Components/VacuumTubes/Triode.cs
index 8fcec460..f2928405 100644
--- a/Circuit/Components/VacuumTubes/Triode.cs
+++ b/Circuit/Components/VacuumTubes/Triode.cs
@@ -146,7 +146,8 @@ public override void Analyze(Analysis Mna)
break;
case TriodeModel.Koren:
Expression E1 = Ln1Exp(Kp * (1.0 / Mu + Vgk * Binary.Power(Kvb + Vpk * Vpk, -0.5))) * Vpk / Kp;
- ip = Mna.AddUnknownEqualTo(Call.If(E1 > 0, 2d * (E1 ^ Ex) / Kg, 0));
+ ip = Call.If(E1 > 0, 2d * (E1 ^ Ex) / Kg, 0);
+ ip = Mna.AddUnknownEqualTo("Ip", ip);
var vg = (Real)Vg;
var knee = (Real)Kn;
@@ -156,7 +157,8 @@ public override void Analyze(Analysis Mna)
var b = (knee - vg) / (2 * knee * rg1);
var c = (-a * Binary.Power(vg - knee, 2)) - (b * (vg - knee));
- ig = Mna.AddUnknownEqualTo(Call.If(Vgk < vg - knee, 0, Call.If(Vgk > vg + knee, (Vgk - vg) / rg1, a * Vgk * Vgk + b * Vgk + c)));
+ ig = Call.If(Vgk < vg - knee, 0, Call.If(Vgk > vg + knee, (Vgk - vg) / rg1, a * Vgk * Vgk + b * Vgk + c));
+ ig = Mna.AddUnknownEqualTo("Ig", ig);
ik = -(ip + ig);
break;
case TriodeModel.DempwolfZolzer:
diff --git a/Circuit/Components/VariableResistor.cs b/Circuit/Components/VariableResistor.cs
index 13f5abf3..73f2d476 100644
--- a/Circuit/Components/VariableResistor.cs
+++ b/Circuit/Components/VariableResistor.cs
@@ -64,7 +64,7 @@ public class VariableResistor : TwoTerminal, IPotControl
protected double wipe = 0.5;
[Serialize, Description("Position of the wiper on this variable resistor, between 0 and 1.")]
- public double Wipe { get { return wipe; } set { wipe = value; NotifyChanged(nameof(Wipe)); } }
+ public double Wipe { get { return wipe; } set { wipe = value; NotifyChanged(nameof(Wipe)); NotifyChanged(nameof(IPotControl.PotValue)); } }
// IPotControl
double IPotControl.PotValue { get { return Wipe; } set { Wipe = value; } }
@@ -80,7 +80,7 @@ public class VariableResistor : TwoTerminal, IPotControl
public override void Analyze(Analysis Mna)
{
- Expression P = AdjustWipe(wipe, sweep);
+ Expression P = Mna.AddParameter(this, Name, () => AdjustWipe(Wipe, Sweep));
Resistor.Analyze(Mna, Name, Anode, Cathode, (Expression)Resistance * P);
}
diff --git a/Circuit/Components/VoltageSource.cs b/Circuit/Components/VoltageSource.cs
index d8be7ef9..686fcb5b 100644
--- a/Circuit/Components/VoltageSource.cs
+++ b/Circuit/Components/VoltageSource.cs
@@ -26,6 +26,9 @@ public static void Analyze(Analysis Mna, string Name, Node Anode, Node Cathode,
{
// Unknown current.
Mna.AddPassiveComponent(Anode, Cathode, Mna.AddUnknown("i" + Name));
+
+ V = Mna.AddUnknownEqualTo(V);
+
// Set the voltage.
Mna.AddEquation(Anode.V - Cathode.V, V);
}
@@ -35,7 +38,10 @@ public static void Analyze(Analysis Mna, string Name, Node Anode, Node Cathode,
Mna.AddInitialConditions(InitialConditions);
}
public static void Analyze(Analysis Mna, Node Anode, Node Cathode, Expression V) { Analyze(Mna, Mna.AnonymousName(), Anode, Cathode, V); }
- public static void Analyze(Analysis Mna, Node Anode, Node Cathode, Expression V, Arrow InitialConditions) { Analyze(Mna, Mna.AnonymousName(), Anode, Cathode, V, InitialConditions); }
+ public static void Analyze(Analysis Mna, Node Anode, Node Cathode, Expression V, Arrow InitialConditions)
+ {
+ Analyze(Mna, Mna.AnonymousName(), Anode, Cathode, V, InitialConditions);
+ }
public override void Analyze(Analysis Mna) { Analyze(Mna, Name, Anode, Cathode, Voltage); }
diff --git a/Circuit/Simulation/Simulation.cs b/Circuit/Simulation/Simulation.cs
index bac949f5..7d7c4594 100644
--- a/Circuit/Simulation/Simulation.cs
+++ b/Circuit/Simulation/Simulation.cs
@@ -6,6 +6,7 @@
using System.Numerics;
using System.Reflection;
using Util;
+using static Circuit.Analysis;
using LinqExpr = System.Linq.Expressions.Expression;
using ParamExpr = System.Linq.Expressions.ParameterExpression;
@@ -98,6 +99,12 @@ public TransientSolution Solution
///
public IEnumerable Output { get { return output; } set { output = value.ToArray(); InvalidateProcess(); } }
+ private Expression[] arguments = new Expression[] { };
+ ///
+ /// Expressions for parameters.
+ ///
+ public IEnumerable Arguments { get { return arguments; } set { arguments = value.ToArray(); InvalidateProcess(); } }
+
// Stores any global state in the simulation (previous state values, mostly).
private Dictionary> globals = new Dictionary>();
// Add a new global and set it to 0 if it didn't already exist.
@@ -153,7 +160,8 @@ public Simulation(TransientSolution Solution)
/// Number of samples to process.
/// Buffers that describe the input samples.
/// Buffers to receive output samples.
- public void Run(int N, IEnumerable Input, IEnumerable Output)
+ /// Scalar values for the arguments.
+ public void Run(int N, IEnumerable Input, IEnumerable Output, IEnumerable Parameters)
{
if (_process == null)
_process = DefineProcess();
@@ -162,7 +170,7 @@ public void Run(int N, IEnumerable Input, IEnumerable Output
{
try
{
- _process(N, n*TimeStep, Input.AsArray(), Output.AsArray());
+ _process(N, n*TimeStep, Input.AsArray(), Output.AsArray(), Parameters.AsArray());
n += N;
}
catch (TargetInvocationException Ex)
@@ -175,11 +183,11 @@ public void Run(int N, IEnumerable Input, IEnumerable Output
throw new SimulationDiverged("Simulation diverged near t = " + Quantity.ToString(Time, Units.s) + " + " + Ex.At, n + Ex.At);
}
}
- public void Run(int N, IEnumerable Output) { Run(N, new double[][] { }, Output); }
- public void Run(double[] Input, IEnumerable Output) { Run(Input.Length, new[] { Input }, Output); }
- public void Run(double[] Input, double[] Output) { Run(Input.Length, new[] { Input }, new[] { Output }); }
+ public void Run(int N, IEnumerable Output, IEnumerable Parameters) { Run(N, new double[][] { }, Output, Parameters); }
+ public void Run(double[] Input, IEnumerable Output, IEnumerable Parameters) { Run(Input.Length, new[] { Input }, Output, Parameters); }
+ public void Run(double[] Input, double[] Output, IEnumerable Parameters) { Run(Input.Length, new[] { Input }, new[] { Output }, Parameters); }
- private Action _process;
+ private Action _process;
// Force rebuilding of the process function.
private void InvalidateProcess()
{
@@ -189,11 +197,12 @@ private void InvalidateProcess()
// The resulting lambda processes N samples, using buffers provided for Input and Output:
// void Process(int N, double t0, double T, double[] Input0 ..., double[] Output0 ...)
// { ... }
- private Action DefineProcess()
+ private Action DefineProcess()
{
// Map expressions to identifiers in the syntax tree.
var inputs = new List>();
var outputs = new List>();
+ var parameters = new List>();
// Lambda code generator.
CodeGen code = new CodeGen();
@@ -203,6 +212,7 @@ private Action DefineProcess()
ParamExpr t = code.Decl(Scope.Parameter, Simulation.t);
var ins = code.Decl(Scope.Parameter, "ins");
var outs = code.Decl(Scope.Parameter, "outs");
+ var parms = code.Decl(Scope.Parameter, "params");
// Create buffer parameters for each input...
for (int i = 0; i < input.Length; i++)
@@ -216,6 +226,11 @@ private Action DefineProcess()
outputs.Add(new KeyValuePair(output[i], LinqExpr.ArrayAccess(outs, LinqExpr.Constant(i))));
}
+ for (int i = 0; i < arguments.Length; i++)
+ {
+ parameters.Add(new KeyValuePair(arguments[i], LinqExpr.ArrayAccess(parms, LinqExpr.Constant(i))));
+ }
+
Arrow t_t1 = Arrow.New(Simulation.t, Simulation.t - Solution.TimeStep);
// Create globals to store previous values of inputs.
@@ -240,6 +255,9 @@ private Action DefineProcess()
foreach (KeyValuePair i in inputs)
code.DeclInit(i.Key, code[i.Key.Evaluate(t_t1)]);
+ foreach (KeyValuePair i in parameters)
+ code.DeclInit(i.Key, i.Value);
+
// Create arrays for linear systems.
int M = Solution.Solutions.OfType().Max(i => i.Equations.Count(), 0);
int N = Solution.Solutions.OfType().Max(i => i.UnknownDeltas.Count(), 0);
@@ -409,7 +427,7 @@ private Action DefineProcess()
foreach (KeyValuePair> i in globals)
code.Add(LinqExpr.Assign(i.Value, code[i.Key]));
- var lambda = code.Build>();
+ var lambda = code.Build>();
return lambda.Compile();
}
diff --git a/Circuit/Simulation/TransientSolution.cs b/Circuit/Simulation/TransientSolution.cs
index 5bcd775b..7ea5d924 100644
--- a/Circuit/Simulation/TransientSolution.cs
+++ b/Circuit/Simulation/TransientSolution.cs
@@ -79,10 +79,10 @@ public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IE
// Define T = step size.
DynamicNamespace globals = new DynamicNamespace();
globals.Add("T", h);
- // Define d[t] = delta function.
+ // Define dq = delta function.
// TODO: This should probably be centered around 0, and also have an integral of 1 (i.e. a height of 1 / h).
globals.Add(ExprFunction.New("d", Call.If((0 <= t) & (t < h), 1, 0), t));
- // Define u[t] = step function.
+ // Define uq = step function.
globals.Add(ExprFunction.New("u", Call.If(t >= 0, 1, 0), t));
mna = mna.Resolve(Analysis).Resolve(globals).OfType().ToList();
@@ -101,6 +101,8 @@ public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IE
.Substitute(dy_dt.Select(i => Arrow.New(i, 0)).Append(Arrow.New(t, 0), Arrow.New(T, 0), SinglePoleSwitch.IncludeOpen))
// Use the initial conditions from analysis.
.Substitute(Analysis.InitialConditions)
+ // Use the default parameter values.
+ .Substitute(Analysis.Parameters.Select(i => Arrow.New(i.Expression, i.Value)))
// Evaluate variables at t=0.
.OfType(), y.Select(j => j.Substitute(t, 0)));
@@ -149,12 +151,13 @@ public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IE
Log.WriteLine(MessageType.Verbose, "Partition unknowns: {0}", String.Join(", ", F.Unknowns));
// Find linear solutions for y. Linear systems should be completely solved here.
F.RowReduce();
- IEnumerable linear = F.Solve();
- if (linear.Any())
+ List linearFwd = new List();
+ List linearBack = new List();
+ F.PartialSolve(linearFwd, linearBack);
+ if (linearFwd.Any())
{
- linear = Factor(linear);
- solutions.Add(new LinearSolutions(linear));
- LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linear);
+ solutions.Add(new LinearSolutions(linearFwd));
+ LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linearFwd);
}
// If there are any variables left, there are some non-linear equations requiring numerical techniques to solve.
@@ -175,20 +178,23 @@ public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IE
// Find linear solutions for dy.
nonlinear.RowReduce(ly);
IEnumerable solved = nonlinear.Solve(ly);
- solved = Factor(solved);
// Initial guess for y[t] = y[t - h].
IEnumerable guess = F.Unknowns.Select(i => Arrow.New(i, i.Substitute(t, t - h))).ToList();
- guess = Factor(guess);
// Newton system equations.
IEnumerable equations = nonlinear.Equations.Buffer();
- 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);
}
+
+ if (linearBack.Any())
+ {
+ solutions.Add(new LinearSolutions(linearBack));
+ LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linearBack);
+ }
}
Log.WriteLine(MessageType.Info, "System solved, {0} solution sets for {1} unknowns.",
@@ -206,9 +212,6 @@ public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IE
public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, ILog Log) { return Solve(Analysis, TimeStep, new Arrow[] { }, Log); }
public static TransientSolution Solve(Analysis Analysis, Expression TimeStep) { return Solve(Analysis, TimeStep, new Arrow[] { }, new NullLog()); }
- private static IEnumerable Factor(IEnumerable x) { return x.Select(i => Arrow.New(i.Left, i.Right.Factor())).Buffer(); }
- private static IEnumerable Factor(IEnumerable x) { return x.Select(i => LinearCombination.New(i.Select(j => new KeyValuePair(j.Key, j.Value.Factor())))).Buffer(); }
-
// Shorthand for df/dx.
protected static Expression D(Expression f, Expression x) { return Call.D(f, x); }
diff --git a/LiveSPICE/LiveSimulation.xaml.cs b/LiveSPICE/LiveSimulation.xaml.cs
index c2231fb1..5cc856eb 100644
--- a/LiveSPICE/LiveSimulation.xaml.cs
+++ b/LiveSPICE/LiveSimulation.xaml.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
+using System.Printing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -65,6 +66,7 @@ public int Iterations
protected Simulation simulation = null;
private List probes = new List();
+ protected Dictionary namedArguments = new Dictionary();
private object sync = new object();
@@ -96,6 +98,52 @@ public LiveSimulation(Schematic Simulate, Audio.Device Device, Audio.Channel[] I
// Build the circuit from the schematic.
circuit = Schematic.Schematic.Build(Log);
+ Circuit.Analysis analysis = circuit.Analyze();
+
+ foreach (Circuit.Analysis.Parameter P in analysis.Parameters)
+ {
+ namedArguments[P.Expression] = P.Value;
+
+ Circuit.Symbol S = P.Of.Tag as Circuit.Symbol;
+ if (S == null)
+ continue;
+
+ SymbolControl tag = S.Tag as SymbolControl;
+ if (tag == null)
+ continue;
+
+ IPotControl pot = (IPotControl)P.Of;
+ var potControl = new PotControl()
+ {
+ Width = 80,
+ Height = 80,
+ Opacity = 0.5,
+ FontSize = 15,
+ FontWeight = FontWeights.Bold,
+ Value = pot.PotValue,
+ };
+ Schematic.Overlays.Children.Add(potControl);
+ Canvas.SetLeft(potControl, Canvas.GetLeft(tag) - potControl.Width / 2 + tag.Width / 2);
+ Canvas.SetTop(potControl, Canvas.GetTop(tag) - potControl.Height / 2 + tag.Height / 2);
+
+ var binding = new Binding
+ {
+ Source = pot,
+ Path = new PropertyPath("(0)", typeof(IPotControl).GetProperty(nameof(IPotControl.PotValue))),
+ Mode = BindingMode.TwoWay,
+ NotifyOnSourceUpdated = true
+ };
+
+ potControl.SetBinding(PotControl.ValueProperty, binding);
+
+ potControl.AddHandler(Binding.SourceUpdatedEvent, new RoutedEventHandler((o, args) =>
+ {
+ lock (namedArguments) namedArguments[P.Expression] = P.Value;
+ }));
+
+ potControl.MouseEnter += (o, e) => potControl.Opacity = 0.95;
+ potControl.MouseLeave += (o, e) => potControl.Opacity = 0.4;
+ }
// Create the input and output controls.
IEnumerable components = circuit.Components;
@@ -116,47 +164,6 @@ public LiveSimulation(Schematic Simulate, Audio.Device Device, Audio.Channel[] I
if (tag == null)
continue;
- // Create potentiometers.
- if (i is IPotControl potentiometer)
- {
- var potControl = new PotControl()
- {
- Width = 80,
- Height = 80,
- Opacity = 0.5,
- FontSize = 15,
- FontWeight = FontWeights.Bold,
- };
- Schematic.Overlays.Children.Add(potControl);
- Canvas.SetLeft(potControl, Canvas.GetLeft(tag) - potControl.Width / 2 + tag.Width / 2);
- Canvas.SetTop(potControl, Canvas.GetTop(tag) - potControl.Height / 2 + tag.Height / 2);
-
- var binding = new Binding
- {
- Source = potentiometer,
- Path = new PropertyPath("(0)", typeof(IPotControl).GetProperty(nameof(IPotControl.PotValue))),
- Mode = BindingMode.TwoWay,
- NotifyOnSourceUpdated = true
- };
-
- potControl.SetBinding(PotControl.ValueProperty, binding);
-
- potControl.AddHandler(Binding.SourceUpdatedEvent, new RoutedEventHandler((o, args) =>
- {
- if (!string.IsNullOrEmpty(potentiometer.Group))
- {
- foreach (var p in components.OfType().Where(p => p != potentiometer && p.Group == potentiometer.Group))
- {
- p.PotValue = (o as PotControl).Value;
- }
- }
- UpdateSimulation(false);
- }));
-
- potControl.MouseEnter += (o, e) => potControl.Opacity = 0.95;
- potControl.MouseLeave += (o, e) => potControl.Opacity = 0.5;
- }
-
// Create Buttons.
if (i is IButtonControl b)
{
@@ -180,7 +187,7 @@ public LiveSimulation(Schematic Simulate, Audio.Device Device, Audio.Channel[] I
foreach (var j in components.OfType().Where(x => x != b && x.Group == b.Group))
j.Click();
}
- UpdateSimulation(true);
+ UpdateSimulation();
};
button.MouseEnter += (o, e) => button.Opacity = 0.95;
@@ -286,6 +293,19 @@ public LiveSimulation(Schematic Simulate, Audio.Device Device, Audio.Channel[] I
}
}
+ private Simulation MakeSimulation(TransientSolution solution)
+ {
+ return new Simulation(solution)
+ {
+ Log = Log,
+ Input = inputs.Keys.ToArray(),
+ Output = probes.Select(i => i.V).Concat(OutputChannels.Select(i => i.Signal)).ToArray(),
+ Arguments = namedArguments.Select(i => i.Key).ToArray(),
+ Oversample = Oversample,
+ Iterations = Iterations,
+ };
+ }
+
private void RebuildSolution()
{
lock (sync)
@@ -297,15 +317,7 @@ private void RebuildSolution()
{
ComputerAlgebra.Expression h = (ComputerAlgebra.Expression)1 / (stream.SampleRate * Oversample);
TransientSolution solution = Circuit.TransientSolution.Solve(circuit.Analyze(), h, Log);
-
- simulation = new Simulation(solution)
- {
- Log = Log,
- Input = inputs.Keys.ToArray(),
- Output = probes.Select(i => i.V).Concat(OutputChannels.Select(i => i.Signal)).ToArray(),
- Oversample = Oversample,
- Iterations = Iterations,
- };
+ simulation = MakeSimulation(solution);
}
catch (Exception Ex)
{
@@ -315,39 +327,14 @@ private void RebuildSolution()
}
}
- private int clock = -1;
- private int update = 0;
- private TaskScheduler scheduler = new RedundantTaskScheduler(1);
- private void UpdateSimulation(bool Rebuild)
+ private void UpdateSimulation()
{
- int id = Interlocked.Increment(ref update);
- new Task(() =>
+ ComputerAlgebra.Expression h = (ComputerAlgebra.Expression)1 / (stream.SampleRate * Oversample);
+ TransientSolution s = Circuit.TransientSolution.Solve(circuit.Analyze(), h, (ILog)Log);
+ lock (sync)
{
- ComputerAlgebra.Expression h = (ComputerAlgebra.Expression)1 / (stream.SampleRate * Oversample);
- TransientSolution s = Circuit.TransientSolution.Solve(circuit.Analyze(), h, Rebuild ? (ILog)Log : new NullLog());
- lock (sync)
- {
- if (id > clock)
- {
- if (Rebuild)
- {
- simulation = new Simulation(s)
- {
- Log = Log,
- Input = inputs.Keys.ToArray(),
- Output = probes.Select(i => i.V).Concat(OutputChannels.Select(i => i.Signal)).ToArray(),
- Oversample = Oversample,
- Iterations = Iterations,
- };
- }
- else
- {
- simulation.Solution = s;
- clock = id;
- }
- }
- }
- }).Start(scheduler);
+ simulation = MakeSimulation(s);
+ }
}
private void ProcessSamples(int Count, Audio.SampleBuffer[] In, Audio.SampleBuffer[] Out, double Rate)
@@ -388,6 +375,7 @@ private void ProcessSamples(int Count, Audio.SampleBuffer[] In, Audio.SampleBuff
// These lists only ever grow, but they should never contain more than 10s of items.
readonly List inputBuffers = new List();
readonly List outputBuffers = new List();
+ readonly List arguments = new List();
private void RunSimulation(int Count, Audio.SampleBuffer[] In, Audio.SampleBuffer[] Out, double Rate)
{
try
@@ -415,8 +403,12 @@ private void RunSimulation(int Count, Audio.SampleBuffer[] In, Audio.SampleBuffe
for (int i = 0; i < Out.Length; ++i)
outputBuffers.Add(Out[i].Samples);
+ arguments.Clear();
+ foreach (double i in namedArguments.Select(i => i.Value))
+ arguments.Add(i);
+
// Process the samples!
- simulation.Run(Count, inputBuffers, outputBuffers);
+ simulation.Run(Count, inputBuffers, outputBuffers, arguments);
// Show the samples on the oscilloscope.
long clock = Scope.Signals.Clock;
diff --git a/Tests/Test.cs b/Tests/Test.cs
index c2244990..940b9f5f 100644
--- a/Tests/Test.cs
+++ b/Tests/Test.cs
@@ -66,11 +66,14 @@ public Dictionary> Run(
Iterations = Iterations,
Input = new[] { Input },
Output = Outputs,
+ Arguments = analysis.Parameters.Select(i => i.Expression),
};
Dictionary> outputs =
S.Output.ToDictionary(i => i, i => new List(Samples));
+ double[] parameters = analysis.Parameters.Select(i => i.Value).ToArray();
+
double T = S.TimeStep;
double t = 0;
Random rng = new Random();
@@ -80,11 +83,11 @@ public Dictionary> Run(
// Using a varying number of samples on each call to S.Run
int N = Math.Min(remaining, rng.Next(1000, 10000));
double[] inputBuffer = new double[N];
- List outputBuffers = S.Output.Select(i => new double[N]).ToList();
+ double[][] outputBuffers = S.Output.Select(i => new double[N]).ToArray();
for (int n = 0; n < N; ++n, t += T)
inputBuffer[n] = Vin(t);
- S.Run(inputBuffer, outputBuffers);
+ S.Run(inputBuffer, outputBuffers, parameters);
for (int i = 0; i < S.Output.Count(); ++i)
outputs[S.Output.ElementAt(i)].AddRange(outputBuffers[i]);
@@ -135,12 +138,14 @@ public double[] Benchmark(
Iterations = Iterations,
Input = new[] { Input },
Output = Outputs,
+ Arguments = analysis.Parameters.Select(i => i.Expression),
};
int N = 1000;
double[] inputBuffer = new double[N];
- List outputBuffers = Outputs.Select(i => new double[N]).ToList();
+ double[][] outputBuffers = Outputs.Select(i => new double[N]).ToArray();
+ double[] parameters = analysis.Parameters.Select(i => i.Value).ToArray();
double T = 1.0 / SampleRate;
double t = 0;
double runTime = Benchmark(3, () =>
@@ -149,7 +154,7 @@ public double[] Benchmark(
for (int n = 0; n < N; ++n, t += T)
inputBuffer[n] = Vin(t);
- S.Run(inputBuffer, outputBuffers);
+ S.Run(inputBuffer, outputBuffers, parameters);
});
double rate = N / runTime;
return new double[] { analyzeTime, solveTime, rate };