Ejemplo n.º 1
0
        public override void stamp(Circuit sim)
        {
            // equations for transformer:
            // v1 = L1 di1/dt + M di2/dt
            // v2 = M di1/dt + L2 di2/dt
            // we invert that to get:
            // di1/dt = a1 v1 + a2 v2
            // di2/dt = a3 v1 + a4 v2
            // integrate di1/dt using trapezoidal approx and we get:
            // i1(t2) = i1(t1) + dt/2 (i1(t1) + i1(t2))
            // = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1) +
            // a1 dt/2 v1(t2) + a2 dt/2 v2(t2)
            // the norton equivalent of this for i1 is:
            // a. current source, I = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1)
            // b. resistor, G = a1 dt/2
            // c. current source controlled by voltage v2, G = a2 dt/2
            // and for i2:
            // a. current source, I = i2(t1) + a3 dt/2 v1(t1) + a4 dt/2 v2(t1)
            // b. resistor, G = a3 dt/2
            // c. current source controlled by voltage v2, G = a4 dt/2
            //
            // For backward euler,
            //
            // i1(t2) = i1(t1) + a1 dt v1(t2) + a2 dt v2(t2)
            //
            // So the current source value is just i1(t1) and we use
            // dt instead of dt/2 for the resistor and VCCS.
            //
            // first winding goes from node 0 to 2, second is from 1 to 3
            double l1 = inductance;
            double l2 = inductance * ratio * ratio;
            double m  = couplingCoef * Math.Sqrt(l1 * l2);
            // build inverted matrix
            double deti = 1 / (l1 * l2 - m * m);
            double ts   = isTrapezoidal ? sim.timeStep / 2 : sim.timeStep;

            a1 = l2 * deti * ts;             // we multiply dt/2 into a1..a4 here
            a2 = -m * deti * ts;
            a3 = -m * deti * ts;
            a4 = l1 * deti * ts;
            sim.stampConductance(lead_node[0], lead_node[2], a1);
            sim.stampVCCS(lead_node[0], lead_node[2], lead_node[1], lead_node[3], a2);
            sim.stampVCCS(lead_node[1], lead_node[3], lead_node[0], lead_node[2], a3);
            sim.stampConductance(lead_node[1], lead_node[3], a4);
            sim.stampRightSide(lead_node[0]);
            sim.stampRightSide(lead_node[1]);
            sim.stampRightSide(lead_node[2]);
            sim.stampRightSide(lead_node[3]);
        }
Ejemplo n.º 2
0
 public override void stamp(Circuit sim)
 {
     nodes[0] = lead_node[0];
     nodes[1] = lead_node[1];
     if (isTrapezoidal)
     {
         compResistance = 2 * inductance / sim.timeStep;
     }
     else
     {
         compResistance = inductance / sim.timeStep;                 // backward euler
     }
     sim.stampResistor(nodes[0], nodes[1], compResistance);
     sim.stampRightSide(nodes[0]);
     sim.stampRightSide(nodes[1]);
 }
