Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Routh–Hurwitz

We saw in the section on stability conditions that there are some simple checks we can do to determine whether a system of order 1, 2, 3, or 4 is stable (all poles are in the LHP). In this section, we explain a more general test for stability called the Routh–Hurwitz stability criterion, which can be applied to systems of any order. It is more complicated, but also more powerful, because it reveals the exact number of poles in the RHP, LHP, and on the imaginary axis.

The Routh array

The Routh–Hurwitz stability criterion is based on a tabular method called the Routh array. Suppose we want to determine whether the roots of the following polynomial are in the LHP, RHP, or on the imaginary axis:

P(s)=ansn+an1sn1++a1s+a0P(s) = a_n s^n + a_{n-1} s^{n-1} + \cdots + a_1 s + a_0

Here is the procedure for the generic case. There are some special cases that come up too, but we will discuss those later.

  1. Construct the Routh array. The rows are labeled with the same powers of ss as the polynomial, in decreasing order. The first two rows are filled with the coefficients of the polynomial, in a zigzag pattern. Here is what it looks like when nn is even:

    snanan2an4a2a0sn1an1an3an5a10sn2s0\def\arraystretch{1.5} \begin{array}{c||c:c:c:c:c:c} s^n & a_n & a_{n-2} & a_{n-4} & \cdots & a_2 & a_0 \\ \hdashline s^{n-1} & a_{n-1} & a_{n-3} & a_{n-5} & \cdots & a_1 & 0 \\ \hdashline s^{n-2} & & & & & & \\ \hdashline \vdots & & & & & & \\ \hdashline s^0 & & & & & & \end{array}
  2. Fill in the next row. The next row is filled in using a formula that involves the entries of the two rows above. For each entry, take the determinant of the 2×22 \times 2 matrix formed by the two entries in the first column and the two entries in the column to the right. Flip the sign, then divide by the first entry in the row directly above. Here are the formulas filled in for the third row:

    snanan2an4a2a0sn1an1an3an5a10sn2anan2an1an3an1anan4an1an5an1anan6an1an7an1ana0an10an10s0\def\arraystretch{1.5} \begin{array}{c||c:c:c:c:c:c} s^n & \textcolor{purple}{a_n} & a_{n-2} & a_{n-4} & \cdots & a_2 & a_0 \\ \hdashline s^{n-1} & \textcolor{blue}{a_{n-1}} & a_{n-3} & a_{n-5} & \cdots & a_1 & 0 \\ \hdashline s^{n-2} & \frac{\svmat{\textcolor{purple}{a_n}&a_{n-2}\\\textcolor{blue}{a_{n-1}}&a_{n-3}}}{-\textcolor{blue}{a_{n-1}}} & \frac{\svmat{\textcolor{purple}{a_n}&a_{n-4}\\\textcolor{blue}{a_{n-1}}&a_{n-5}}}{-\textcolor{blue}{a_{n-1}}} & \frac{\svmat{\textcolor{purple}{a_n}&a_{n-6}\\\textcolor{blue}{a_{n-1}}&a_{n-7}}}{-\textcolor{blue}{a_{n-1}}} & \cdots & \frac{\svmat{\textcolor{purple}{a_n}&a_0\\\textcolor{blue}{a_{n-1}}&0}}{-\textcolor{blue}{a_{n-1}}} & 0 \\ \hdashline \vdots & & & & & & \\ \hdashline s^0 & & & & & & \end{array}

    The first column gets reused a lot, so we color it purple and blue to make it easier to keep track of which entries are being used in the formula.

  3. Continue filling in the rows. Fill in the rest of the array one row at a time. Each row depends on the two rows above it using the same formula as in step 2. Keep going until you have filled in the row corresponding to s0s^0.

  4. Count the sign changes in the first column. The number of sign changes in the first column of the completed Routh array is the number of roots in the RHP. If there are no sign changes, then all roots are in the LHP and the system is stable.

Example 1

Let’s apply Routh–Hurwitz to the following polynomial:

P1(s)=s3+3s2+7s+5P_1(s) = s^3 + 3s^2 + 7s + 5

Start filling out the Routh array:

s317s235s1?s0\def\arraystretch{1.5} \begin{array}{c||c:c} s^3 & 1 & 7 \\ \hdashline s^2 & 3 & 5 \\ \hdashline s^1 & \textcolor{blue}{?} & \\ \hdashline s^0 & & \end{array}

We use the formula to find the missing entry:

17353=37153=163\frac{-\vmat{1&7\\3&5}}{3} = \frac{3 \cdot 7 - 1 \cdot 5 }{3} = \textcolor{blue}{\frac{16}{3}}

We can fill in the rest using our tricks for simplifying calculation.

17351631735163017351017351050\def\arraystretch{1.5} \begin{array}{||c:c} 1 & 7 \\ \hdashline 3 & 5 \\ \hdashline \frac{16}{3} & \\ \hdashline & \end{array} \quad\rightarrow\quad \begin{array}{||c:c} 1 & 7 \\ \hdashline 3 & 5 \\ \hdashline \frac{16}{3} & 0 \\ \hdashline & \end{array} \quad\rightarrow\quad \begin{array}{||c:c} 1 & 7 \\ \hdashline 3 & 5 \\ \hdashline 1 & 0 \\ \hdashline & \end{array} \quad\rightarrow\quad \begin{array}{||c:c} 1 & 7 \\ \hdashline 3 & 5 \\ \hdashline 1 & 0 \\ \hdashline 5 & 0 \end{array}

The first column is all positive, so there are no sign changes. Therefore, all roots of P1(s)P_1(s) are in the LHP, and the system is stable. We can verify this by using our stability rules for cubic polynomials. The coefficients are all positive, and a2a1>a0a_2 a_1 > a_0 because 37>53 \cdot 7 > 5, so the system is stable.

Example 2

Let’s do a more complicated example:

P2(s)=3s7+9s6+6s5+4s4+7s3+8s2+2s+6P_2(s) = 3 s^7 + 9 s^6 + 6 s^5 + 4 s^4 + 7 s^3 + 8 s^2 + 2 s + 6

Here is the completed Routh array. Using exact fractions get quite messy so we just used decimal approximations. This is fine because we only care about the signs of the entries, not their exact values.

s73672s69486s54.74.30s44.486s312.96.4s210.26s11.2s06\def\arraystretch{1.5} \begin{array}{c||c:c:c:c} s^7 & 3 & 6 & 7 & 2\\ \hdashline s^6 & 9 & 4 & 8 & 6 \\ \hdashline s^5 & 4.7 & 4.3 & 0 & \\ \hdashline s^4 & -4.4 & 8 & 6 & \\ \hdashline s^3 & 12.9 & 6.4 & & \\ \hdashline s^2 & 10.2 & 6 & & \\ \hdashline s^1 & -1.2 & & & \\ \hdashline s^0 & 6 & & & \end{array}

The entries we left blank are just zero. The staircase structure of the Routh array above is a common pattern. The “6” that shows up on the right in every second row follows from the one zero property.

As a sample calculation, to find the 4.34.3 in the s5s^5 row, we did:

37989=97389=3994.3\frac{-\vmat{3&7\\9&8}}{9} = \frac{9 \cdot 7 - 3 \cdot 8}{9} = \frac{39}{9} \approx 4.3

The first column has four sign changes, so there are four roots in the RHP. Since it’s a 7th-order polynomial, the remaining three roots are in the LHP. We can verify this is true by calculating the roots numerically and we obtain:

{  2.29,  1.03±0.65j3 LHP roots,  0.03±0.80j,  0.64±0.71j4 RHP roots  }\bigl\{\; \underbrace{-2.29,\; -1.03 \pm 0.65j}_{\textsf{3 LHP roots}},\; \underbrace{0.03 \pm 0.80j,\; 0.64 \pm 0.71j}_{\textsf{4 RHP roots}} \;\bigr\}

Special case: first column zero

Since computing each entry requires us to divide by the first entry in the row above, we run into a problem if that entry is zero. In this case, it turns out we can replace the zero with a small positive number or negative number and fill in the rest as normal.

As an example, consider the polynomial:

P3(s)=s5+2s4+3s3+6s2+5s+3P_3(s) = s^5 + 2 s^4 + 3 s^3 + 6 s^2 + 5 s + 3

Filling out the first few rows of the Routh array, we get:

s5135s4263s303.5s2?\def\arraystretch{1.5} \begin{array}{c||c:c:c} s^5 & 1 & 3 & 5 \\ \hdashline s^4 & 2 & 6 & 3 \\ \hdashline s^3 & \textcolor{red}{0} & 3.5 & \\ \hdashline s^2 & ? & & \\ \end{array}

We can’t continue because we would have to divide by zero. Let’s see what happens if we replace the zero with a small positive or negative number ±0.01\pm 0.01.

