Problem 541853 · easy · Level 05 Advanced Algorithms & Graphs

Is the Drone's Height Loop Stable?

poles · stability · unit circle · numpy · polynomial roots

A drone holds its height with a discrete controller. Closing the loop gives a characteristic polynomial, written as a coefficient list p with the highest power of z first: [1, -1.2, 0.5] means z^2 - 1.2 z + 0.5. (It is the same list as the polynomial in z^-1 with the constant first; multiplying by z^2 turns one into the other.) Its roots are the loop's poles.

In Level 4 you found roots by hand. From this level on numpy does it: numpy.roots(p) returns all the roots of the polynomial p (highest power first) as an array of complex numbers, and abs(z) (or numpy.abs on the whole array) is a pole's distance from the origin. A pole at radius r makes its part of the response shrink like r ** k after k samples, so

  • the loop is stable when every pole has radius less than 1 (strictly inside the unit circle);
  • the largest radius decides how fast the slowest part dies away.

Write pole_radii(p) that returns a pair (radii, stable): the radii of all len(p) - 1 poles, largest first, and True if all are below 1, else False. A constant polynomial (len(p) == 1) has no poles: ([], True).

import numpy

goes inside your function or at the top of your code; this problem loads numpy for you.

Examples

Input:  p = [1, -1.2, 0.5]
Output: ([0.7071067811865476, 0.7071067811865476], True)
Explanation: the poles are 0.6 + 0.374j and 0.6 - 0.374j, both at radius sqrt(0.5).

Input:  p = [1, -0.4, -0.45]
Output: ([0.9, 0.5], True)
Explanation: z^2 - 0.4 z - 0.45 = (z - 0.9)(z + 0.5).

Input:  p = [1, -1.6, 0.55]
Output: ([1.1, 0.5], False)
Explanation: a pole at 1.1 grows by 10 % every sample; the drone climbs away.

Constraints

  • no pole lies within 1e-6 of the unit circle in the tests, so rounding never changes the verdict
  • radii are compared with a tolerance of 1e-6; an array is accepted in place of the list

Goals

  • Find the roots of a characteristic polynomial with numpy.roots
  • Measure each pole's distance from the origin with abs
  • Call a discrete loop stable when every pole lies strictly inside the unit circle
Starting Python…