I am working on a circuit simulator based on Modified Nodal Analysis (MNA), aiming to support nonlinear components such as diodes. To solve the nonlinear equations, I have implemented the Newton-Raphson method. However, I am facing issues with my implementation. Here is a simplified version of the code I am using to solve the below circuit:
// Function to calculate the diode current using the Shockley diode equation
double diodeEquation(double vd, double is, double vt) {
return is * (exp(vd / vt) - 1.0);
}
// Function to calculate the diode current derivative w.r.t. voltage using the Shockley diode equation
double diodeDerivative(double vd, double is, double vt) {
return is * exp(vd / vt) / vt;
}
int main() {
// Step 1: Set up the MNA equations
// Circuit components
double vs = 5.0; // Voltage source value
double r1 = 10.0; // Resistor R1 value
double r2 = 20.0; // Resistor R2 value
double r3 = 30.0; // Resistor R3 value
// Diode parameters for the Shockley diode equation
double is = 1e-12; // Saturation current
double vt = 25.85e-3; // Thermal voltage
// Step 2: Initialize variables
double v1 = 0.0; // Initial guess for node voltage V1
double v2 = 0.0; // Initial guess for node voltage V2
double v3 = 0.0; // Initial guess for node voltage V3
double v1_old, v2_old, v3_old; // Previous values for convergence check
double tol = 1e-6; // Tolerance for convergence
int maxIterations = 100; // Maximum number of iterations
int iterations = 0; // Iteration counter
bool converged = false; // Convergence flag
// Step 4: Perform the Modified Newton-Raphson iteration
while (!converged && iterations < maxIterations) {
// Save the previous node voltages for convergence check
v1_old = v1;
v2_old = v2;
v3_old = v3;
// Calculate the diode current and its derivative
double vd = v2 - v3;
double id = diodeEquation(vd, is, vt);
double g = diodeDerivative(vd, is, vt);
// Formulate the MNA equations
double i1 = (v1 - vs) / r1;
double i2 = (v2 - v3) / r2;
double i3 = v3 / r3;
double i4 = id;
// Construct the Jacobian matrix
double j11 = 1.0 / r1;
double j12 = -1.0 / r1;
double j13 = 0.0;
double j21 = 1.0 / r2;
double j22 = -1.0 / r2 - g;
double j23 = g;
double j31 = 0.0;
double j32 = g;
double j33 = -g;
// Construct the residual vector
double r1 = i1 - i2;
double r2 = -i1 + i2 - i3;
double r3 = -i2 + i3 - i4;
// Solve the linear system of equations to obtain the update
double detJ = j11 * (j22 * j33 - j32 * j23) - j12 * (j21 * j33 - j31 * j23) + j13 * (j21 * j32 - j31 * j22);
double dv1 = ((j22 * j33 - j32 * j23) * r1 - (j12 * j33 - j32 * j13) * r2 + (j12 * j23 - j22 * j13) * r3) / detJ;
double dv2 = (-(j21 * j33 - j31 * j23) * r1 + (j11 * j33 - j31 * j13) * r2 - (j11 * j23 - j21 * j13) * r3) / detJ;
double dv3 = ((j21 * j32 - j31 * j22) * r1 - (j11 * j32 - j31 * j12) * r2 + (j11 * j22 - j21 * j12) * r3) / detJ;
// Update the solution vector
v1 -= dv1;
v2 -= dv2;
v3 -= dv3;
// Check for convergence
double norm = sqrt(pow(v1 - v1_old, 2) + pow(v2 - v2_old, 2) + pow(v3 - v3_old, 2));
if (norm < tol) {
converged = true;
}
iterations++;
}
// Step 5: Output the final solution
if (converged) {
std::cout << "Converged to solution:\n";
std::cout << "V1 = " << v1 << " V\n";
std::cout << "V2 = " << v2 << " V\n";
std::cout << "V3 = " << v3 << " V\n";
}
return 0;
}
I have tested the same circuit in two other circuit simulators, The first simulator reports Vd = 739 mV
and Id = 70.74 mA
, and the second simulator reports Vd = 765 mV
and Id = 70 mA
. However, in my implementation, the output is Vd = 175 mV
and Id = 2.14 µA
.
I would appreciate any insights into what might be wrong with my implementation of the Newton-Raphson method for solving the circuit equations, especially with regards to the diode component.
Edit:
After considering the suggestions from EvgsupportsModerator, I have formulated the equations based on Kirchhoff's Voltage Law (KVL) and Kirchhoff's Current Law (KCL). The equations for each node are as follows:
KCL at node 1: I + (v1 - v2)/R1 = 0 // I is the current through the voltage source
KCL at node 2: (v2 - v1)/R1 + v2/R2 + Is*(exp((v2 - v3)/vt) - 1) = 0
KCL at node 3: -Is*(exp((v2 - v3)/vt) - 1) + v3/R3 = 0
KVL at node 1: v1 - E = 0
I obtained the following vector solution when I execute the previous code that I provide:
v1 = 5
v2 = 3.33142
v3 = 0.00861309
I = -0.166858
However, when I substituted these values back into the system, I found that they do not satisfy all of the equations. They only satisfy the first and last equations.
To validate my calculations, I simulated the same circuit using the ngspice software, and it provided a different vector solution:
v1 = 5
v2 = 2.808430
v3 = 2.362064
I = -0.219157
Interestingly, when I substituted these values into the system, it appeared to be a correct solution. Therefore, it seems that the values obtained from the ngspice simulation align better with the given equations.