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.

First of all, you have only TWO free parameters, not four. For network problems (water flow, electric circuits, ... ) these are most conveniently taken as the driving potentials at nodes, since currents/flows depend only on the difference between these potentials and the resistances in the connectors. In this problem, the best two parameters are V2 and V3 (voltages at nodes 2 and 3).
Secondly, a diode is a highly NON-LINEAR device. Thus, Newton-Raphson is not necessarily a good way to solve this problem. (By hand, I used single-point iteration, since the inverted diode formula gives a logarithm, which changes relatively slowly.)
In the end I did manage to solve your problem by Newton-Raphson, but I had to do two key things. (1) I needed a decent initial guess (to find which I basically took the diode as offering no resistance). (2) I had to UNDER-RELAX the update step. (This is a classic technique in non-linear problems such as computational fluid mechanics.)
The solver that I have used here is a very cheap one (2x2 matrices only). You can use your library one for bigger problems.
Final iterations and output: