/// <summary> /// Converts every state to a waveform. Waveforms built have <paramref name="pointsCount"/> points and time increment of /// <paramref name="timeStep"/>. /// </summary> /// <returns></returns> /// <param name="pointsCount"></param> /// <param name="timeStep"></param> public WaveformPartialState ToWaveform(int pointsCount, double timeStep) { // Create state for result var result = new WaveformPartialState(_NodeIndices, _ActiveComponentsIndices, States.Keys); // For each state foreach (var state in States) { // Use its method to convert to a waveform result.States[state.Key] = States[state.Key].ToWaveform(pointsCount, timeStep); } return(result); }
/// <summary> /// Topmost logic behind AC Full Cycle - calling it will result in simulation being performed and saved to /// <see cref="ISimulationResultsProvider"/>. This version adjusts <see cref="IOpAmp"/> operation for every calculated point so that neither /// <see cref="IOpAmp"/> exceeds its supply voltages. /// </summary> /// <param name="factory"></param> /// <param name="includeDCBias">If true DC bias will be performed and added to results, if false only saturated <see cref="IOpAmp"/>s /// will be considered for DC part of simulation</param> private void FullCycleLogicWithOpAmpAdjustment(AdmittanceMatrixFactory factory, bool includeDCBias) { // TODO: Try to make it so that saturated op amp bias is not considered to be pure DC but rather an extension of all sources // contributing to the circuit // TODO: number of points should be given by caller int pointsCount = 600; // Time step between two subsequent points in time vector double timeStep = GetTimeStep(pointsCount, factory.LowestFrequency); // Create an enumeration of used sources - take AC sources and op-amp saturation source. If DC bias is requested, add the DC sources too. var usedSources = (includeDCBias ? factory.AllSources : factory.ACSources).Concat(factory.OpAmpSaturationSource); // Get node indices constructed on the basis of the circuit var nodeIndices = factory.Nodes.ToList(); // Create a state which will be filled with adjusted simulation points var adjustedState = new WaveformPartialState(factory.NodesCount, factory.ActiveComponentsCount, usedSources); // Go through each simulation point separately - it is necessary in order to correctly determine op-amp operation at each specific point for (int i = 0; i < pointsCount; ++i) { // Use the helper to obtain instantenous potentials var instantenousValues = FullCycleInstantenousValuesHelper(factory, i, timeStep, includeDCBias); // Loop until correct op-amp operation is found while (!factory.CheckOpAmpOperationWithSelfAdjustment(instantenousValues.Combine().Potentials)) { // If the op-amp operation was adjusted, recalculate the instantenous values instantenousValues = FullCycleInstantenousValuesHelper(factory, i, timeStep, includeDCBias); } // For each state foreach (var state in instantenousValues.States.Values) { // And for each node foreach (var index in nodeIndices) { // Add the calculated potential for state at node 'index' to the adjusted result waveform. // Lists are empty - points should just be added to them to form a full waveform. adjustedState.States[state.SourceDescription].Potentials[index].Add( instantenousValues.States[state.SourceDescription].Potentials[index]); } // Add the instantenous values of active components currents to the waveforms - just like currents foreach (var index in factory.ActiveComponents) { adjustedState.States[state.SourceDescription].Currents[index].Add( instantenousValues.States[state.SourceDescription].Currents[index]); } } // Finally reset the op-amp operation for next iteration factory.ResetOpAmpOperation(); } // Create simulation results IoC.Resolve <SimulationResultsProvider>().Value = new SimulationResultsTime( // Convert the adjusted state to potentials - specify that reference node should be added adjustedState.PotentialsToTimeDomainSignals(timeStep, true), adjustedState.CurrentsToTimeDomainSignals(timeStep), timeStep, 0); }