Я думаю, что проблема может быть из-за внутренних ошибок округления, потому что 0.1 нельзя представить точно как питон float
. Я бы попробовал
import math
def dy_dt(y,t):
if math.isclose(t, t1):
return 500 - 2*y
else:
return -2y
Также в документации odeint
предлагается использовать параметр args
вместо глобальных переменных, чтобы дать вашей производной функции доступ к дополнительным аргументам и заменить np.arange
на np.linspace
:
import scipy.integrate as sp
import matplotlib.pyplot as plt
import numpy as np
import math
def dy_dt(y, t, t1):
if math.isclose(t, t1):
return 500 - 2*y
else:
return -2*y
t1 = 4
y0 = 500
t = np.linspace(0, 10, num=101)
y = sp.odeint(dy_dt, y0, t, args=(t1,))
plt.plot(t, y)
Я не тестировал код, поэтому скажите, если с ним что-то не так.
РЕДАКТИРОВАТЬ:
При тестированиимой код Я посмотрел на t
значения, для которых dy_dt
оценивается. Я заметил, что odeint
не только использует значения t
, которые указаны, но и слегка их изменяет:
...
3.6636447422787928
3.743098503914526
3.822552265550259
3.902006027185992
3.991829287543431
4.08165254790087
4.171475808258308
...
Теперь, используя мой метод, мы получаем
math.isclose(3.991829287543431, 4) # False
, потому чтодопуск по умолчанию установлен на относительную ошибку не более 10 ^ (- 9), поэтому функция odeint
«пропускает» удар производной на 4. К счастью, мы можем исправить это, указав более высокий порог ошибки:
def dy_dt(y, t, t1):
if math.isclose(t, t1, abs_tol=0.01):
return 500 - 2*y
else:
return -2*y
Сейчас dy_dt
очень высоко для всех значений от 3,99 до 4,01. Можно уменьшить этот диапазон, если увеличить num
аргумент linspace
.
TL; DR
Ваша проблема не впроблема питона, но проблема численного решения дифференциального уравнения: вам нужно изменить производную на интервал достаточной длины, иначе решатель, скорее всего, упустит интересующее место. Дельта Кронекера не работает с числовыми подходами к решению ODE.