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]); } }
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]); }
public void doStep(Circuit sim, double voltdiff) { // used to have .1 here, but needed .01 for peak detector if (Math.Abs(voltdiff - lastvoltdiff) > 0.01) { sim.converged = false; } voltdiff = limitStep(sim, voltdiff, lastvoltdiff); lastvoltdiff = voltdiff; if (voltdiff >= 0 || zvoltage == 0) { // regular diode or forward-biased zener double eval = Math.Exp(voltdiff * vdcoef); // make diode linear with negative voltages; aids convergence if (voltdiff < 0) { eval = 1; } double geq = vdcoef * leakage * eval; double nc = (eval - 1) * leakage - geq * voltdiff; sim.stampConductance(nodes[0], nodes[1], geq); sim.stampCurrentSource(nodes[0], nodes[1], nc); } else { // Zener diode // I(Vd) = Is * (exp[Vd*C] - exp[(-Vd-Vz)*C] - 1 ) // geq is I'(Vd) nc is I(Vd) + I'(Vd)*(-Vd) double geq = leakage * vdcoef * (Math.Exp(voltdiff * vdcoef) + Math.Exp((-voltdiff - zoffset) * vdcoef)); double nc = leakage * (Math.Exp(voltdiff * vdcoef) - Math.Exp((-voltdiff - zoffset) * vdcoef) - 1) + geq * (-voltdiff); sim.stampConductance(nodes[0], nodes[1], geq); sim.stampCurrentSource(nodes[0], nodes[1], nc); } }
public override void step(Circuit sim) { double voltdiff = lead_volt[0] - lead_volt[1]; if (Math.Abs(voltdiff - lastvoltdiff) > 0.01) { sim.converged = false; } voltdiff = limitStep(voltdiff, lastvoltdiff); lastvoltdiff = voltdiff; double i = pip * Math.Exp(-pvpp / pvt) * (Math.Exp(voltdiff / pvt) - 1) + pip * (voltdiff / pvp) * Math.Exp(1 - voltdiff / pvp) + piv * Math.Exp(voltdiff - pvv); double geq = pip * Math.Exp(-pvpp / pvt) * Math.Exp(voltdiff / pvt) / pvt + pip * Math.Exp(1 - voltdiff / pvp) / pvp - Math.Exp(1 - voltdiff / pvp) * pip * voltdiff / (pvp * pvp) + Math.Exp(voltdiff - pvv) * piv; double nc = i - geq * voltdiff; sim.stampConductance(lead_node[0], lead_node[1], geq); sim.stampCurrentSource(lead_node[0], lead_node[1], nc); }