Example #1
0
        public Connection Connect(CircuitElement left, int leftLeadNdx, CircuitElement right, int rightLeadNdx)
        {
            Lead leftlead  = left.getLead(leftLeadNdx);
            Lead rightlead = right.getLead(rightLeadNdx);

            return(Connect(leftlead, rightlead));
        }
Example #2
0
 public void panic(String why, CircuitElement elem)
 {
     circuitMatrix = null;
     _analyze      = true;
     Debug.Log(why);
     throw new CircuitException(why, elem);
 }
Example #3
0
 public void AddElement(CircuitElement elm)
 {
     if (!elements.Contains(elm))
     {
         elements.Add(elm);
     }
 }
Example #4
0
 public FindPathInfo(Circuit r, PathType t, CircuitElement e, int d)
 {
     sim      = r;
     dest     = d;
     type     = t;
     firstElm = e;
     used     = new bool[sim.nodeList.Count];
 }
Example #5
0
 public List <ScopeFrame> Watch(CircuitElement component)
 {
     if (!scopeMap.ContainsKey(component))
     {
         List <ScopeFrame> scope = new List <ScopeFrame>();
         scopeMap.Add(component, scope);
         return(scope);
     }
     else
     {
         return(scopeMap[component]);
     }
 }
Example #6
0
 internal Lead(CircuitElement e, int i)
 {
     elem = e;
     ndx  = i;
     Id   = Circuit.snowflake.NextId();
 }
Example #7
0
        public void analyze()
        {
            if (elements.Count == 0)
            {
                return;
            }

            nodeList.Clear();

            #region 查找电源和接地元素
            // Search the circuit for a Ground, or Voltage sourcre
            CircuitElement voltageElm = null;
            bool           gotGround  = false;
            bool           gotRail    = false;
            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement elem = elements[i];
                if (elem is Ground)
                {
                    gotGround = true;
                    break;
                }

                if (elem is VoltageInput)                //RailElm in Java
                {
                    gotRail = true;
                }

                if (voltageElm == null && elem is Voltage)
                {
                    voltageElm = elem;
                }
            }

            // If no ground and no rails, then the voltage elm's first terminal is ground.
            // 没有电源(单),没有接地,但是有电源(双),那么电源的零点为接地点
            if (!gotGround && !gotRail && voltageElm != null)
            {
                CircuitNode cn = new CircuitNode();
                cn.lead = voltageElm.getLead(0);
                nodeList.Add(cn);
            }
            else
            {
                // If the circuit contains a ground, rail, or voltage
                // element, push a temporary node to the node list.
                CircuitNode cn = new CircuitNode();
                cn.lead = null; //Bin: 特殊节点,零点
                nodeList.Add(cn);
            }
            #endregion

            // At this point, there is 1 node in the list, the special `global ground` node.

            #region 电路节点和电源节点
            int vscount = 0;             // Number of voltage sources
            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement ce    = elements[i];
                int            leads = ce.getLeadCount();

                for (int j = 0; j != leads; j++)
                {
                    Lead lead = ce.getLead(j);
                    int  k;
                    for (k = 0; k != nodeList.Count; k++) //查找现有的每个节点,判断是否相连
                    {
                        //原Java版,这里用元器件的端点的坐标(XY)判断是否相连
                        //我们这里没有坐标,因此连接关系由Lead自己维护
                        CircuitNode cn = nodeList[k];
                        if (cn.lead != null)
                        {
                            FindConnection fc = new FindConnection(this, lead.Id);
                            if (fc.IsConnected(cn.lead.Id))
                            {
                                break;
                            }
                        }
                    }
                    if (k == nodeList.Count)  //没有找到现有的节点
                    {
                        CircuitNode cn = new CircuitNode();
                        cn.lead = lead;
                        CircuitNodeLink cnl = new CircuitNodeLink();
                        cnl.lead_ndx = j;
                        cnl.element  = ce;
                        cn.links.Add(cnl);
                        ce.setLeadNode(j, nodeList.Count);
                        nodeList.Add(cn); //这两行顺序不能颠倒
                    }
                    else
                    {
                        CircuitNodeLink cnl = new CircuitNodeLink();
                        cnl.lead_ndx = j;
                        cnl.element  = ce;
                        nodeList[k].links.Add(cnl);
                        ce.setLeadNode(j, k);
                        // if it's the ground node, make sure the node voltage is 0,
                        // cause it may not get set later
                        if (k == 0)
                        {
                            ce.setLeadVoltage(j, 0);
                        }
                    }
                }

                // Push an internal node onto the list for
                // each internal lead on the element.
                int internalLeads = ce.getInternalLeadCount();
                for (int j = 0; j != internalLeads; j++)
                {
                    CircuitNode cn = new CircuitNode();
                    cn.lead     = null;
                    cn.Internal = true;
                    CircuitNodeLink cnl = new CircuitNodeLink();
                    cnl.lead_ndx = j + leads;
                    cnl.element  = ce;
                    cn.links.Add(cnl);
                    ce.setLeadNode(cnl.lead_ndx, nodeList.Count);
                    nodeList.Add(cn); //这两行顺序不能颠倒
                }
                vscount += ce.getVoltageSourceCount();
            }
            #endregion

            // 创建电源节点数组
            // 同时判断电路是否线性

            // VoltageSourceId -> CircuitElement map
            voltageSources   = new CircuitElement[vscount];
            vscount          = 0;
            circuitNonLinear = false;


            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement ce = elements[i];
                if (ce.nonLinear())
                {
                    circuitNonLinear = true;
                }

                // Assign each votage source in the element a globally unique id,
                // (the index of the next open slot in voltageSources)
                for (int j = 0; j != ce.getVoltageSourceCount(); j++)
                {
                    voltageSources[vscount] = ce;
                    ce.setVoltageSource(j, vscount);
                    vscount++;
                }
            }

            #region 创建矩阵
            int matrixSize = nodeList.Count - 1 + vscount;

            // setup circuitMatrix
            circuitMatrix = new double[matrixSize][];
            for (int z = 0; z < matrixSize; z++)
            {
                circuitMatrix[z] = new double[matrixSize];
            }

            circuitRightSide = new double[matrixSize];

            // setup origMatrix
            origMatrix = new double[matrixSize][];
            for (int z = 0; z < matrixSize; z++)
            {
                origMatrix[z] = new double[matrixSize];
            }

            origRightSide = new double[matrixSize];

            // setup circuitRowInfo
            circuitRowInfo = new RowInfo[matrixSize];
            for (int i = 0; i != matrixSize; i++)
            {
                circuitRowInfo[i] = new RowInfo();
            }

            circuitPermute    = new int[matrixSize];
            circuitMatrixSize = circuitMatrixFullSize = matrixSize;
            circuitNeedsMap   = false;
            #endregion

            // Stamp linear circuit elements.
            for (int i = 0; i != elements.Count; i++)
            {
                elements[i].stamp(this);
            }

            #region 查找连接不正确的节点
            bool[] closure = new bool[nodeList.Count];
            bool   changed = true;
            closure[0] = true;
            while (changed)
            {
                changed = false;
                for (int i = 0; i != elements.Count; i++)
                {
                    CircuitElement ce = elements[i];
                    // loop through all ce's nodes to see if they are connected
                    // to other nodes not in closure
                    for (int leadX = 0; leadX < ce.getLeadCount(); leadX++)
                    {
                        if (!closure[ce.getLeadNode(leadX)])
                        {
                            if (ce.leadIsGround(leadX))
                            {
                                closure[ce.getLeadNode(leadX)] = changed = true;
                            }
                            continue;
                        }
                        for (int k = 0; k != ce.getLeadCount(); k++)
                        {
                            if (leadX == k)
                            {
                                continue;
                            }
                            int kn = ce.getLeadNode(k);
                            if (ce.leadsAreConnected(leadX, k) && !closure[kn])
                            {
                                closure[kn] = true;
                                changed     = true;
                            }
                        }
                    }
                }

                if (changed)
                {
                    continue;
                }

                // connect unconnected nodes
                for (int i = 0; i != nodeList.Count; i++)
                {
                    if (!closure[i] && !nodeList[i].Internal)
                    {
                        //System.out.println("node " + i + " unconnected");
                        stampResistor(0, i, 1E8);
                        closure[i] = true;
                        changed    = true;
                        break;
                    }
                }
            }
            #endregion

            #region  电路正确性检查
            for (int i = 0; i != elements.Count; i++)
            {
                CircuitElement ce = elements[i];

                // look for inductors with no current path
                if (ce is InductorElm)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.INDUCT, ce, ce.getLeadNode(1));
                    // first try findPath with maximum depth of 5, to avoid slowdowns
                    if (!fpi.findPath(ce.getLeadNode(0), 5) && !fpi.findPath(ce.getLeadNode(0)))
                    {
                        //System.out.println(ce + " no path");
                        ce.reset();
                    }
                }

                // look for current sources with no current path
                if (ce is CurrentSource)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.INDUCT, ce, ce.getLeadNode(1));
                    if (!fpi.findPath(ce.getLeadNode(0)))
                    {
                        panic("No path for current source!", ce);
                    }
                }

                // look for voltage source loops
                if ((ce is Voltage && ce.getLeadCount() == 2) || ce is Wire)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.VOLTAGE, ce, ce.getLeadNode(1));
                    if (fpi.findPath(ce.getLeadNode(0)))
                    {
                        panic("Voltage source/wire loop with no resistance!", ce);
                    }
                }

                // look for shorted caps, or caps w/ voltage but no R
                if (ce is CapacitorElm)
                {
                    FindPathInfo fpi = new FindPathInfo(this, FindPathInfo.PathType.SHORT, ce, ce.getLeadNode(1));
                    if (fpi.findPath(ce.getLeadNode(0)))
                    {
                        //System.out.println(ce + " shorted");
                        ce.reset();
                    }
                    else
                    {
                        fpi = new FindPathInfo(this, FindPathInfo.PathType.CAP_V, ce, ce.getLeadNode(1));
                        if (fpi.findPath(ce.getLeadNode(0)))
                        {
                            panic("Capacitor loop with no resistance!", ce);
                        }
                    }
                }
            }
            #endregion

            #region 简化矩阵 这块会导致电池无法并联,先去掉
            //for(int i = 0; i != matrixSize; i++) {
            //    int qm = -1, qp = -1;
            //    double qv = 0;
            //    RowInfo re = circuitRowInfo[i];

            //    if(re.lsChanges || re.dropRow || re.rsChanges)
            //        continue;

            //    double rsadd = 0;

            //    // look for rows that can be removed
            //    int leadX = 0;
            //    for(; leadX != matrixSize; leadX++) {

            //        double q = circuitMatrix[i][leadX];
            //        if(circuitRowInfo[leadX].type == RowInfo.ROW_CONST) {
            //            // keep a running total of const values that have been removed already
            //            rsadd -= circuitRowInfo[leadX].value * q;
            //            continue;
            //        }

            //        if(q == 0)
            //            continue;

            //        if(qp == -1) {
            //            qp = leadX;
            //            qv = q;
            //            continue;
            //        }

            //        if(qm == -1 && q == -qv) {
            //            qm = leadX;
            //            continue;
            //        }

            //        break;
            //    }

            //    if(leadX == matrixSize) {

            //        if(qp == -1)
            //            panic("Matrix error", null);

            //        RowInfo elt = circuitRowInfo[qp];
            //        if(qm == -1) {
            //            // we found a row with only one nonzero entry;
            //            // that value is a constant
            //            for(int k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++) {
            //                // follow the chain
            //                // System.out.println("following equal chain from " + i + " " + qp + " to " + elt.nodeEq);
            //                qp = elt.nodeEq;
            //                elt = circuitRowInfo[qp];
            //            }

            //            if(elt.type == RowInfo.ROW_EQUAL) {
            //                // break equal chains
            //                // System.out.println("Break equal chain");
            //                elt.type = RowInfo.ROW_NORMAL;
            //                continue;
            //            }

            //            if(elt.type != RowInfo.ROW_NORMAL) {
            //                //System.out.println("type already " + elt.type + " for " + qp + "!");
            //                continue;
            //            }

            //            elt.type = RowInfo.ROW_CONST;
            //            elt.value = (circuitRightSide[i] + rsadd) / qv;
            //            circuitRowInfo[i].dropRow = true;
            //            // System.out.println(qp + " * " + qv + " = const " + elt.value);
            //            i = -1; // start over from scratch
            //        } else if(circuitRightSide[i] + rsadd == 0) {
            //            // we found a row with only two nonzero entries, and one
            //            // is the negative of the other; the values are equal
            //            if(elt.type != RowInfo.ROW_NORMAL) {
            //                // System.out.println("swapping");
            //                int qq = qm;
            //                qm = qp;
            //                qp = qq;
            //                elt = circuitRowInfo[qp];
            //                if(elt.type != RowInfo.ROW_NORMAL) {
            //                    // we should follow the chain here, but this hardly
            //                    // ever happens so it's not worth worrying about
            //                    //System.out.println("swap failed");
            //                    continue;
            //                }
            //            }
            //            elt.type = RowInfo.ROW_EQUAL;
            //            elt.nodeEq = qm;
            //            circuitRowInfo[i].dropRow = true;
            //            // System.out.println(qp + " = " + qm);
            //        }
            //    }
            //}

            // == Find size of new matrix
            int nn = 0;
            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo elt = circuitRowInfo[i];
                if (elt.type == RowInfo.ROW_NORMAL)
                {
                    elt.mapCol = nn++;
                    // System.out.println("col " + i + " maps to " + elt.mapCol);
                    continue;
                }
                if (elt.type == RowInfo.ROW_EQUAL)
                {
                    RowInfo e2 = null;
                    // resolve chains of equality; 100 max steps to avoid loops
                    for (int leadX = 0; leadX != 100; leadX++)
                    {
                        e2 = circuitRowInfo[elt.nodeEq];
                        if (e2.type != RowInfo.ROW_EQUAL)
                        {
                            break;
                        }

                        if (i == e2.nodeEq)
                        {
                            break;
                        }

                        elt.nodeEq = e2.nodeEq;
                    }
                }
                if (elt.type == RowInfo.ROW_CONST)
                {
                    elt.mapCol = -1;
                }
            }

            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo elt = circuitRowInfo[i];
                if (elt.type == RowInfo.ROW_EQUAL)
                {
                    RowInfo e2 = circuitRowInfo[elt.nodeEq];
                    if (e2.type == RowInfo.ROW_CONST)
                    {
                        // if something is equal to a const, it's a const
                        elt.type   = e2.type;
                        elt.value  = e2.value;
                        elt.mapCol = -1;
                    }
                    else
                    {
                        elt.mapCol = e2.mapCol;
                    }
                }
            }

            // == Make the new, simplified matrix.
            int        newsize = nn;
            double[][] newmatx = new double[newsize][];
            for (int z = 0; z < newsize; z++)
            {
                newmatx[z] = new double[newsize];
            }

            double[] newrs = new double[newsize];
            int      ii    = 0;
            for (int i = 0; i != matrixSize; i++)
            {
                RowInfo rri = circuitRowInfo[i];
                if (rri.dropRow)
                {
                    rri.mapRow = -1;
                    continue;
                }
                newrs[ii]  = circuitRightSide[i];
                rri.mapRow = ii;
                // System.out.println("Row " + i + " maps to " + ii);
                for (int leadX = 0; leadX != matrixSize; leadX++)
                {
                    RowInfo ri = circuitRowInfo[leadX];
                    if (ri.type == RowInfo.ROW_CONST)
                    {
                        newrs[ii] -= ri.value * circuitMatrix[i][leadX];
                    }
                    else
                    {
                        newmatx[ii][ri.mapCol] += circuitMatrix[i][leadX];
                    }
                }
                ii++;
            }
            #endregion

            #region             //// Copy matrix to orig ////
            circuitMatrix    = newmatx;
            circuitRightSide = newrs;
            matrixSize       = circuitMatrixSize = newsize;

            // copy `rightSide` to `origRightSide`
            for (int i = 0; i != matrixSize; i++)
            {
                origRightSide[i] = circuitRightSide[i];
            }

            // copy `matrix` to `origMatrix`
            for (int i = 0; i != matrixSize; i++)
            {
                for (int leadX = 0; leadX != matrixSize; leadX++)
                {
                    origMatrix[i][leadX] = circuitMatrix[i][leadX];
                }
            }
            #endregion

            circuitNeedsMap = true;
            _analyze        = false;

            // If the matrix is linear, we can do the lu_factor
            // here instead of needing to do it every frame.
            if (!circuitNonLinear)
            {
                if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute))
                {
                    panic("Singular matrix!", null);
                }
            }
        }
