/// <summary> /// Dado un supernodo, recorre todas sus ramas para hallar la corriente en una de ellas /// </summary> /// <param name="nodo"></param> /// <param name="W"></param> /// <returns></returns> private static double CalculateSupernodeCurrent(Node nodo, Dipole comp, double t) { if (nodo.IsReference) { nodo = comp.OtherNode(nodo); } double i = 0; foreach (var comp2 in nodo.Components) { if (comp2 == comp) { continue; } if (comp2 is VoltageGenerator) { Node nodo1 = comp2.OtherNode(nodo); i += CalculateSupernodeCurrent(nodo1, comp2, t); } else { i += comp2.Current(nodo, t); } } return(i); }
/// <summary> /// Valida una rama y la agrega al circuito si corresponde /// En caso contrario solo agrega el componente indicado /// </summary> /// <param name="yaanalizados"></param> /// <param name="nodosnormales"></param> /// <param name="ramas"></param> /// <param name="nodo"></param> /// <param name="compo"></param> /// <param name="br"></param> protected static void ValidateBranch(List <Dipole> yaanalizados, List <Node> nodosnormales, List <Branch> ramas, Node nodo, Dipole compo, Branch br) { if (br.Components.Count <= 1) { if (compo is PasiveComponent) { Node other = compo.OtherNode(nodo); other.TypeOfNode = Node.NodeType.MultibranchCurrentNode; if (!nodosnormales.Contains(other) && !other.IsReference) { nodosnormales.Add(other); } } yaanalizados.Add(compo); } else { //rama valida ramas.Add(br); Node other = br.OtherNode(nodo); if (!nodosnormales.Contains(other) && !other.IsReference) { nodosnormales.Add(other); } yaanalizados.AddRange(br.Components); foreach (var comp in br.Components) { comp.Owner = br; } } }
/// <summary> /// barre una rama desde un nodo interno hacia la izquierda o derecha /// calculando la suma de las tensiones de generadores V1 /// y la suma de impedancias Z1 /// </summary> /// <param name="nodo"></param> /// <param name="compo1"></param> /// <param name="t"></param> /// <param name="v1"></param> /// <param name="z1"></param> private static void NavigateBranch(Node nodo, Dipole compo1, double t, ref double v1, ref double z1) { Node nodo1 = nodo; while (!(nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo1.IsReference)) { if (compo1 is Resistor) { z1 += compo1.Impedance().Real; } else if (compo1 is VoltageGenerator || compo1 is Capacitor) { v1 += compo1.voltage(nodo1, t); } else { throw new NotImplementedException(); } nodo1 = compo1.OtherNode(nodo1); compo1 = nodo1.OtherComponent(compo1); } if (nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode) { v1 += nodo1.Voltage.Real; } }
/// <summary> /// barre una rama desde un nodo interno hacia la izquierda o derecha /// calculando la suma de las tensiones de generadores V1 /// y la suma de impedancias Z1 /// </summary> /// <param name="nodo"></param> /// <param name="compo1"></param> /// <param name="v1"></param> /// <param name="z1"></param> private static void NavigateBranch(Node nodo, Dipole compo1, ref Complex32 v1, ref Complex32 z1) { Node nodo1 = nodo; while (!(nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode || nodo1.IsReference)) { if (compo1 is PasiveComponent) { z1 += compo1.Impedance(); } else if (compo1 is VoltageGenerator) { v1 += compo1.voltage(nodo1, null); } else { throw new NotImplementedException(); } nodo1 = compo1.OtherNode(nodo1); compo1 = nodo1.OtherComponent(compo1); } if (nodo1.TypeOfNode == Node.NodeType.MultibranchCurrentNode) { v1 += nodo1.Voltage; } }
protected static void AddComponentNodes(Circuit ciroptimizado, Dipole rama) { if (!ciroptimizado.Nodes.ContainsValue(rama.Nodes[0])) { ciroptimizado.Nodes.Add(rama.Nodes[0].Name, rama.Nodes[0]); } if (!ciroptimizado.Nodes.ContainsValue(rama.Nodes[1])) { ciroptimizado.Nodes.Add(rama.Nodes[1].Name, rama.Nodes[1]); } }
/// <summary> /// Dado un supernodo, recorre todas sus ramas para hallar la corriente en una de ellas /// </summary> /// <param name="nodo"></param> /// <param name="W"></param> /// <returns></returns> private static Complex32 CalculateSupernodeCurrent(Node nodo, Complex32 W, Dipole comp) { Complex32 i = Complex32.Zero; foreach (var comp2 in nodo.Components) { if (comp2 == comp) { continue; } if (comp2 is VoltageGenerator) { Node nodo1 = comp2.OtherNode(nodo); i += CalculateSupernodeCurrent(nodo1, W, comp2); } else { i += comp2.Current(nodo, W); } } return(i); }
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 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); }
/// <summary> /// optimize a recent loaded circuit leaving ready for simulation /// </summary> /// <param name="cir"></param> /// <returns></returns> public static bool Optimize(Circuit cir) { List <Dipole> yaanalizados = new List <Dipole>(); List <ParallelBlock> paralelos = new List <ParallelBlock>(); List <Node> nodosnormales = new List <Node>(); List <Branch> ramas = new List <Branch>(); ParallelBlock para = null; #region Chequeo de nodos sueltos o componentes colgantes foreach (var nodo in cir.Nodes.Values) { if (nodo.Components.Count == 0) { throw new NotImplementedException(); } //componente con borne suelto if (nodo.Components.Count == 1) { throw new NotImplementedException(); } } #endregion #region busco componentes en paralelo if (false) { for (int i = 0; i < cir.Components.Count - 1; i++) { if (yaanalizados.Contains(cir.Components[i])) { continue; } Dipole comp1 = cir.Components[i]; for (int j = i + 1; j < cir.Components.Count; j++) { if (yaanalizados.Contains(cir.Components[j])) { continue; } Dipole comp2 = cir.Components[j]; if ((comp1.Nodes[0] == comp2.Nodes[0] && comp1.Nodes[1] == comp2.Nodes[1]) || (comp1.Nodes[0] == comp2.Nodes[1] && comp1.Nodes[1] == comp2.Nodes[0])) { if (para == null) { para = new ParallelBlock(cir, comp1, comp2); paralelos.Add(para); yaanalizados.Add(comp1); yaanalizados.Add(comp2); } else { para.Components.Add(comp2); yaanalizados.Add(comp2); } } } } } #endregion #region reemplazo los componentes paralelos separados por //el correspondiente block paralelo foreach (var para1 in paralelos) { foreach (var compo in para1.Components) { cir.Components.Remove(compo); } cir.Components.Add(para1); } #endregion #region identifico la tierra Node tierra = cir.Reference; if (tierra == null) { foreach (var item in cir.Nodes.Values) { if (item.IsReference) { tierra = item; cir.Reference = tierra; break; } } } #endregion #region arranco desde tierra he identifico los nodos de tension fija, //posibles nodos flotantes de corriente y ramas conectadas a tierra List <Dipole> componenttoearh = new List <Dipole>(); componenttoearh.AddRange(tierra.Components); foreach (var compo in componenttoearh) { foreach (var rama in ramas) { if (rama.Components.Contains(compo)) { goto end; } } //los nodos de tension fija if (compo is VoltageGenerator) { Node other = compo.OtherNode(tierra); other.TypeOfNode = Node.NodeType.VoltageFixedNode; other.Voltage = compo.Voltage; } //desde tierra los nodos son: //a: pertenecen a una rama. hay que levantar dicha rama... //b: son nodos normales flotantes (se aplica teorema de nodo) Branch br = FindBranch(cir, tierra, compo); //si no forma parte de una rama, la rama de 1 elemento se desecha ValidateBranch(yaanalizados, nodosnormales, ramas, tierra, compo, br); } end :; #endregion #region Analizo las ramas faltantes desde los nodos normales encontrados foreach (var nodo in nodosnormales) { foreach (var compo in nodo.Components) { if (ramas.Contains(compo) || yaanalizados.Contains(compo)) { continue; } Branch br = FindBranch(cir, nodo, compo); ValidateBranch(yaanalizados, nodosnormales, ramas, nodo, compo, br); } } #endregion //reemplazo los componentes que arman una rama por la propia rama foreach (var rama in ramas) { foreach (var compo in rama.Components) { cir.Components.Remove(compo); } } cir.Components.AddRange(ramas); //foreach (var rama in ramas) //{ // AddComponentNodes(cir, rama); //} cir.State = Circuit.CircuitState.Optimized; cir.OptimizedCircuit = cir; return(true); }
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); } } }
public SpecialComponentInfo(Dipole comp) { Component = comp; ImportantInputNodes = new List <Node>(); ImportantOutputNodes = new List <Node>(); }
private static void dipole_sample_test() //****************************************************************************80 // // Purpose: // // DIPOLE_SAMPLE_TEST tests DIPOLE_SAMPLE; // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 24 January 2007 // // Author: // // John Burkardt // { const int SAMPLE_NUM = 1000; const int TEST_NUM = 3; int seed = 123456789; double[] test_a = { 0.0, Math.PI / 4.0, Math.PI / 2.0 } ; double[] test_b = { 1.0, 0.5, 0.0 } ; int test_i; double[] x = new double[SAMPLE_NUM]; Console.WriteLine(""); Console.WriteLine("DIPOLE_SAMPLE_TEST"); Console.WriteLine(" DIPOLE_SAMPLE samples the Dipole distribution;"); for (test_i = 0; test_i < TEST_NUM; test_i++) { double a = test_a[test_i]; double b = test_b[test_i]; Console.WriteLine(""); Console.WriteLine(" PDF parameter A = " + a + ""); Console.WriteLine(" PDF parameter B = " + b + ""); if (!Dipole.dipole_check(a, b)) { Console.WriteLine(""); Console.WriteLine("DIPOLE_SAMPLE_TEST - Fatal error!"); Console.WriteLine(" The parameters are not legal."); return; } int i; for (i = 0; i < SAMPLE_NUM; i++) { x[i] = Dipole.dipole_sample(a, b, ref seed); } double mean = typeMethods.r8vec_mean(SAMPLE_NUM, x); double variance = typeMethods.r8vec_variance(SAMPLE_NUM, x); double xmax = typeMethods.r8vec_max(SAMPLE_NUM, x); double xmin = typeMethods.r8vec_min(SAMPLE_NUM, x); Console.WriteLine(""); Console.WriteLine(" Sample size = " + SAMPLE_NUM + ""); Console.WriteLine(" Sample mean = " + mean + ""); Console.WriteLine(" Sample variance = " + variance + ""); Console.WriteLine(" Sample maximum = " + xmax + ""); Console.WriteLine(" Sample minimum = " + xmin + ""); } }
private static void dipole_cdf_test() //****************************************************************************80 // // Purpose: // // DIPOLE_CDF_TEST tests DIPOLE_CDF. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 24 January 2007 // // Author: // // John Burkardt // { const int TEST_NUM = 3; int seed = 123456789; int test_i; double[] test_a = { 0.0, Math.PI / 4.0, Math.PI / 2.0 } ; double[] test_b = { 1.0, 0.5, 0.0 } ; Console.WriteLine(""); Console.WriteLine("DIPOLE_CDF_TEST"); Console.WriteLine(" DIPOLE_CDF evaluates the Dipole CDF;"); Console.WriteLine(" DIPOLE_CDF_INV inverts the Dipole CDF."); Console.WriteLine(" DIPOLE_PDF evaluates the Dipole PDF;"); for (test_i = 0; test_i < TEST_NUM; test_i++) { double a = test_a[test_i]; double b = test_b[test_i]; Console.WriteLine(""); Console.WriteLine(" PDF parameter A = " + a + ""); Console.WriteLine(" PDF parameter B = " + b + ""); if (!Dipole.dipole_check(a, b)) { Console.WriteLine(""); Console.WriteLine("DIPOLE_CDF_TEST - Fatal error!"); Console.WriteLine(" The parameters are not legal."); return; } Console.WriteLine(""); Console.WriteLine(" X PDF CDF CDF_INV"); Console.WriteLine(""); int i; for (i = 1; i <= 10; i++) { double x = Dipole.dipole_sample(a, b, ref seed); double pdf = Dipole.dipole_pdf(x, a, b); double cdf = Dipole.dipole_cdf(x, a, b); double x2 = Dipole.dipole_cdf_inv(cdf, a, b); Console.WriteLine(" " + x.ToString(CultureInfo.InvariantCulture).PadLeft(12) + " " + pdf.ToString(CultureInfo.InvariantCulture).PadLeft(12) + " " + cdf.ToString(CultureInfo.InvariantCulture).PadLeft(12) + " " + x2.ToString(CultureInfo.InvariantCulture).PadLeft(12) + ""); } } }
protected static void CalculateCurrents(ComponentContainer container, double t) { foreach (var comp in container.Components) { //la corriente en las resistencias se calcula directamente en ellas: es ley de Ohm:V/R if (comp is CurrentGenerator || comp is Inductor || comp is Resistor) { Node nodo = comp.Nodes[0]; //comp.current = new Complex32((float)comp.Current(nodo, t), 0); if (container is Branch) { ((Branch)container).current = new Complex32((float)comp.Current(nodo, t), 0); } continue; } //en los Generadores de tension hay que calcular la corriente en 1 u ambos nodos if (comp is VoltageGenerator || comp is Capacitor) { foreach (var nodo in comp.Nodes) { if (nodo.IsReference) { continue; } Dipole comp2 = nodo.OtherComponent(comp); //si tiene solo un resistor en serie es automatico el valor de corriente if (nodo.Components.Count == 2 && (comp2 is Resistor || comp2 is CurrentGenerator || comp2 is Inductor)) { if (nodo == comp.Nodes[0]) { comp.current = new Complex32((float)comp2.Current(nodo, t), 0); } else { comp.current = new Complex32((float)-comp2.Current(nodo, t), 0); } if (container is Branch) { ((Branch)container).current = comp.current; } goto out1; } } Node node = comp.Nodes[0]; //si no tiene solo una resistencias en serie, es decir, un nodo de multiples ramas //se aplica 2da de Kirchoff para el supernodo comp.current = new Complex32((float)CalculateSupernodeCurrent(node, comp, t), 0); } else if (comp is Branch) { CalculateCurrents((Branch)comp, t); continue; } else if (comp is ParallelBlock) { CalculateCurrents((ParallelBlock)comp, t); continue; } out1 :; } }
protected static void CalculateCurrents(ComponentContainer container, Complex32 W) { foreach (var comp in container.Components) { //la corriente en las resistencias se calcula directamente en ellas: es ley de Ohm:V/R if (comp is PasiveComponent || comp is CurrentGenerator) { Node nodo = comp.Nodes[0]; comp.current = comp.Current(nodo, W); if (container is Branch) { ((Branch)container).current = comp.current; } continue; } //en los Generadores de tension hay que calcular la corriente en 1 u ambos nodos if (comp is VoltageGenerator) { foreach (var nodo in comp.Nodes) { Dipole comp2 = nodo.OtherComponent(comp); //si tiene solo un resistor en serie es automatico el valor de corriente if (nodo.Components.Count == 2 && (comp2 is PasiveComponent || comp2 is CurrentGenerator)) { comp.current = comp2.Current(nodo, W); if (container is Branch) { ((Branch)container).current = comp.current; } goto out1; } } //si no tiene solo una resistencias en serie, es decir, un nodo de multiples ramas //se aplica 2da de Kirchoff para el supernodo // throw new NotImplementedException(); foreach (var nodo in comp.Nodes) { if (nodo.IsReference) { continue; } Complex32 i = Complex32.Zero; i = CalculateSupernodeCurrent(nodo, W, comp); comp.current = i; break; } } else if (comp is Branch) { CalculateCurrents((Branch)comp, W); continue; } else if (comp is ParallelBlock) { CalculateCurrents((ParallelBlock)comp, W); continue; } out1 :; } }
/// <summary> /// Calculate Statics components currents /// </summary> /// <param name="container"></param> private static void CalculateCurrents(ComponentContainer container) { foreach (var comp in container.Components) { //la corriente de DC de un capacitor es 0 if (comp is Capacitor) { continue; } //la corriente en las resistencias se calcula directamente en ellas: es ley de Ohm:V/R if (comp is Resistor || comp is CurrentGenerator) { if (container is Branch) { Node nodo = comp.Nodes[0]; ((Branch)container).current = comp.Current(nodo); } continue; } //en los Generadores de tension hay que calcular la corriente en 1 u ambos nodos if (comp is VoltageGenerator || comp is Inductor) { foreach (var nodo in comp.Nodes) { Dipole comp2 = nodo.OtherComponent(comp); //si tiene solo un resistor en serie es automatico el valor de corriente if (nodo.Components.Count == 2 && (comp2 is Resistor || comp2 is CurrentGenerator)) { //Node nodo2 = com comp.current = comp2.Current(nodo); if (container is Branch) { ((Branch)container).current = comp.Current(nodo); } goto out1; } } //si no tiene solo una resistencias en serie, es decir, un nodo de multiples ramas //se aplica 2da de Kirchoff para el supernodo throw new NotImplementedException(); foreach (var nodo in comp.Nodes) { Complex32 i; foreach (var comp2 in nodo.Components) { } } } else if (comp is Branch) { CalculateCurrents((Branch)comp); continue; } else if (comp is ParallelBlock) { CalculateCurrents((ParallelBlock)comp); continue; } out1 :; } }
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) //{ //} } }