s5135s4263s30.013.5s2694.03s13.5s03s5135s4263s30.013.5s2706.03s13.5s03\def\arraystretch{1.5} \begin{array}{c||c:c:c} s^5 & 1 & 3 & 5 \\ \hdashline s^4 & 2 & 6 & 3 \\ \hdashline s^3 & \textcolor{red}{0.01} & 3.5 & \\ \hdashline s^2 & -694.0 & 3 & \\ \hdashline s^1 & 3.5 & & \\ \hdashline s^0 & 3 & & \end{array} \qquad \begin{array}{c||c:c:c} s^5 & 1 & 3 & 5 \\ \hdashline s^4 & 2 & 6 & 3 \\ \hdashline s^3 & \textcolor{red}{-0.01} & 3.5 & \\ \hdashline s^2 & 706.0 & 3 & \\ \hdashline s^1 & 3.5 & & \\ \hdashline s^0 & 3 & & \end{array}

The arrays look different, but they have the same number of sign changes in the first column, which is what we care about. In both cases, there are two sign changes, so there are two roots in the RHP and three roots in the LHP.

This works because the roots of a polynomial are a continuous function of its coefficients. If we perturb the coefficients by a small amount, the roots will also be perturbed by a small amount. Therefore, if we replace the zero with a small positive or negative number, the roots will not change drastically, and the number of roots in the RHP will not change.

In practice, if we encounter a zero in the first column, we can just replace it with a small positive number and proceed with the calculation. We can also be more formal and replace the zero with a symbolic variable ε\epsilon, fill in the rest of the array, and evaluate the sign of each entry in the first column in the limit as ε0+\epsilon \to 0^+.

Special case: entire row zero

If an entire row of the Routh array is zero, this indicates that the presence of a special factor that contains only even or odd powers of ss. For example, consider the polynomial:

P4(s)=(s2+s+1)(s4+2s2+2)even factor=s6+s5+3s4+2s3+4s2+2s+2\begin{aligned} P_4(s) &= (s^2+s+1)\overbrace{(s^4+2s^2+2)}^{\textsf{even factor}} \\ &= s^6 + s^5 + 3 s^4 + 2 s^3 + 4 s^2 + 2 s + 2 \end{aligned}

The Routh array for this polynomial is:

s61342s5122s4122s300aaaa}  specialfactor\def\arraystretch{1.5} \begin{array}{c||c:c:c:c} s^6 & 1 & 3 & 4 & 2 \\ \hdashline s^5 & 1 & 2 & 2 & \\ \hdashline s^4 & 1 & 2 & 2 & \\ \hdashline s^3 & \textcolor{red}{0} & \textcolor{red}{0} & & \end{array} \begin{array}{l} \vphantom{a}\\\vphantom{a}\\ \left.\mat{\vphantom{a}\\\vphantom{a}}\right\}\; \def\arraystretch{1.0} \mat{\textsf{special}\\\textsf{factor}} \\ \end{array}

The entire s3s^3 row is zero, indicating that we have a special factor. We can read it from the last two rows, using the row labels as a guide. Here, we read: s4+2s2+2s^4 + 2 s^2 + 2, which is the same as the even factor identified in Eq. (17).

To proceed, we replace the row of zeros with the derivative of the special factor. In this case, dds(s4+2s2+2)=4s3+4s\frac{\dd}{\dd s}\left(s^4 + 2 s^2 + 2\right) = 4 s^3 + 4 s. We fill in the rest of the array as usual:

s61342s5122s4122s344s212s14s02\def\arraystretch{1.5} \begin{array}{c||c:c:c:c} s^6 & 1 & 3 & 4 & 2 \\ \hdashline s^5 & 1 & 2 & 2 & \\ \hdashline s^4 & 1 & 2 & 2 & \\ \hdashline s^3 & 4 & 4 & & \\ \hdashline s^2 & 1 & 2 & & \\ \hdashline s^1 & -4 & & & \\ \hdashline s^0 & 2 & & & \\ \end{array}

We can interpret the resulting table the same way as before: there are two sign changes in the first column, so there are two RHP roots.

Imaginary axis roots

Even polynomials have the special property that if ss is a root, then s-s is also a root. Therefore, the number of RHP and LHP roots is the same. Any left over roots must therefore be on the imaginary axis. For example, consider the polynomial:

P5(s)=s6+2s4+4s2+3P_5(s) = s^6 + 2 s^4 + 4 s^2 + 3

This is an even polynomial. The Routh array is:

