/// <summary> /// Adds a new waveform to the signal, updates <see cref="FinalWaveform"/> /// </summary> /// <param name="description">Positive value</param> /// <param name="values"></param> protected void AddWaveformHelper(ISourceDescription description, IEnumerable <double> values) { // Null check if (description == null || values == null) { throw new ArgumentNullException(); } // Check if number of samples in the waveform matches this time domain signal if (values.Count() != Samples) { throw new ArgumentException(nameof(values) + $" must have count equal to {Samples} ({nameof(Samples)})"); } // If the source description is already present in the collection if (_Waveforms.ContainsKey(description)) { // Add the new values to those already present _Waveforms[description] = _Waveforms[description].MergeSelect(values, (x, y) => x + y); } else { // Otherwise make a new entry _Waveforms.Add(description, values); } // And finally add values to the final waveform values.ForEach((x, i) => _FinalWaveform[i] += x); }
/// <summary> /// Constructor with parameters /// </summary> /// <param name="nodeIndices">Nodes present in this instance</param> /// <param name="activeComponentsIndices">Active components indices present in this instance</param> /// <param name="defaultValueFactory">Func used for generating initial values in <see cref="Potentials"/> and <see cref="Currents"/>, /// if null (which is the default value) <see cref="default(T)"/> will be used</param> /// <param name="sourceDescription">Description of source that produced this state. Can be null - it means that it's indetermined or /// many sources produced this state</param> public GenericState(IEnumerable <int> nodeIndices, IEnumerable <int> activeComponentsIndices, ISourceDescription sourceDescription, Func <T> defaultValueFactory = null) { // Null checks if (nodeIndices == null) { throw new ArgumentNullException(nameof(nodeIndices)); } if (activeComponentsIndices == null) { throw new ArgumentNullException(nameof(activeComponentsIndices)); } // Make an entry for each node foreach (var node in nodeIndices) { Potentials.Add(node, defaultValueFactory == null ? default(T) : defaultValueFactory()); } // Make an entry for each index foreach (var index in activeComponentsIndices) { Currents.Add(index, defaultValueFactory == null ? default(T) : defaultValueFactory()); } // Assign source description SourceDescription = sourceDescription; }
/// <summary> /// Configures the <paramref name="source"/> for desired <paramref name="state"/>. /// Outputs is set to 1 in order to generate transfer functions. /// </summary> /// <param name="sourceIndex"></param> /// <param name="state">True if the source is active, false if not (it is considered as short-circuit)</param> private void ConfigureVoltageSource(AdmittanceMatrix matrix, ISourceDescription source, bool state) { // Get the voltage source's nodes var nodes = _SourcesNodes[source]; // And its index var sourceIndex = _IndexedComponentsIndices[source]; // If the positive terminal is not grounded if (nodes.Positive != ReferenceNode) { // Fill the entry in the row corresponding to the node and column corresponding to the source (plus start column) // with 1 (positive terminal) matrix._B[nodes.Positive, sourceIndex] = 1; // Fill the entry in the row corresponding to the source (plus starting row) // and column corresponding to the node with 1 (positive terminal) matrix._C[sourceIndex, nodes.Positive] = 1; } // If the negative terminal is not grounded if (nodes.Negative != ReferenceNode) { // Fill the entry in the row corresponding to the node and column corresponding to the source (plus start column) // with -1 (negative terminal) matrix._B[nodes.Negative, sourceIndex] = -1; // Fill the entry in the row corresponding to the source (plus starting row) // and column corresponding to the node with -1 (negative terminal) matrix._C[sourceIndex, nodes.Negative] = -1; } matrix._E[sourceIndex] = state ? source.OutputValue : 0; }
/// <summary> /// Activates (all current sources are not active by default) the current source given by the index. /// </summary> /// <param name="sourceIndex"></param> private void ActivateCurrentSource(AdmittanceMatrix matrix, ISourceDescription source) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // Matrix I has += and -= instead of just assignment because that's the actual correct way of building the matrix. // // However it only matters if there is more than one source active at a time. For example, if there would be 2 sources, each connected // // to the same node, then the value in the corresponding entry in I matrix should be a sum of produced currents. Simply assigning value // // would result in an error. Again, for now, admittance matrices are built only for one source, however if it would happen that it changes // // in the future then there won't be any errors because of assigning rather than adding / subtracting. // // // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Get the nodes var nodes = _SourcesNodes[source]; // If the positive terminal is not grounded if (nodes.Positive != ReferenceNode) { // Add source's current to the node matrix._I[nodes.Positive] += source.OutputValue; } // If the negative terminal is not grounded if (nodes.Negative != -1) { // Subtract source's current from the node matrix._I[nodes.Negative] -= source.OutputValue; } }
/// <summary> /// Returns an admittance matrix for current source given by <paramref name="source"/>. /// </summary> /// <returns></returns> private AdmittanceMatrix ConstructForCurrentSource(ISourceDescription source) { // Create initialized matrix var matrix = ConstructAndInitialize(source.Frequency); // Turn on the current source ActivateCurrentSource(matrix, source); return(matrix); }
/// <summary> /// Returns an admittance matrix for voltage source given by <paramref name="source"/>. /// </summary> /// <param name="source"></param> /// <returns></returns> private AdmittanceMatrix ConstructForVoltageSource(ISourceDescription source) { // Create initialized matrix var matrix = ConstructAndInitialize(source.Frequency); // Turn on the voltage source ConfigureVoltageSource(matrix, source, true); return(matrix); }
/// <summary> /// Adds <paramref name="value"/> to this <see cref="PhasorDomainSignal"/>. Either creates a new entry or adds the <paramref name="value"/> /// to the entry already existing for <paramref name="source"/>. /// </summary> /// <param name="source"></param> /// <param name="value"></param> protected void AddPhasorHelper(ISourceDescription source, Complex value) { // If source is already present in the dictionary if (_Phasors.ContainsKey(source)) { // Add the value to the stored value _Phasors[source] += value; } else { // Otherwise create a new entry _Phasors.Add(source, value); } }
/// <summary> /// Returns phasors constructed for source given by <paramref name="sourceDescription"/> /// </summary> /// <param name="factory"></param> /// <param name="sourceDescription"></param> private PhasorState GetPhasor(AdmittanceMatrixFactory factory, ISourceDescription sourceDescription) { var state = new PhasorState(factory.NodesCount, factory.ActiveComponentsCount, sourceDescription); // Create an admittance matrix corresponding to the given source factory.Construct(sourceDescription). // And solve it Solve(out var nodePotentials, out var activeComponentsCurrents); // Add the results to state state.AddValues(nodePotentials, activeComponentsCurrents); return(state); }
/// <summary> /// Constructrs an admittance matrix for the given source. /// </summary> /// <param name="source"></param> /// <returns></returns> public AdmittanceMatrix Construct(ISourceDescription source) { switch (source.SourceType) { case SourceType.ACVoltageSource: case SourceType.DCVoltageSource: { return(ConstructForVoltageSource(source)); } case SourceType.DCCurrentSource: { return(ConstructForCurrentSource(source)); } default: { throw new Exception($"Unhandled {nameof(SourceType)}"); } } }
/// <summary> /// Constructor with parameters /// </summary> /// <param name="nodeIndices">Nodes present in this instance</param> /// <param name="activeComponentsCount">Number of active components, indices available in this instance will be given by a /// range: 0 to <paramref name="activeComponentsCount"/> - 1</param> /// <param name="defaultValueFactory">Func used for generating initial values in <see cref="Potentials"/> and <see cref="Currents"/>, /// if null (which is the default value) <see cref="default(T)"/> will be used</param> /// <param name="sourceDescription">Description of source that produced this state. Can be null - it means that it's indetermined or /// many sources produced this state</param> public GenericState(IEnumerable <int> nodeIndices, int activeComponentsCount, ISourceDescription sourceDescription, Func <T> defaultValueFactory = null) : this(nodeIndices, Enumerable.Range(0, activeComponentsCount), sourceDescription, defaultValueFactory) { }
/// <summary> /// Adds a new waveform to the signal. If one already exists for source described by <paramref name="description"/>, adds them together, /// otherwise makes a new entry in <see cref="ITimeDomainSignal.ACWaveforms"/> or <see cref="ITimeDomainSignal.DCWaveforms"/> /// </summary> /// <param name="description"></param> /// <param name="value"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> public void AddWaveform(ISourceDescription description, IEnumerable <double> values) => AddWaveformHelper(description, values);
/// <summary> /// Used to add <see cref="KeyValuePair{TKey, TValue}"/> to <see cref="INodePotentialBias.Phasors"/> /// </summary> /// <param name="source"></param> /// <param name="value"></param> public void AddPhasor(ISourceDescription source, Complex value) => AddPhasorHelper(source, value);
/// <summary> /// Constructor with parameters /// </summary> /// <param name="nodeIndices">Nodes present in this instance</param> /// <param name="activeComponentsCount">Number of active components, indices available in this instance will be given by a /// range: 0 to <paramref name="activeComponentsCount"/> - 1</param> /// <param name="sourceDescription">Description of source that produced this state. Can be null - it means that it's indetermined or /// many sources produced this state</param> public InstantenousState(IEnumerable <int> nodeIndices, int activeComponentsCount, ISourceDescription sourceDescription) : this(nodeIndices, Enumerable.Range(0, activeComponentsCount), sourceDescription) { }
/// <summary> /// Constructor with parameters /// </summary> /// <param name="nodeIndices">Nodes present in this instance</param> /// <param name="activeComponentsIndices">Active components indices present in this instance</param> /// <param name="sourceDescription">Description of source that produced this state. Can be null - it means that it's indetermined or /// many sources produced this state</param> public InstantenousState(IEnumerable <int> nodeIndices, IEnumerable <int> activeComponentsIndices, ISourceDescription sourceDescription) : base(nodeIndices, activeComponentsIndices, sourceDescription) { }
/// <summary> /// Constructor with parameters /// </summary> /// <param name="nodesCount">Number of nodes, indicies available in this instance will be given by a range: /// 0 to <paramref name="nodesCount"/></param> /// <param name="activeComponentsCount">Number of active components, indices available in this instance will be given by a /// range: 0 to <paramref name="activeComponentsCount"/> - 1</param> /// <param name="sourceDescription">Description of source that produced this state. Can be null - it means that it's indetermined or /// many sources produced this state</param> public PhasorState(int nodesCount, int activeComponentsCount, ISourceDescription sourceDescription) : this(Enumerable.Range(0, nodesCount), Enumerable.Range(0, activeComponentsCount), sourceDescription) { }
/// <summary> /// Adds a new waveform to the signal. If one already exists for source described by <paramref name="description"/>, adds them together, /// otherwise makes a new entry in <see cref="ITimeDomainSignal.ACWaveforms"/>. or <see cref="ITimeDomainSignal.DCWaveforms"/>. /// The waveform is given by a constant value - full /// waveform will be constructed from it. /// </summary> /// <param name="description"></param> /// <param name="value"></param> /// <exception cref="ArgumentNullException"></exception> public void AddWaveform(ISourceDescription description, double value) => AddWaveform(description, WaveformBuilder.ConstantWaveform(value, Samples));
/// <summary> /// Constructor with parameters /// </summary> /// <param name="nodeIndices">Nodes present in this instance</param> /// <param name="activeComponentsIndices">Active components indices present in this instance</param> /// <param name="sourceDescription">Description of source that produced this state. Can be null - it means that it's indetermined or /// many sources produced this state</param> public WaveformState(IEnumerable <int> nodeIndices, IEnumerable <int> activeComponentsIndices, ISourceDescription sourceDescription) : base(nodeIndices, activeComponentsIndices, sourceDescription, () => new List <double>()) { }