protected static void Calculate(List <Node> nodosnorton) { if (nodosnorton.Count == 0) { return; } //existen nodos donde la tension se puede calcular directamente List <Node> nodosCalculables = new List <Node>(); foreach (var nodo in nodosnorton) { if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode) { nodosCalculables.Add(nodo); } } foreach (var nodo in nodosCalculables) { nodosnorton.Remove(nodo); } //remuevo esos nodos de los que deben calcularse matricialmente if (nodosnorton.Count > 0) { int fila = 0, columna = 0; var v = Vector <Complex32> .Build.Dense(nodosnorton.Count); var A = Matrix <Complex32> .Build.DenseOfArray(new Complex32[nodosnorton.Count, nodosnorton.Count]); foreach (var nodo in nodosnorton) { columna = fila = nodosnorton.IndexOf(nodo); Complex32 Z, V; if (nodo.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo.TypeOfNode == Node.NodeType.InternalBranchNode) { foreach (var rama in nodo.Components) { if (rama is Branch || rama is PasiveComponent) { columna = fila = nodosnorton.IndexOf(nodo); if (rama is Branch) { V = ((Branch)rama).NortonCurrent(nodo); } else { V = rama.Current(nodo); } v[fila] += V; Z = rama.Impedance(); A[fila, columna] += 1 / Z; Node nodo2 = rama.OtherNode(nodo); if (!nodo2.IsReference) { columna = nodosnorton.IndexOf(nodo2); A[fila, columna] -= 1 / Z; } } else if (rama is CurrentGenerator) { V = rama.Current(nodo); v[fila] += V; } } } else if (nodo.TypeOfNode == Node.NodeType.VoltageLinkedNode) { Dipole compo = nodo.Components[0]; if (!(compo is VoltageGenerator)) { compo = nodo.Components[1]; } v[fila] = compo.Voltage.Real; A[fila, columna] = 1; columna = nodosnorton.IndexOf(compo.OtherNode(nodo)); A[fila, columna] = -1; } else { throw new NotImplementedException(); } } var x = A.Solve(v); foreach (var nodo in nodosnorton) { fila = nodosnorton.IndexOf(nodo); nodo.Voltage = x[fila]; } } foreach (var nodo in nodosCalculables) { if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode) { Node nodo1 = nodo; Dipole compo1 = nodo.Components[0]; Branch br = compo1.Owner as Branch; if (br == null) { throw new Exception(); } Complex32 v1, v2, z1, z2; v1 = v2 = z1 = z2 = Complex32.Zero; //el nodo es interno en una rama, deberian los 2 componentes conectados //al nodo, Dipole compo2 = nodo.Components[1]; //hacia la izq (o derec) NavigateBranch(nodo1, compo1, ref v1, ref z1); //hacia el otro lado NavigateBranch(nodo1, compo2, ref v2, ref z2); nodo.Voltage = (z2 * v1 + v2 * z1) / (z1 + z2); //nodosCalculables.Add(nodo); } } //return x; }
protected static void Calculate(SolveInfo solveinfo, Complex32 W) { if (solveinfo.nortonnodes.Count == 0 && solveinfo.calculablenodes.Count == 0) { return; } //existen nodos donde la tension se puede calcular directamente foreach (var nodo in solveinfo.calculablenodes) { if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode) { foreach (var compo in nodo.Components) { if (compo.IsConnectedToEarth && (compo is ACVoltageGenerator)) { nodo.Voltage = compo.voltage(nodo, W); //el componente conectado a tierra debe ser Vdc o Vsin o capacitor break; } } continue; } } #region Calculo de tensions mediante matrices if (solveinfo.nortonnodes.Count > 0) { int fila = 0, columna = 0, max; //cada componente especial agrega 0, 1 o 2 variable mas, dependiendo del tipo max = solveinfo.MatrixDimension; var v = Vector <Complex32> .Build.Dense(max); var A = Matrix <Complex32> .Build.DenseOfArray(new Complex32[max, max]); //primero la ecuacion de transferencia del VcV foreach (var info in solveinfo.specialcomponents) { //foreach (var item in info.Component) //{ //} //int entrada = especialcomponents.IndexOf(info); //fila = nodosnorton.Count - 1 + entrada; columna = 1; A[fila, columna] = 1; } foreach (var nodo in solveinfo.nortonnodes) { columna = fila = solveinfo.nortonnodes.IndexOf(nodo); Complex32 Z, V; if ( nodo.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo.TypeOfNode == Node.NodeType.VoltageFixedNode || nodo.TypeOfNode == Node.NodeType.InternalBranchNode) { foreach (var rama in nodo.Components) { if (rama is Branch || rama is PasiveComponent) { columna = fila = solveinfo.nortonnodes.IndexOf(nodo); if (rama is Branch) { V = ((Branch)rama).NortonCurrent(nodo, W); } else { V = rama.Current(nodo, W); } v[fila] += V; Z = rama.Impedance(W); A[fila, columna] += 1 / Z; Node nodo2 = rama.OtherNode(nodo); if (!nodo2.IsReference) { columna = solveinfo.nortonnodes.IndexOf(nodo2); A[fila, columna] -= 1 / Z; } } else if (rama is CurrentGenerator) { V = rama.Current(nodo, W); v[fila] += V; } else if (rama is VoltageControlledGenerator) { //int entrada = especialcomponents.Values.ToList().IndexOf(rama); //columna = nodosnorton.Count -1 + entrada; ////un nodo es positva la corriente, en el otro es negativa //if (entrada % 2 == 0) // A[fila, columna] = 1; //else // A[fila, columna] = -1; } } } else if (nodo.TypeOfNode == Node.NodeType.VoltageLinkedNode) { Dipole compo = nodo.Components[0]; if (!(compo is VoltageGenerator)) { compo = nodo.Components[1]; } v[fila] = compo.Voltage.Real; A[fila, columna] = 1; columna = solveinfo.nortonnodes.IndexOf(compo.OtherNode(nodo)); A[fila, columna] = -1; } //else if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode) //{ // foreach (var rama in nodo.Components) // { // if (rama is VoltageControlledGenerator) // { // } // } //} else { throw new NotImplementedException(); } } var x = A.Solve(v); foreach (var nodo in solveinfo.nortonnodes) { fila = solveinfo.nortonnodes.IndexOf(nodo); nodo.Voltage = x[fila]; } } #endregion //existen nodos donde la tension se puede calcular indirectamente foreach (var nodo in solveinfo.calculablenodes) { if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode) { Node nodo1 = nodo; Dipole compo1 = nodo.Components[0]; Branch br = compo1.Owner as Branch; if (br == null) { throw new Exception(); } Complex32 v1, v2, z1, z2; v1 = v2 = z1 = z2 = Complex32.Zero; //el nodo es interno en una rama, deberian los 2 componentes conectados //al nodo, Dipole compo2 = nodo.Components[1]; //hacia la izq (o derec) NavigateBranch(nodo1, compo1, W, ref v1, ref z1); //hacia el otro lado NavigateBranch(nodo1, compo2, W, ref v2, ref z2); nodo.Voltage = (z2 * v1 + v2 * z1) / (z1 + z2); } } }
protected static Branch FindBranch(Circuit cir, Node initialNode, Dipole Component) { Branch br = new Branch(cir); Dipole compo = Component; Node nodo = Component.OtherNode(initialNode); br.Nodes.Clear(); //solo es valido si el circuito fue optimizado, y los paralelos //se reemplazaron por bloques paralelo while (nodo.Components.Count == 2 && cir.Reference != nodo) { br.Components.Add(compo); br.InternalNodes.Add(nodo); compo = nodo.OtherComponent(compo); nodo = compo.OtherNode(nodo); } br.Components.Add(compo); if (br.Components.Count > 1) { initialNode.Components.Remove(Component); initialNode.Components.Add(br); nodo.Components.Remove(compo); nodo.Components.Add(br); nodo.TypeOfNode = Node.NodeType.MultibranchCurrentNode; } br.Nodes.Add(initialNode); br.Nodes.Add(nodo); //hay que recorrer la rama para buscar los nodos intermedios flotantes //y aquellos dependientes de los flotantes nodo = compo.OtherNode(nodo); while (nodo != initialNode) { if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode) { // nothing, node was calculated } else if (compo is VoltageGenerator) { if (nodo.TypeOfNode == Node.NodeType.Unknow) { nodo.TypeOfNode = Node.NodeType.VoltageLinkedNode; } else { throw new NotImplementedException(); } } else if (compo is PasiveComponent) { if (nodo.TypeOfNode == Node.NodeType.Unknow) { nodo.TypeOfNode = Node.NodeType.VoltageDivideNode; } else { throw new NotImplementedException(); } } else { if (nodo.TypeOfNode == Node.NodeType.Unknow) { nodo.TypeOfNode = Node.NodeType.InternalBranchNode; } else { throw new NotImplementedException(); } } compo = nodo.OtherComponent(compo); nodo = compo.OtherNode(nodo); } return(br); }
protected static void Calculate(SolveInfo solveinfo, double t) { if (solveinfo.nortonnodes.Count == 0 && solveinfo.calculablenodes.Count == 0) { return; } //tensiones que se calculan directamente foreach (var nodo in solveinfo.calculablenodes) { if (nodo.TypeOfNode == Node.NodeType.VoltageFixedNode) { foreach (var compo in nodo.Components) { if (compo.IsConnectedToEarth && (compo is VoltageGenerator || compo is Capacitor)) { nodo.Voltage = new Complex32((float)compo.voltage(nodo, t), 0); //el componente conectado a tierra debe ser Vdc o Vsin o capacitor break; } } continue; } } #region Tensiones de nodos que se calculan mediante matriz if (solveinfo.nortonnodes.Count > 0) { int fila = 0, columna = 0; var Currs = Vector <double> .Build.Dense(solveinfo.MatrixDimension); var A = Matrix <double> .Build.DenseOfArray(new double[solveinfo.MatrixDimension, solveinfo.MatrixDimension]); foreach (var nodo in solveinfo.nortonnodes) { columna = fila = solveinfo.nortonnodes.IndexOf(nodo); double Z, I; if (nodo.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo.TypeOfNode == Node.NodeType.InternalBranchNode) { foreach (var rama in nodo.Components) { if (rama is Branch || rama is Resistor) { columna = fila = solveinfo.nortonnodes.IndexOf(nodo); if (rama is Branch) { I = ((Branch)rama).NortonCurrent(nodo, t); } else { I = rama.Current(nodo, t); } Currs[fila] += I; Z = rama.Impedance().Real; A[fila, columna] += 1 / Z; Node nodo2 = rama.OtherNode(nodo); if (!nodo2.IsReference && solveinfo.nortonnodes.Contains(nodo2)) { columna = solveinfo.nortonnodes.IndexOf(nodo2); A[fila, columna] -= 1 / Z; } } else if (rama is CurrentGenerator || rama is Inductor) { I = rama.Current(nodo, t); Currs[fila] += I; } } } else if (nodo.TypeOfNode == Node.NodeType.VoltageLinkedNode) { Dipole compo = nodo.Components[0]; if (!(compo is VoltageGenerator || compo is Capacitor)) { compo = nodo.Components[1]; } Currs[fila] = compo.voltage(nodo, t); A[fila, columna] = 1; columna = solveinfo.nortonnodes.IndexOf(compo.OtherNode(nodo)); A[fila, columna] = -1; } else { throw new NotImplementedException(); } } var x = A.Solve(Currs); foreach (var nodo in solveinfo.nortonnodes) { fila = solveinfo.nortonnodes.IndexOf(nodo); nodo.Voltage = new Complex32((float)x[fila], 0); } } #endregion //existen nodos donde la tension se puede calcular casi directamente foreach (var nodo in solveinfo.calculablenodes) { if (nodo.TypeOfNode == Node.NodeType.VoltageDivideNode) { Node nodo1 = nodo; Dipole compo1 = nodo.Components[0]; Branch br = compo1.Owner as Branch; if (br == null) { throw new Exception(); } double v1, v2, z1, z2; v1 = v2 = z1 = z2 = 0; //el nodo es interno en una rama, deberian los 2 componentes conectados //al nodo, Dipole compo2 = nodo.Components[1]; //hacia la izq (o derec) NavigateBranch(nodo1, compo1, t, ref v1, ref z1); //hacia el otro lado NavigateBranch(nodo1, compo2, t, ref v2, ref z2); nodo.Voltage = new Complex32((float)((z2 * v1 + v2 * z1) / (z1 + z2)), 0); } } //parto del extremo de la rama foreach (var rama in solveinfo.ramas) { Node nodo1 = null; //busco nodos ya calculados en la rama foreach (var nodo in rama.InternalNodes) { if (!solveinfo.calculablenodes.Contains(nodo) && !solveinfo.nortonnodes.Contains(nodo)) { nodo1 = nodo; break; } } if (nodo1 == null) { continue; } double i = 0; //encuentro la corriente impuesta de la rama si es que la hay //nodo1 = rama.Nodes[0]; i = rama.Current(nodo1, t); Dipole compo1 = null; foreach (var compo in rama.Components) { //busco el componente hubicado en un extremo de la rama if (compo.Nodes[0] == nodo1 || compo.Nodes[1] == nodo1) { compo1 = compo; break; } } Node nodo2 = compo1.OtherNode(nodo1); if (compo1 is VoltageGenerator) { //nodo de tension vinculada nodo1.Voltage = nodo2.Voltage + new Complex32((float)compo1.voltage(nodo2, t), 0); } else if (compo1 is Resistor) { //nodo interno, pero conocemos la corriente nodo1.Voltage = nodo2.Voltage - new Complex32((float)i * compo1.Impedance().Real, 0); } else { throw new NotImplementedException(); } //if (nodo.TypeOfNode == Node.NodeType.InternalBranchNode) //{ //} } }