public double Run(Circuit.Circuit C, Func <double, double> Vin, Expression Input, IEnumerable <Expression> Plots) { long a = Timer.Counter; Analysis analysis = C.Analyze(); TransientSolution TS = TransientSolution.Solve(analysis, (Real)1 / (SampleRate * Oversample), Log); analysisTime += Timer.Delta(a); Simulation S = new Simulation(TS) { Oversample = Oversample, Iterations = Iterations, Log = Log, Input = new[] { Input }, Output = Plots, }; Log.WriteLine(""); if (Samples > 0) { return(RunTest( C, S, Vin, Samples, C.Name)); } else { return(0.0); } }
public void ClearSchematic() { Schematic = null; SchematicPath = ""; circuit = null; InteractiveComponents.Clear(); }
public double RunTest(Circuit.Circuit C, Simulation S, Func <double, double> Vin, int Samples, string Name) { double t0 = (double)S.Time; double T = S.TimeStep; int N = 353; double[] input = new double[N]; List <List <double> > output = S.Output.Select(i => new List <double>(Samples)).ToList(); List <double[]> buffers = S.Output.Select(i => new double[N]).ToList(); double time = 0.0; int samples = 0; double t = 0; for (; samples < Samples; samples += N) { for (int n = 0; n < N; ++n, t += T) { input[n] = Vin(t); } long a = Timer.Counter; S.Run(input, buffers); time += Timer.Delta(a); for (int i = 0; i < S.Output.Count(); ++i) { output[i].AddRange(buffers[i]); } } simulateTime += time; int t1 = Math.Min(samples, 4000); Log.WriteLine("Performance {0}", Quantity.ToString(samples / time, Units.Hz)); Plot p = new Plot() { Title = Name, Width = 800, Height = 400, x0 = t0, x1 = T * t1, xLabel = "Time (s)", yLabel = "Voltage (V)", }; p.Series.AddRange(output.Select((i, j) => new Scatter( i.Take(t1) .Select((k, n) => new KeyValuePair <double, double>(n * T, k)).ToArray()) { Name = S.Output.ElementAt(j).ToString() })); return(samples / time); }
private static Expression FindInput(Circuit.Circuit C) { return(C.Components.Where(i => i is Input) .Select(i => Component.DependentVariable(i.Name, Component.t)) // If there are no inputs, just make a dummy. .DefaultIfEmpty("V[t]") // Require exactly one input. .Single()); }
private static Expression FindInput(Circuit.Circuit C) { return(C.Components.OfType <Input>() .Select(i => i.In) // If there are no inputs, just make a dummy. .DefaultIfEmpty("V[t]") // Require exactly one input. .Single()); }
public double Run(string FileName, Func <double, double> Vin) { Circuit.Circuit C = Schematic.Load(FileName, Log).Build(); C.Name = System.IO.Path.GetFileNameWithoutExtension(FileName); return(Run( C, Vin, C.Components.OfType <Input>().Select(i => Expression.Parse(i.Name + "[t]")).DefaultIfEmpty("V[t]").SingleOrDefault(), C.Nodes.Select(i => i.V))); }
public void LoadSchematic(string path) { Schematic newSchematic = Circuit.Schematic.Load(path); Circuit.Circuit circuit = newSchematic.Build(); SetCircuit(circuit); Schematic = newSchematic; SchematicPath = path; }
void SetCircuit(Circuit.Circuit circuit) { this.circuit = circuit; InteractiveComponents.Clear(); Dictionary <string, ButtonWrapper> buttonGroups = new Dictionary <string, ButtonWrapper>(); foreach (Circuit.Component i in circuit.Components) { if (i is IPotControl) { InteractiveComponents.Add(new PotWrapper((i as IPotControl), i.Name)); } else if (i is IButtonControl) { IButtonControl button = (i as IButtonControl); ButtonWrapper wrapper = null; if (string.IsNullOrEmpty(button.Group)) { wrapper = new ButtonWrapper(i.Name); InteractiveComponents.Add(wrapper); } else if (buttonGroups.ContainsKey(button.Group)) { wrapper = buttonGroups[button.Group]; } else { wrapper = new ButtonWrapper(button.Group); buttonGroups[button.Group] = wrapper; InteractiveComponents.Add(wrapper); } wrapper.AddButton(button); } } needRebuild = true; }
static void Main(string[] args) { bool test = args.Contains("--test"); bool benchmark = args.Contains("--benchmark"); bool plot = args.Contains("--plot"); Log log = new ConsoleLog() { Verbosity = MessageType.Info }; Test tester = new Test(); foreach (string i in args.Where(i => !i.StartsWith("--"))) { foreach (string File in Globber.Glob(i)) { System.Console.WriteLine(File); Circuit.Circuit C = Schematic.Load(File, log).Build(); C.Name = Path.GetFileNameWithoutExtension(File); if (test) { Dictionary <Expression, List <double> > outputs = tester.Run(C, t => Harmonics(t, 0.5, 82, 2), SampleRate, Samples, Oversample, Iterations); if (plot) { tester.PlotAll(C.Name, outputs); } } if (benchmark) { tester.Benchmark(C, t => Harmonics(t, 0.5, 82, 2), SampleRate, Oversample, Iterations); } System.Console.WriteLine(""); } } }
public Dictionary <Expression, List <double> > Run( Circuit.Circuit C, Func <double, double> Vin, int SampleRate, int Samples, int Oversample, int Iterations, Expression Input = null, IEnumerable <Expression> Outputs = null) { Analysis analysis = C.Analyze(); TransientSolution TS = TransientSolution.Solve(analysis, (Real)1 / (SampleRate * Oversample)); // By default, pass Vin to each input of the circuit. if (Input == null) { Input = C.Components.Where(i => i is Input) .Select(i => Component.DependentVariable(i.Name, Component.t)) // If there are no inputs, just make a dummy. .DefaultIfEmpty("V[t]") // Require exactly one input. .Single(); } // By default, produce every node of the circuit as output. if (Outputs == null) { Outputs = C.Nodes.Select(i => i.V); } Simulation S = new Simulation(TS) { Oversample = Oversample, Iterations = Iterations, Input = new[] { Input }, Output = Outputs, }; Dictionary <Expression, List <double> > outputs = S.Output.ToDictionary(i => i, i => new List <double>(Samples)); double T = S.TimeStep; double t = 0; Random rng = new Random(); int remaining = Samples; while (remaining > 0) { // 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 <double[]> outputBuffers = S.Output.Select(i => new double[N]).ToList(); for (int n = 0; n < N; ++n, t += T) { inputBuffer[n] = Vin(t); } S.Run(inputBuffer, outputBuffers); for (int i = 0; i < S.Output.Count(); ++i) { outputs[S.Output.ElementAt(i)].AddRange(outputBuffers[i]); } remaining -= N; } return(outputs); }
/// <summary> /// Begin analysis of a new context. /// </summary> /// <param name="Name"></param> public void PushContext(string Name) { context = new Circuit(context, Name); }
/// <summary> /// Benchmark a circuit simulation. /// By default, benchmarks producing the sum of all output components. /// </summary> /// <returns>The rate at which the circuit simulated, in samples per second.</returns> public void Benchmark( Circuit.Circuit C, Func <double, double> Vin, int SampleRate, int Oversample, int Iterations, Expression Input = null, IEnumerable <Expression> Outputs = null) { Analysis analysis = null; double analyzeTime = Benchmark(1, () => analysis = C.Analyze()); System.Console.WriteLine("Circuit.Analyze time: {0:G3} ms", analyzeTime * 1000); TransientSolution TS = null; double solveTime = Benchmark(1, () => TS = TransientSolution.Solve(analysis, (Real)1 / (SampleRate * Oversample))); System.Console.WriteLine("TransientSolution.Solve time: {0:G3} ms", solveTime * 1000); // By default, pass Vin to each input of the circuit. if (Input == null) { Input = FindInput(C); } // By default, produce every node of the circuit as output. if (Outputs == null) { Expression sum = 0; foreach (Speaker i in C.Components.Where(i => i is Speaker)) { sum += Component.DependentVariable(i.Name, Component.t); } Outputs = new[] { sum }; } Simulation S = null; double simTime = Benchmark(1, () => S = new Simulation(TS) { Oversample = Oversample, Iterations = Iterations, Input = new[] { Input }, Output = Outputs, }); System.Console.WriteLine("Simulation.Simulation time: {0} ms", simTime * 1000); int N = 1000; double[] inputBuffer = new double[N]; List <double[]> outputBuffers = Outputs.Select(i => new double[N]).ToList(); double T = 1.0 / SampleRate; double t = 0; double runTime = Benchmark(3, () => { // This is counting the cost of evaluating Vin during benchmarking... for (int n = 0; n < N; ++n, t += T) { inputBuffer[n] = Vin(t); } S.Run(inputBuffer, outputBuffers); }); double rate = N / runTime; System.Console.WriteLine("{0:G3} kHz, {1:G3}x real time", rate / 1000, rate / SampleRate); }
public Circuit(Circuit Parent, string Name) { parent = Parent; name = Name; }
public double Run(string FileName, Func <double, double> Vin, Expression Input, IEnumerable <Expression> Plots) { Circuit.Circuit C = Schematic.Load(FileName, Log).Build(); C.Name = System.IO.Path.GetFileNameWithoutExtension(FileName); return(Run(C, Vin, Input, Plots)); }
void SetCircuit(Circuit.Circuit circuit) { this.circuit = circuit; InteractiveComponents.Clear(); Dictionary <string, ButtonWrapper> buttonGroups = new Dictionary <string, ButtonWrapper>(); Dictionary <string, PotWrapper> potGroups = new Dictionary <string, PotWrapper>(); foreach (Circuit.Component i in circuit.Components) { if (i is IPotControl pot) { if (string.IsNullOrEmpty(pot.Group)) { InteractiveComponents.Add(new PotWrapper(pot, i.Name)); } else if (potGroups.TryGetValue(pot.Group, out var wrapper)) { wrapper.AddSection(pot); } else { wrapper = new PotWrapper(pot, pot.Group); potGroups.Add(pot.Group, wrapper); InteractiveComponents.Add(wrapper); } } else if (i is IButtonControl button) { ButtonWrapper wrapper; if (string.IsNullOrEmpty(button.Group)) { if (button.NumPositions == 2) { wrapper = new DoubleThrowWrapper(button, i.Name); InteractiveComponents.Add(wrapper); } else { wrapper = new MultiThrowWrapper(button, i.Name); InteractiveComponents.Add(wrapper); } } else if (buttonGroups.ContainsKey(button.Group)) { wrapper = buttonGroups[button.Group]; wrapper.AddSection(button); } else { if (button.NumPositions == 2) { wrapper = new DoubleThrowWrapper(button, button.Group); } else { wrapper = new MultiThrowWrapper(button, i.Name); } buttonGroups[button.Group] = wrapper; InteractiveComponents.Add(wrapper); } } } needRebuild = true; }
public LiveSimulation(Schematic Simulate, Audio.Device Device, Audio.Channel[] Inputs, Audio.Channel[] Outputs) { try { InitializeComponent(); // Make a clone of the schematic so we can mess with it. var clone = Circuit.Schematic.Deserialize(Simulate.Serialize(), Log); clone.Elements.ItemAdded += OnElementAdded; clone.Elements.ItemRemoved += OnElementRemoved; Schematic = new SimulationSchematic(clone); Schematic.SelectionChanged += OnProbeSelected; // Build the circuit from the schematic. circuit = Schematic.Schematic.Build(Log); // Create the input and output controls. IEnumerable <Circuit.Component> components = circuit.Components; // Create audio input channels. for (int i = 0; i < Inputs.Length; ++i) { InputChannels.Add(new InputChannel(i) { Name = Inputs[i].Name }); } ComputerAlgebra.Expression speakers = 0; foreach (Circuit.Component i in components) { Symbol S = i.Tag as Symbol; if (S == null) { continue; } SymbolControl tag = (SymbolControl)S.Tag; 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 <IPotControl>().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) { Button button = new Button() { Width = tag.Width, Height = tag.Height, Opacity = 0.5, Background = Brushes.White, }; Schematic.Overlays.Children.Add(button); Canvas.SetLeft(button, Canvas.GetLeft(tag)); Canvas.SetTop(button, Canvas.GetTop(tag)); button.Click += (o, e) => { b.Click(); // Click all the buttons in the group. if (!string.IsNullOrEmpty(b.Group)) { foreach (var j in components.OfType <IButtonControl>().Where(x => x != b && x.Group == b.Group)) { j.Click(); } } UpdateSimulation(true); }; button.MouseEnter += (o, e) => button.Opacity = 0.95; button.MouseLeave += (o, e) => button.Opacity = 0.5; } if (i is Speaker output) { speakers += output.Out; } // Create input controls. if (i is Input input) { tag.ShowText = false; ComboBox combo = new ComboBox() { Width = 80, Height = 24, Opacity = 0.5, IsEditable = true, SelectedValuePath = "Tag", }; foreach (InputChannel j in InputChannels) { combo.Items.Add(new ComboBoxItem() { Tag = j, Content = j.Name }); } Schematic.Overlays.Children.Add(combo); Canvas.SetLeft(combo, Canvas.GetLeft(tag) - combo.Width / 2 + tag.Width / 2); Canvas.SetTop(combo, Canvas.GetTop(tag) - combo.Height / 2 + tag.Height / 2); ComputerAlgebra.Expression In = input.In; inputs[In] = new SignalChannel(0); combo.SelectionChanged += (o, e) => { if (combo.SelectedItem != null) { ComboBoxItem it = (ComboBoxItem)combo.SelectedItem; inputs[In] = new InputChannel(((InputChannel)it.Tag).Index); } }; combo.AddHandler(TextBox.KeyDownEvent, new KeyEventHandler((o, e) => { try { inputs[In] = new SignalChannel(ComputerAlgebra.Expression.Parse(combo.Text)); } catch (Exception) { // If there is an error in the expression, zero out the signal. inputs[In] = new SignalChannel(0); } })); if (combo.Items.Count > 0) { combo.SelectedItem = combo.Items[0]; } else { combo.Text = "0 V"; } combo.MouseEnter += (o, e) => combo.Opacity = 0.95; combo.MouseLeave += (o, e) => combo.Opacity = 0.5; } } // Create audio output channels. for (int i = 0; i < Outputs.Length; ++i) { OutputChannel c = new OutputChannel(i) { Name = Outputs[i].Name, Signal = speakers }; c.PropertyChanged += (o, e) => { if (e.PropertyName == "Signal") { RebuildSolution(); } }; OutputChannels.Add(c); } // Begin audio processing. if (Inputs.Any() || Outputs.Any()) { stream = Device.Open(ProcessSamples, Inputs, Outputs); } else { stream = new NullStream(ProcessSamples); } ContentRendered += (o, e) => RebuildSolution(); Closed += (s, e) => stream.Stop(); timer = new System.Timers.Timer() { Interval = 100, AutoReset = true, Enabled = true, }; timer.Elapsed += timer_Elapsed; timer.Start(); } catch (Exception Ex) { MessageBox.Show(Ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
/// <summary> /// End analysis of the current context. /// </summary> public void PopContext() { // Evaluate the definitions from the context for the equations and add the results to the analysis. foreach (Equal i in context.Equations) { Equal ei = (Equal)Evaluate(i, context.Definitions); if (!equations.Contains(ei)) equations.Add(ei); } // And the KCL equations. foreach (KeyValuePair<Expression, Expression> i in context.Kcl) AddKcl(kcl, i.Key, Evaluate(i.Value, context.Definitions)); // And the initial conditions. initialConditions.AddRange(context.InitialConditions.Evaluate(context.Definitions).OfType<Arrow>()); foreach (Node i in context.Nodes) i.EndAnalysis(); context = context.Parent; }
public double RunTest(Circuit.Circuit C, Simulation S, Func<double, double> Vin, int Samples, string Name) { double t0 = (double)S.Time; double T = S.TimeStep; int N = 353; double[] input = new double[N]; List<List<double>> output = S.Output.Select(i => new List<double>(Samples)).ToList(); List<double[]> buffers = S.Output.Select(i => new double[N]).ToList(); double time = 0.0; int samples = 0; double t = 0; for (; samples < Samples; samples += N) { for (int n = 0; n < N; ++n, t += T) input[n] = Vin(t); long a = Timer.Counter; S.Run(input, buffers); time += Timer.Delta(a); for (int i = 0; i < S.Output.Count(); ++i) output[i].AddRange(buffers[i]); } simulateTime += time; int t1 = Math.Min(samples, 4000); Log.WriteLine("Performance {0}", Quantity.ToString(samples / time, Units.Hz)); Plot p = new Plot() { Title = Name, Width = 800, Height = 400, x0 = t0, x1 = T * t1, xLabel = "Time (s)", yLabel = "Voltage (V)", }; p.Series.AddRange(output.Select((i, j) => new Scatter( i.Take(t1) .Select((k, n) => new KeyValuePair<double, double>(n * T, k)).ToArray()) { Name = S.Output.ElementAt(j).ToString() })); return samples / time; }
public double Run(Circuit.Circuit C, Func<double, double> Vin, Expression Input, IEnumerable<Expression> Plots) { long a = Timer.Counter; Analysis analysis = C.Analyze(); TransientSolution TS = TransientSolution.Solve(analysis, (Real)1 / (SampleRate * Oversample), Log); analysisTime += Timer.Delta(a); Simulation S = new Simulation(TS) { Oversample = Oversample, Iterations = Iterations, Log = Log, Input = new[] { Input }, Output = Plots, }; Log.WriteLine(""); if (Samples > 0) return RunTest( C, S, Vin, Samples, C.Name); else return 0.0; }