예제 #1
0
        /// <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;
        }
예제 #2
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;
            }
        }
예제 #3
0
        /// <summary>
        /// Configures submatrices so that <paramref name="opAmp"/> is considered to work in saturation, however output remains at 0 - op-amps have
        /// to be manually activated, for example using <see cref="ActivateSaturatedOpAmp(AdmittanceMatrix, IOpAmpDescription)"/>.
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="opAmp"></param>
        private void ConfigureOpAmpForSaturation(AdmittanceMatrix matrix, IOpAmpDescription opAmp)
        {
            // Indices of op-amps nodes
            var nodes = _OpAmpsNodes[opAmp];

            // And its index
            var index = _IndexedComponentsIndices[opAmp];

            // If the non-inverting input is not grounded, reset its entry in the _C matrix
            if (nodes.NonInvertingInput != ReferenceNode)
            {
                matrix._C[index, nodes.NonInvertingInput] = 0;
            }

            // If the inverting input is not grounded, reset its entry in the _C matrix
            if (nodes.InvertingInput != ReferenceNode)
            {
                matrix._C[index, nodes.InvertingInput] = 0;
            }

            // And the entry in _C corresponding to the output node to 1
            // It is important that, when non-inverting input is connected directly to the output, the entry in _B
            // corresponding to that node is 1 (and not 0 like the if above would set it). Because this assigning is done after
            // the one for non-inverting input no special conditions are necessary however it's very important to remeber about
            // it if (when) this method is modified
            matrix._C[index, nodes.Output] = 1;
        }
예제 #4
0
        /// <summary>
        /// Fills the non-diagonal entries of an admittance matrix - for entry i,j all admittances located between node i and node j are subtracted
        /// from that entry
        /// </summary>
        private void FillAMatrixNonDiagonal(AdmittanceMatrix matrix, double frequency)
        {
            // For each node
            foreach (var node1 in _Nodes)
            {
                // Matrix A is symmetrical along the main diagonal so it's only necessary to fill the
                // part below main diagonal and copy the operation to the corresponding entry above the main diagonal
                foreach (var node2 in _Nodes.FindAll((x) => x.Index < node1.Index))
                {
                    // Find all components located between node i and node j
                    var admittancesBetweenNodesij =
                        new List <IBaseComponent>(node1.ConnectedComponents.Intersect(node2.ConnectedComponents));

                    // For each of them
                    admittancesBetweenNodesij.ForEach((component) =>
                    {
                        // If the component is a two terminal
                        if (component is ITwoTerminal twoTerminal)
                        {
                            // Get the admittance of the element
                            var admittance = twoTerminal.GetAdmittance(frequency);

                            // Subtract its admittance from the matrix
                            matrix._A[node1.Index, node2.Index] -= admittance;

                            // And do the same to the entry j,i - admittances between node i,j are identical to admittances between nodes j,i
                            matrix._A[node2.Index, node1.Index] -= admittance;
                        }
                    });
                }
            }
        }
예제 #5
0
 /// <summary>
 /// Configures all voltage sources for specific operation.
 /// </summary>
 private void ConfigureVoltageSources(AdmittanceMatrix matrix, bool state)
 {
     // Take all voltage sources (DC + AC)
     foreach (var source in _DCVoltageSources.Concat(_ACVoltageSources))
     {
         // And configure them for the state
         ConfigureVoltageSource(matrix, source, state);
     }
 }
예제 #6
0
 /// <summary>
 /// Fills the B part of admittance matrix with 0 or 1 based on op-amps present in the circuit
 /// </summary>
 private void FillBMatrixOpAmpOutputNodes(AdmittanceMatrix matrix)
 {
     // For each op-amp
     foreach (var opAmp in _OpAmps)
     {
         // Set the entry in _B corresponding to the output node to 1
         matrix._B[_OpAmpsNodes[opAmp].Output, _IndexedComponentsIndices[opAmp]] = 1;
     }
 }
예제 #7
0
        /// <summary>
        /// Modifies <paramref name="matrix"/> with initial op-amp settings - op-amps are set in their respective operation modes depending on
        /// <see cref="_OpAmpOperation"/>.
        /// </summary>
        private void InitialOpAmpConfiguration(AdmittanceMatrix matrix)
        {
            FillBMatrixOpAmpOutputNodes(matrix);

            // Configure each op-amp for its operation
            foreach (var opAmp in _OpAmps)
            {
                ConfigureOpAmpOperation(matrix, opAmp, _OpAmpOperation[opAmp]);
            }
        }