Example #8
0
 public CircuitException(string why, CircuitElement elem)
     : base(why)
 {
     element = elem;
 }
Example #9
0
            public bool findPath(int n1, int depth)
            {
                if (n1 == dest)
                {
                    return(true);
                }

                if (depth-- == 0)
                {
                    return(false);
                }

                if (used[n1])
                {
                    return(false);
                }

                used[n1] = true;
                for (int i = 0; i != sim.elements.Count; i++)
                {
                    CircuitElement ce = sim.elements[i];
                    if (ce == firstElm)
                    {
                        continue;
                    }

                    if (type == PathType.INDUCT)
                    {
                        if (ce is CurrentSource)
                        {
                            continue;
                        }
                    }

                    if (type == PathType.VOLTAGE)
                    {
                        if (!(ce.isWire() || ce is Voltage))
                        {
                            continue;
                        }
                    }

                    if (type == PathType.SHORT && !ce.isWire())
                    {
                        continue;
                    }

                    if (type == PathType.CAP_V)
                    {
                        if (!(ce.isWire() || ce is CapacitorElm || ce is Voltage))
                        {
                            continue;
                        }
                    }

                    if (n1 == 0)
                    {
                        // look for posts which have a ground connection;
                        // our path can go through ground
                        for (int z = 0; z != ce.getLeadCount(); z++)
                        {
                            if (ce.leadIsGround(z) && findPath(ce.getLeadNode(z), depth))
                            {
                                used[n1] = false;
                                return(true);
                            }
                        }
                    }

                    int j;
                    for (j = 0; j != ce.getLeadCount(); j++)
                    {
                        if (ce.getLeadNode(j) == n1)
                        {
                            break;
                        }
                    }

                    if (j == ce.getLeadCount())
                    {
                        continue;
                    }

                    if (ce.leadIsGround(j) && findPath(0, depth))
                    {
                        // System.out.println(ce + " has ground");
                        used[n1] = false;
                        return(true);
                    }

                    if (type == PathType.INDUCT && ce is InductorElm)
                    {
                        double c = ce.getCurrent();
                        if (j == 0)
                        {
                            c = -c;
                        }

                        // System.out.println("matching " + c + " to " + firstElm.getCurrent());
                        // System.out.println(ce + " " + firstElm);
                        if (Math.Abs(c - firstElm.getCurrent()) > 1e-10)
                        {
                            continue;
                        }
                    }

                    for (int k = 0; k != ce.getLeadCount(); k++)
                    {
                        if (j == k)
                        {
                            continue;
                        }

                        // System.out.println(ce + " " + ce.getNode(j) + "-" + ce.getNode(k));
                        if (ce.leadsAreConnected(j, k) && findPath(ce.getLeadNode(k), depth))
                        {
                            // System.out.println("got findpath " + n1);
                            used[n1] = false;
                            return(true);
                        }
                        // System.out.println("back on findpath " + n1);
                    }
                }

                used[n1] = false;
                // System.out.println(n1 + " failed");
                return(false);
            }