Ejemplo n.º 3
0
        public override void stamp(Circuit sim)
        {
            // equations for transformer:
            // v1 = L1 di1/dt + M1 di2/dt + M1 di3/dt
            // v2 = M1 di1/dt + L2 di2/dt + M2 di3/dt
            // v3 = M1 di1/dt + M2 di2/dt + L2 di3/dt
            // we invert that to get:
            // di1/dt = a1 v1 + a2 v2 + a3 v3
            // di2/dt = a4 v1 + a5 v2 + a6 v3
            // di3/dt = a7 v1 + a8 v2 + a9 v3
            // integrate di1/dt using trapezoidal approx and we get:
            // i1(t2) = i1(t1) + dt/2 (i1(t1) + i1(t2))
            // = i1(t1) + a1 dt/2 v1(t1)+a2 dt/2 v2(t1)+a3 dt/2 v3(t3) +
            // a1 dt/2 v1(t2)+a2 dt/2 v2(t2)+a3 dt/2 v3(t3)
            // the norton equivalent of this for i1 is:
            // a. current source, I = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1)
            // + a3 dt/2 v3(t1)
            // b. resistor, G = a1 dt/2
            // c. current source controlled by voltage v2, G = a2 dt/2
            // d. current source controlled by voltage v3, G = a3 dt/2
            // and similarly for i2
            //
            // first winding goes from node 0 to 1, second is from 2 to 3 to 4
            double l1 = inductance;
            double cc = .99;

            // double m1 = .999*Math.sqrt(l1*l2);
            // mutual inductance between two halves of the second winding
            // is equal to self-inductance of either half (slightly less
            // because the coupling is not perfect)
            // double m2 = .999*l2;
            // load pre-inverted matrix
            a[0] = (1 + cc) / (l1 * (1 + cc - 2 * cc * cc));
            a[1] = a[2] = a[3] = a[6] = 2 * cc / ((2 * cc * cc - cc - 1) * inductance * ratio);
            a[4] = a[8] = -4 * (1 + cc) / ((2 * cc * cc - cc - 1) * l1 * ratio * ratio);
            a[5] = a[7] = 4 * cc / ((2 * cc * cc - cc - 1) * l1 * ratio * ratio);
            int i;

            for (i = 0; i != 9; i++)
            {
                a[i] *= sim.timeStep / 2;
            }

            sim.stampConductance(lead_node[0], lead_node[1], a[0]);
            sim.stampVCCS(lead_node[0], lead_node[1], lead_node[2], lead_node[3], a[1]);
            sim.stampVCCS(lead_node[0], lead_node[1], lead_node[3], lead_node[4], a[2]);

            sim.stampVCCS(lead_node[2], lead_node[3], lead_node[0], lead_node[1], a[3]);
            sim.stampConductance(lead_node[2], lead_node[3], a[4]);
            sim.stampVCCS(lead_node[2], lead_node[3], lead_node[3], lead_node[4], a[5]);

            sim.stampVCCS(lead_node[3], lead_node[4], lead_node[0], lead_node[1], a[6]);
            sim.stampVCCS(lead_node[3], lead_node[4], lead_node[2], lead_node[3], a[7]);
            sim.stampConductance(lead_node[3], lead_node[4], a[8]);

            for (i = 0; i != 5; i++)
            {
                sim.stampRightSide(lead_node[i]);
            }
        }
Ejemplo n.º 4
0
 public override void stamp(Circuit sim)
 {
     // Capacitor companion model using trapezoidal approximation
     // (Norton equivalent) consists of a current source in
     // parallel with a resistor. Trapezoidal is more accurate
     // than backward euler but can cause oscillatory behavior
     // if RC is small relative to the timestep.
     if (isTrapezoidal)
     {
         compResistance = sim.timeStep / (2 * capacitance);
     }
     else
     {
         compResistance = sim.timeStep / capacitance;
     }
     sim.stampResistor(lead_node[0], lead_node[1], compResistance);
     sim.stampRightSide(lead_node[0]);
     sim.stampRightSide(lead_node[1]);
 }
Ejemplo n.º 5
0
 public void stamp(Circuit sim, double deltaTime, int n0, int n1)
 {
     // inductor companion model using trapezoidal or backward euler
     // approximations (Norton equivalent) consists of a current
     // source in parallel with a resistor. Trapezoidal is more
     // accurate than backward euler but can cause oscillatory behavior.
     // The oscillation is a real problem in circuits with switches.
     nodes[0] = n0;
     nodes[1] = n1;
     if (isTrapezoidal)
     {
         compResistance = 2 * inductance / deltaTime;
     }
     else
     {
         compResistance = inductance / deltaTime;                 // backward euler
     }
     sim.stampResistor(nodes[0], nodes[1], compResistance);
     sim.stampRightSide(nodes[0]);
     sim.stampRightSide(nodes[1]);
 }
Ejemplo n.º 6
0
        public override void step(Circuit sim)
        {
            double vd = lead_volt[1] - lead_volt[0];

            if (Math.Abs(lastvd - vd) > 0.1)
            {
                sim.converged = false;
            }
            else if (lead_volt[2] > maxOut + 0.1 || lead_volt[2] < minOut - 0.1)
            {
                sim.converged = false;
            }

            double x  = 0;
            int    vn = sim.nodeCount + voltSource;
            double dx = 0;

            if (vd >= maxOut / gain && (lastvd >= 0 || getRand(4) == 1))
            {
                dx = 1E-4;
                x  = maxOut - dx * maxOut / gain;
            }
            else if (vd <= minOut / gain && (lastvd <= 0 || getRand(4) == 1))
            {
                dx = 1E-4;
                x  = minOut - dx * minOut / gain;
            }
            else
            {
                dx = gain;
            }

            // newton-raphson
            sim.stampMatrix(vn, lead_node[0], dx);
            sim.stampMatrix(vn, lead_node[1], -dx);
            sim.stampMatrix(vn, lead_node[2], 1);
            sim.stampRightSide(vn, x);

            lastvd = vd;
        }