예제 #8
0
        /// <summary>
        /// Initializes submatrices of the given <see cref="AdmittanceMatrix"/>
        /// </summary>
        /// <param name="matrix"></param>
        private void InitializeSubmatrices(AdmittanceMatrix matrix)
        {
            matrix._A = ArrayHelpers.CreateAndInitialize(Complex.Zero, _BigDimension, _BigDimension);

            matrix._B = ArrayHelpers.CreateAndInitialize <Complex>(0, _BigDimension, _SmallDimension);
            matrix._C = ArrayHelpers.CreateAndInitialize(Complex.Zero, _SmallDimension, _BigDimension);
            matrix._D = ArrayHelpers.CreateAndInitialize(Complex.Zero, _SmallDimension, _SmallDimension);

            matrix._E = ArrayHelpers.CreateAndInitialize(Complex.Zero, _SmallDimension);
            matrix._I = ArrayHelpers.CreateAndInitialize(Complex.Zero, _BigDimension);
        }
예제 #9
0
 /// <summary>
 /// Activates all saturated op amps
 /// </summary>
 /// <param name="matrix"></param>
 private void ActivateSaturatedOpAmps(AdmittanceMatrix matrix)
 {
     // For each op-amp
     foreach (var opAmp in _OpAmps)
     {
         // If it's in either saturation
         if (_OpAmpOperation[opAmp] == OpAmpOperationMode.PositiveSaturation || _OpAmpOperation[opAmp] == OpAmpOperationMode.NegativeSaturation)
         {
             // Activate it
             ActivateSaturatedOpAmp(matrix, opAmp);
         }
     }
 }
예제 #10
0
        /// <summary>
        /// Configures submatrices so that <paramref name="opAmp"/> is considered to work in active operation (output is between
        /// supply voltages)
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="opAmp"></param>
        private void ConfigureOpAmpForActiveOperation(AdmittanceMatrix matrix, IOpAmpDescription opAmp)
        {
            // Get nodes of the op-amp
            var nodes = _OpAmpsNodes[opAmp];

            // As well as its index
            var index = _IndexedComponentsIndices[opAmp];

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //																													 //
            // Very important: in case the non-inverting input and output are short-circuited (they are the same node) then		 //
            // the value of 1 should be entered into the corresponding cell in _C array. This comes from the fact that having	 //
            // -OpenLoopGain and OpenLoogGain in the _C in the same row enforces potentials at both inputs to be equal. However  //
            // if the non-inverting input is shorted then the OpenLoopGain value has no place in _C and 1 from the output should //
            // be put there.																									 //
            // If the inverting input is shorted with the output then the OpenLoopGain should be put int the corresponding cell  //
            // instead of 1. That's because the initial assumption that V+ = V- is made and if Vout = V- (the same node) then	 //
            // The OpenLoopGain has to be used to guarantee both voltages will be equal											 //
            // (so matrix looks like : ... -k ... k ... | 0 which boils down to kV- = kV+ which means V- = V+)					 //
            // That's why it is very important that if (when) this method is modified the rules presented above are obeyed.		 //
            //																													 //
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            // If there exists a node to which TerminalA (non-inverting input) is connected
            // (it's possible it may not exist due to removed ground node)
            if (nodes.NonInvertingInput != ReferenceNode)
            {
                // Fill the entry in the row corresponding to the op-amp (plus starting row)
                // and column corresponding to the node (positive terminal) with -OpenLoopGain
                matrix._C[index, nodes.NonInvertingInput] = -opAmp.OpenLoopGain;
            }

            // If there exists a node to which TerminalB (inverting input) is connected
            // (it's possible it may not exist due to removed ground node)
            if (nodes.InvertingInput != ReferenceNode)
            {
                // Fill the entry in the row corresponding to the op-amp (plus starting row)
                // and column corresponding to the node (positive terminal) with OpenLoopGain
                matrix._C[index, nodes.InvertingInput] = opAmp.OpenLoopGain;
            }

            // If the output is not shorted with the inverting input
            if (nodes.Output != nodes.InvertingInput)
            {
                matrix._C[index, nodes.Output] = 1;
            }

            // Fill the entry in the row corresponding to the op-amp (plus starting row)
            // and column corresponding to the node (positive terminal) with 1
            matrix._E[index] = 0;
        }