s61243s5688s423833s31619s21583s1335s03awas all zeroaaaaa\def\arraystretch{1.5} \begin{array}{c||c:c:c:c} s^6 & 1 & 2 & 4 & 3 \\ \hdashline s^5 & 6 & 8 & 8 & \\ \hdashline s^4 & \tfrac{2}{3} & \tfrac{8}{3} & 3 & \\ \hdashline s^3 & -16 & -19 & & \\ \hdashline s^2 & \tfrac{15}{8} & 3 & & \\ \hdashline s^1 & \tfrac{33}{5} & & & \\ \hdashline s^0 & 3 & & & \end{array} \begin{array}{c} \vphantom{a} \\ \leftarrow \textsf{was all zero} \\ \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \end{array}

Since there are two sign changes in the first column, there are two RHP roots. Since the polynomial is even, there are also two LHP roots. Since it’s a 6th-order polynomial, the remaining two roots must be on the imaginary axis. We can verify this by factoring P5P_5 and finding its roots numerically: P5(s)=(s2+1)(s4+s2+3)P_5(s) = (s^2 + 1)(s^4+s^2+3). The six roots are:

{  ±jimaginary,  0.785±1.056j2 RHP roots,  0.785±1.056j2 LHP roots  }\bigl\{\; \underbrace{\pm j}_\textsf{imaginary},\; \underbrace{0.785 \pm 1.056j}_{\textsf{2 RHP roots}},\; \underbrace{-0.785 \pm 1.056j}_{\textsf{2 LHP roots}} \;\bigr\}

Imaginary axis roots always produce factors of the form (s2+ω2)(s^2 + \omega^2), so they always show up as special factors in the Routh array. Therefore, a row of zeros is necessary for the existence of imaginary axis roots. However, it is not sufficient because we can have special factors that have no imaginary axis roots, as we saw in the example with P4P_4.

By analyzing the special factor, we can determine how many RHP, LHP, and imaginary axis roots it contains. Then, using the fact that we know the total number of RHP roots and that the rest of the roots cannot be imaginary, we can determine a complete classification of all the roots. We’ll see a complete example of this next.

Step-by-step example

Consider the polynomial:

P6(s)=s8+3s7+10s6+24s5+48s4+96s3+128s2+192s+128P_6(s) = s^8 + 3s^7 + 10s^6 + 24s^5 + 48s^4 + 96s^3 + 128s^2 + 192s + 128

Click the box below to see the step-by-step solution.

The resulting Routh array is:

s811048128128s7183264s6183264s531632s41824s315s218s13s08aaawas all zeroaaaaa\def\arraystretch{1.5} \begin{array}{c||r:r:r:r:r} s^8 & 1 & 10 & 48 & 128 & 128 \\ \hdashline s^7 & 1 & 8 & 32 & 64 & \\ \hdashline s^6 & 1 & 8 & 32 & 64 & \\ \hdashline s^5 & 3 & 16 & 32 & & \\ \hdashline s^4 & 1 & 8 & 24 & & \\ \hdashline s^3 & -1 & -5 & & & \\ \hdashline s^2 & 1 & 8 & & & \\ \hdashline s^1 & 3 & & & & \\ \hdashline s^0 & 8 & & & & \end{array} \begin{array}{c} \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \\ \leftarrow \textsf{was all zero} \\ \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \\ \vphantom{a} \\ \end{array}

We conclude from the Routh array that:

So overall, there must be: 2 imaginary roots, 2 RHP roots, and 4 LHP roots.

We can verify this because:

P6(s)=(s+1)(s+2)(s2+2s+4)4 LHP roots(s22s+4)2 RHP roots(s2+4)2 imaginaryP_6(s) = \underbrace{(s+1)(s+2)(s^2+2s+4)}_{\textsf{4 LHP roots}} \underbrace{(s^2-2s+4)}_{\textsf{2 RHP roots}} \underbrace{(s^2+4)}_{\textsf{2 imaginary}}

Why does it work?

The Routh–Hurwitz approach works because it converts a root-location problem into a sign-counting problem. Given a polynomial P(s)P(s), the number of roots in the right half-plane can be determined by how the curve P(jω)P(j\omega) winds around the origin as ω\omega runs from -\infty to ++\infty.

This is a consequence of the argument principle from complex analysis: roots inside a region are counted by the winding of the function around zero on the boundary of that region (the “winding number”).

The Routh array is an algebraic way to compute that winding number without explicitly plotting P(jω)P(j\omega) or solving for the roots. It does this by repeatedly combining the even and odd parts of the polynomial, in a way closely related to the Euclidean algorithm or a Sturm sequence. Each step preserves the information needed to count how many times the argument of P(jω)P(j\omega) crosses through critical directions.