Ejemplo n.º 7
0
        public override void step(Circuit sim)
        {
            double vbc = lead_volt[0] - lead_volt[1];             // typically negative
            double vbe = lead_volt[0] - lead_volt[2];             // typically positive

            if (Math.Abs(vbc - lastvbc) > 0.01 || Math.Abs(vbe - lastvbe) > 0.01)
            {
                sim.converged = false;
            }

            gmin = 0;
            if (sim.subIterations > 100)
            {
                // if we have trouble converging, put a conductance in parallel with
                // all P-N junctions. Gradually increase the conductance value for each iteration.
                gmin = Math.Exp(-9 * Math.Log(10) * (1 - sim.subIterations / 3000.0));
                if (gmin > .1)
                {
                    gmin = .1;
                }
            }

            vbc     = pnp * limitStep(sim, pnp * vbc, pnp * lastvbc);
            vbe     = pnp * limitStep(sim, pnp * vbe, pnp * lastvbe);
            lastvbc = vbc;
            lastvbe = vbe;
            double pcoef = vdcoef * pnp;
            double expbc = Math.Exp(vbc * pcoef);

            double expbe = Math.Exp(vbe * pcoef);

            if (expbe < 1)
            {
                expbe = 1;
            }

            ie = pnp * leakage * (-(expbe - 1) + rgain * (expbc - 1));
            ic = pnp * leakage * (fgain * (expbe - 1) - (expbc - 1));
            ib = -(ie + ic);

            double gee = -leakage * vdcoef * expbe;
            double gec = rgain * leakage * vdcoef * expbc;
            double gce = -gee * fgain;
            double gcc = -gec * (1 / rgain);

            // stamps from page 302 of Pillage. Node 0 is the base,
            // node 1 the collector, node 2 the emitter. Also stamp
            // minimum conductance (gmin) between b,e and b,c
            sim.stampMatrix(lead_node[0], lead_node[0], -gee - gec - gce - gcc + gmin * 2);
            sim.stampMatrix(lead_node[0], lead_node[1], gec + gcc - gmin);
            sim.stampMatrix(lead_node[0], lead_node[2], gee + gce - gmin);
            sim.stampMatrix(lead_node[1], lead_node[0], gce + gcc - gmin);
            sim.stampMatrix(lead_node[1], lead_node[1], -gcc + gmin);
            sim.stampMatrix(lead_node[1], lead_node[2], -gce);
            sim.stampMatrix(lead_node[2], lead_node[0], gee + gec - gmin);
            sim.stampMatrix(lead_node[2], lead_node[1], -gec);
            sim.stampMatrix(lead_node[2], lead_node[2], -gee + gmin);

            // we are solving for v(k+1), not delta v, so we use formula
            // 10.5.13, multiplying J by v(k)
            sim.stampRightSide(lead_node[0], -ib - (gec + gcc) * vbc - (gee + gce) * vbe);
            sim.stampRightSide(lead_node[1], -ic + gce * vbe + gcc * vbc);
            sim.stampRightSide(lead_node[2], -ie + gee * vbe + gec * vbc);
        }