예제 #11
0
 /// <summary>
 /// Fills the diagonal of an admittance matrix - for i-th node adds all admittances connected to it, to the cell denoted by indices i,i
 /// </summary>
 private void FillAMatrixDiagonal(AdmittanceMatrix matrix, double frequency)
 {
     // For each node
     foreach (var node in _Nodes)
     {
         // For each component connected to that node
         node.ConnectedComponents.ForEach((component) =>
         {
             // If the component is a two terminal
             if (component is ITwoTerminal twoTerminal)
             {
                 // Add its admittance to the matrix
                 matrix._A[node.Index, node.Index] += twoTerminal.GetAdmittance(frequency);
             }
         });
     }
 }
예제 #12
0
        /// <summary>
        /// Constructs and initializes the general version (without any source in mind) of admittance matrix
        /// </summary>
        /// <param name="frequency"></param>
        /// <returns></returns>
        private AdmittanceMatrix ConstructAndInitialize(double frequency)
        {
            // TODO: Short circuit inductors for DC when they're added

            var matrix = new AdmittanceMatrix(_BigDimension, _SmallDimension);

            // Initialize submatrices (arrays)
            InitializeSubmatrices(matrix);

            // Fill A matrix - it's only dependent on frequency
            FillAMatrix(matrix, frequency);

            // Configure voltage sources to be off - the only active voltage source (if any) can then be turned on
            ConfigureVoltageSources(matrix, false);

            // Initialize op-amp settings - disabled saturated op-amps
            InitialOpAmpConfiguration(matrix);

            return(matrix);
        }
예제 #13
0
        /// <summary>
        /// Configures <see cref="IOpAmp"/> for operation in <paramref name="operationMode"/> in <paramref name="matrix"/>. Saturated op-amps remain
        /// inactive after this call - they will appear to be saturated but saturation voltage will be equal to 0. Op-amps have to be manually
        /// activated, for example using <see cref="ActivateSaturatedOpAmps(AdmittanceMatrix)"/>
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="opAmpIndex"></param>
        /// <param name="operationMode"></param>
        private void ConfigureOpAmpOperation(AdmittanceMatrix matrix, IOpAmpDescription opAmp, OpAmpOperationMode operationMode)
        {
            // Call appropriate method based on operation mode
            switch (_OpAmpOperation[opAmp])
            {
            case OpAmpOperationMode.Active:
            {
                ConfigureOpAmpForActiveOperation(matrix, opAmp);
            }
            break;

            case OpAmpOperationMode.PositiveSaturation:
            case OpAmpOperationMode.NegativeSaturation:
            {
                ConfigureOpAmpForSaturation(matrix, opAmp);
            }
            break;

            default:
            {
                throw new Exception("Unhandled case");
            }
            }
        }
예제 #14
0
 /// <summary>
 /// Activates saturated op-amp - modifies matrix E with saturation voltage in entry corresponding to that op-amp. Does not check if
 /// the op-amp is in fact saturated - assumes that caller checked that.
 /// </summary>
 /// <param name="matrix"></param>
 /// <param name="opAmp"></param>
 private void ActivateSaturatedOpAmp(AdmittanceMatrix matrix, IOpAmpDescription opAmp) =>
 // Depending on which supply was exceeded, set the value of the op-amp output to either positive or negative
 // supply voltage, depending on saturaiton (if determined that it is in either saturation).
 // Modify entry in E matrix corresponding to index of the op-amp.
 matrix._E[_IndexedComponentsIndices[opAmp]] = _OpAmpOperation[opAmp] == OpAmpOperationMode.PositiveSaturation ?
                                               opAmp.PositiveSupplyVoltage : opAmp.NegativeSupplyVoltage;
예제 #15
0
        /// <summary>
        /// Fills the <see cref="_A"/> Matrix
        /// </summary>
        private void FillAMatrix(AdmittanceMatrix matrix, double frequency)
        {
            FillAMatrixDiagonal(matrix, frequency);

            FillAMatrixNonDiagonal(matrix, frequency);
        }