The characteristic equation
Constant coefficients and the characteristic equation (lesson 6.2.1)
0 of 8 correct
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
How to type answers
- Powers with
^:x^7,2^(1/3),a^-2. - Multiply with
*or by writing side by side:3x^2,2(x+1). ln(x)is the natural log,log(x, 2)is log base 2,eis Euler's number,sqrt(x)is a square root.sin(x),cos(x)andtan(x)take radians; writepifor π andsin(x)^2for sin²x.- Your first answer to each question is saved: it counts towards your score and brings the question back for review.
- Exact answers like
ln(20)/ln(3)are best. Decimals need about 4 significant figures.
General solutions and boundary conditions
General solutions and boundary conditions (lesson 6.2.2)
0 of 9 correct
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
How to type answers
- Powers with
^:x^7,2^(1/3),a^-2. - Multiply with
*or by writing side by side:3x^2,2(x+1). ln(x)is the natural log,log(x, 2)is log base 2,eis Euler's number,sqrt(x)is a square root.sin(x),cos(x)andtan(x)take radians; writepifor π andsin(x)^2for sin²x.- Your first answer to each question is saved: it counts towards your score and brings the question back for review.
- Exact answers like
ln(20)/ln(3)are best. Decimals need about 4 significant figures.
Coding exercise
Solving any constant-coefficient equation
Write ivp_solution(a, b, c, y0, v0, t). It returns for the solution of with and , by the formulas of lessons 6.2.1 and 6.2.2. t may be a number or a NumPy array.
- Decide the case from the discriminant , then write the general solution of that case.
- Fix and from and (lesson 6.2.2). In the complex case, remember that adds to the slope.
- Raise
ValueErrorifais 0: the equation is then first order.
The tests use the examples of both lessons, an equation with in each real case, and a growing solution. They compare your answer with solve_ivp for other coefficients, and check that it starts at with slope .
See the tests
import math
import numpy as np
from scipy.integrate import solve_ivp
def _numerical(a, b, c, y0, v0, T):
sol = solve_ivp(lambda t, s: [s[1], -(b * s[1] + c * s[0]) / a], (0, T), [y0, v0], rtol=1e-12, atol=1e-12)
return sol.y[0, -1]
def test_two_real_roots():
"""y'' + 5y' + 4y = 0 from y(0) = 1, y'(0) = 0 is 0.484401 at t = 1"""
expect_close(ivp_solution(1, 5, 4, 1, 0, 1), 0.4844007085990117, what="ivp_solution(1, 5, 4, 1, 0, 1)", rel=1e-9)
def test_repeated_root():
"""y'' + 4y' + 4y = 0 from y(0) = 1, y'(0) = 0 is 3e⁻² at t = 1"""
expect_close(ivp_solution(1, 4, 4, 1, 0, 1), 3 * math.exp(-2), what="ivp_solution(1, 4, 4, 1, 0, 1)", rel=1e-9)
def test_complex_roots():
"""y'' + 2y' + 5y = 0 from y(0) = 1, y'(0) = 0 is 0.014164 at t = 1"""
expect_close(ivp_solution(1, 2, 5, 1, 0, 1), 0.01416404894540483, what="ivp_solution(1, 2, 5, 1, 0, 1)", rel=1e-9)
def test_waves():
"""y'' + y = 0 from y(0) = 0, y'(0) = 1 is sin t: sin 2 at t = 2"""
expect_close(ivp_solution(1, 0, 1, 0, 1, 2), math.sin(2), what="ivp_solution(1, 0, 1, 0, 1, 2)", rel=1e-9)
def test_growth():
"""y'' − y = 0 from y(0) = 1, y'(0) = 0 is (e + 1/e)/2 at t = 1"""
expect_close(ivp_solution(1, 0, -1, 1, 0, 1), (math.e + 1 / math.e) / 2, what="ivp_solution(1, 0, -1, 1, 0, 1)", rel=1e-9)
def test_leading_coefficient():
"""2y'' + 3y' + y = 0 from y(0) = 1, y'(0) = 1 is −3e⁻² + 4e⁻¹ at t = 2"""
expect_close(ivp_solution(2, 3, 1, 1, 1, 2), -3 * math.exp(-2) + 4 * math.exp(-1), what="ivp_solution(2, 3, 1, 1, 1, 2)", rel=1e-9)
def test_repeated_with_a():
"""0.5y'' + 2y' + 2y = 0 has a repeated root −2: from y(0) = 1, y'(0) = −1 it is 4e⁻⁶ at t = 3"""
expect_close(ivp_solution(0.5, 2, 2, 1, -1, 3), 4 * math.exp(-6), what="ivp_solution(0.5, 2, 2, 1, -1, 3)", rel=1e-9)
def test_against_solve_ivp():
"""It agrees with solve_ivp for y'' + 0.3y' + 2.5y = 0 and 3y'' − y' − 2y = 0"""
for args, T in [((1, 0.3, 2.5, -1, 2), 4), ((3, -1, -2, 0.5, 0.5), 2)]:
expect_close(ivp_solution(*args, T), _numerical(*args, T), what=f"ivp_solution{args + (T,)}", rel=1e-7)
def test_starts_right():
"""The solution of y'' + y' + 3y = 0 starts at y(0) = 2 with slope −1"""
h = 1e-6
expect_close(ivp_solution(1, 1, 3, 2, -1, 0), 2.0, what="y(0)", rel=1e-12)
slope = (ivp_solution(1, 1, 3, 2, -1, h) - ivp_solution(1, 1, 3, 2, -1, -h)) / (2 * h)
expect_close(slope, -1.0, what="slope at 0", rel=1e-6)
def test_array():
"""An array of times gives an array of values"""
t = np.linspace(0, 3, 7)
got = ivp_solution(1, 2, 5, 1, 0, t)
assert isinstance(got, np.ndarray) and got.shape == t.shape, f"expected an array of shape {t.shape}, got {got!r}"
expect_close(got, np.exp(-t) * (np.cos(2 * t) + 0.5 * np.sin(2 * t)), what="values at 0, 0.5, ..., 3", rel=1e-9)
def test_first_order():
"""a = 0 raises ValueError: there is no second derivative"""
try:
ivp_solution(0, 1, 2, 1, 0, 1)
except ValueError:
return
raise AssertionError("expected ValueError for a = 0")