A hearing aid shapes sound with a recursive digital filter. Its designer describes it by two coefficient lists, b (the numerator) and a (the denominator), and its transfer function
B(z) b[0] + b[1] * z^-1 + b[2] * z^-2 + ...
H(z) = ------ = ----------------------------------------
A(z) a[0] + a[1] * z^-1 + a[2] * z^-2 + ...
Until now z^-1 was a symbol for a delay. The power of the transfer function is that you can also put a number in for z, any complex number except 0, and get a complex number H(z) back. Special values of z answer physical questions: z = 1 gives the gain for a constant input, and points on the circle |z| = 1 give the response to sine waves (both come later in this level). Values of z where A(z) = 0 are the filter's poles: there H(z) is not defined, and near them it is huge.
Python's complex numbers do the arithmetic: z ** -k is z^-k, and 1j is the imaginary unit.
Write tf_value(b, a, z) that returns the pair (H.real, H.imag), or None if abs(A(z)) < 1e-12 (z is a pole).
Examples
Input: b = [1, 1], a = [1, -0.5], z = 1
Output: (4.0, 0.0)
Explanation: B(1) = 1 + 1 = 2, A(1) = 1 - 0.5 = 0.5, so H(1) = 4.
Input: b = [1, 1], a = [1, -0.5], z = 1j
Output: (0.4, -1.2)
Explanation: z^-1 = 1 / 1j = -1j, so B = 1 - 1j and A = 1 + 0.5j; (1 - 1j) / (1 + 0.5j) = 0.4 - 1.2j.
Input: b = [1, 1], a = [1, -0.5], z = 0.5
Output: None
Explanation: A(0.5) = 1 - 0.5 * 2 = 0: z = 0.5 is a pole.
Constraints
zmay be given as an int, a float or a complex number, never0- answers are compared with a tolerance of
1e-6; a list[re, im]is accepted in place of the tuple - the tests never have
abs(A(z))close to1e-12unless it is really 0
Goals
- Evaluate a transfer function H(z) = B(z) / A(z) at a complex number z
- Evaluate a polynomial in z^-1 term by term or with Horner's rule
- Recognise a value of z where the denominator is zero (a pole)