Ejemplo n.º 8
0
        public override void step(Circuit sim)
        {
            double[] vs = new double[3];
            vs[0] = lead_volt[0];
            vs[1] = lead_volt[1];
            vs[2] = lead_volt[2];
            if (vs[1] > lastv1 + .5)
            {
                vs[1] = lastv1 + .5;
            }
            if (vs[1] < lastv1 - .5)
            {
                vs[1] = lastv1 - .5;
            }
            if (vs[2] > lastv2 + .5)
            {
                vs[2] = lastv2 + .5;
            }
            if (vs[2] < lastv2 - .5)
            {
                vs[2] = lastv2 - .5;
            }
            int source = 1;
            int drain  = 2;

            if ((pnp ? -1 : 1) * vs[1] > (pnp ? -1 : 1) * vs[2])
            {
                source = 2;
                drain  = 1;
            }
            int    gate = 0;
            double vgs  = vs[gate] - vs[source];
            double vds  = vs[drain] - vs[source];

            if (Math.Abs(lastv1 - vs[1]) > .01 || Math.Abs(lastv2 - vs[2]) > .01)
            {
                sim.converged = false;
            }
            lastv1 = vs[1];
            lastv2 = vs[2];
            double realvgs = vgs;
            double realvds = vds;

            vgs *= (pnp ? -1 : 1);
            vds *= (pnp ? -1 : 1);
            ids  = 0;
            gm   = 0;
            double Gds  = 0;
            double beta = getBeta();

            if (vgs > .5 && this is JfetElm)
            {
                sim.panic("JFET is reverse biased!", this);
                return;
            }
            if (vgs < _threshold)
            {
                // should be all zero, but that causes a singular matrix,
                // so instead we treat it as a large resistor
                Gds  = 1e-8;
                ids  = vds * Gds;
                mode = 0;
            }
            else if (vds < vgs - _threshold)
            {
                // linear
                ids  = beta * ((vgs - _threshold) * vds - vds * vds * .5);
                gm   = beta * vds;
                Gds  = beta * (vgs - vds - _threshold);
                mode = 1;
            }
            else
            {
                // saturation; Gds = 0
                gm = beta * (vgs - _threshold);
                // use very small Gds to avoid nonconvergence
                Gds  = 1e-8;
                ids  = 0.5 * beta * (vgs - _threshold) * (vgs - _threshold) + (vds - (vgs - _threshold)) * Gds;
                mode = 2;
            }
            double rs = -(pnp ? -1 : 1) * ids + Gds * realvds + gm * realvgs;

            sim.stampMatrix(lead_node[drain], lead_node[drain], Gds);
            sim.stampMatrix(lead_node[drain], lead_node[source], -Gds - gm);
            sim.stampMatrix(lead_node[drain], lead_node[gate], gm);
            sim.stampMatrix(lead_node[source], lead_node[drain], -Gds);
            sim.stampMatrix(lead_node[source], lead_node[source], Gds + gm);
            sim.stampMatrix(lead_node[source], lead_node[gate], -gm);
            sim.stampRightSide(lead_node[drain], rs);
            sim.stampRightSide(lead_node[source], -rs);
            if (source == 2 && (pnp ? -1 : 1) == 1 || source == 1 && (pnp ? -1 : 1) == -1)
            {
                ids = -ids;
            }
        }
Ejemplo n.º 9
0
        /*public override double getPower() {
         *      return (lead_volt[0] - lead_volt[2]) * current;
         * }*/

        public override void step(Circuit sim)
        {
            double[] vs = new double[3];
            vs[0] = lead_volt[0];
            vs[1] = lead_volt[1];
            vs[2] = lead_volt[2];
            if (vs[1] > lastv1 + 0.5)
            {
                vs[1] = lastv1 + 0.5;
            }
            if (vs[1] < lastv1 - 0.5)
            {
                vs[1] = lastv1 - 0.5;
            }
            if (vs[2] > lastv2 + 0.5)
            {
                vs[2] = lastv2 + 0.5;
            }
            if (vs[2] < lastv2 - 0.5)
            {
                vs[2] = lastv2 - 0.5;
            }
            int    grid  = 1;
            int    cath  = 2;
            int    plate = 0;
            double vgk   = vs[grid] - vs[cath];
            double vpk   = vs[plate] - vs[cath];

            if (Math.Abs(lastv0 - vs[0]) > 0.01 || Math.Abs(lastv1 - vs[1]) > 0.01 || Math.Abs(lastv2 - vs[2]) > 0.01)
            {
                sim.converged = false;
            }
            lastv0 = vs[0];
            lastv1 = vs[1];
            lastv2 = vs[2];
            double ids  = 0;
            double gm   = 0;
            double Gds  = 0;
            double ival = vgk + vpk / mu;

            currentg = 0;
            if (vgk > .01)
            {
                sim.stampResistor(lead_node[grid], lead_node[cath], gridCurrentR);
                currentg = vgk / gridCurrentR;
            }
            if (ival < 0)
            {
                // should be all zero, but that causes a singular matrix,
                // so instead we treat it as a large resistor
                Gds = 1E-8;
                ids = vpk * Gds;
            }
            else
            {
                ids = Math.Pow(ival, 1.5) / kg1;
                double q = 1.5 * Math.Sqrt(ival) / kg1;
                // gm = dids/dgk;
                // Gds = dids/dpk;
                Gds = q;
                gm  = q / mu;
            }
            currentp = ids;
            currentc = ids + currentg;
            double rs = -ids + Gds * vpk + gm * vgk;

            sim.stampMatrix(lead_node[plate], lead_node[plate], Gds);
            sim.stampMatrix(lead_node[plate], lead_node[cath], -Gds - gm);
            sim.stampMatrix(lead_node[plate], lead_node[grid], gm);

            sim.stampMatrix(lead_node[cath], lead_node[plate], -Gds);
            sim.stampMatrix(lead_node[cath], lead_node[cath], Gds + gm);
            sim.stampMatrix(lead_node[cath], lead_node[grid], -gm);

            sim.stampRightSide(lead_node[plate], rs);
            sim.stampRightSide(lead_node[cath], -rs);
        }