ODEINT с несколькими параметрами (зависит от времени)

Я пытаюсь решить одно ОДУ первого порядка с помощью ODEINT. Ниже приведен код. Я ожидаю получить 3 значения y для 3 временных точек. Проблема, с которой я борюсь, - это возможность передать n-е значение mt и nt для вычисления dydt. Я думаю, что ODEINT передает все 3 значения mt и nt, а не только 0-е, 1-е или 2-е, в зависимости от итерации. Из-за этого я получаю такую ​​ошибку:

RuntimeError: размер массива, возвращаемого func (4), не соответствует размеру y0 (1).

Интересно, что если я заменю начальное условие, которое является (и должно быть) одним значением как: a0 = [2] * 4, код работает, но дает мне матрицу 4X4 в качестве решения, что кажется неправильным.

mt = np.array([3,7,4,2]) # Array of constants
nt = np.array([5,1,9,3]) # Array of constants
c1,c2,c3 = [-0.3,1.4,-0.5] # co-efficients
para = [mt,nt] # Packing parameters

#Test ODE function
def test (y,t,extra):
    m,n = extra
    dydt = c1*c2*m - c1*y - c3*n
    return dydt

a0= [2]  # Initial Condition
tspan = range(len(mt)) # Define tspan

#Solving the ODE
yt= odeint(test, a0,tspan,args=(para,)) 
#Plotting the ODE
plt.plot(tspan,yt,'g')
plt.title('Multiple Parameters Test')
plt.xlabel('Time')
plt.ylabel('Magnitude')

Дифференциальное уравнение первого порядка:

dy/dt = c1*(c2*mt-y(t)) - c3*nt

Это уравнение представляет собой часть эндокринной системы мышей, которую я пытаюсь смоделировать. Система аналогична системе с двумя резервуарами, где первый резервуар получает определенный гормон [с неизвестной скоростью], но наш датчик определяет этот уровень (mt) через определенные интервалы времени (1 секунда). Затем этот резервуар поступает во второй резервуар, где уровень этого гормона (y) определяется другим датчиком. Я обозначил уровни, используя отдельные переменные, потому что датчики, определяющие уровни, не зависят друг от друга и не откалиброваны друг для друга. «c2» можно рассматривать как коэффициент, который показывает корреляцию между двумя уровнями. Кроме того, перенос этого гормона из резервуара 1 в резервуар 2 обусловлен диффузией. Этот гормон дополнительно потребляется в ходе биохимического процесса (аналогично сливному клапану для второго резервуара). На данный момент неясно, какие параметры влияют на потребление; однако другой датчик может определять количество потребляемого гормона (nt) в определенный интервал времени (1 секунда, в этом случае тоже).

Таким образом, mt и nt - это концентрации / уровни гормона в определенные моменты времени. хотя в коде всего 4 элемента, в моем исследовании эти массивы намного длиннее. Все датчики сообщают о концентрациях с интервалом в 1 секунду, поэтому tspan состоит из временных точек, разделенных 1 секундой.

Цель состоит в том, чтобы математически определить концентрацию этого гормона во втором резервуаре (y), а затем оптимизировать значения этих коэффициентов на основе экспериментальных данных. Я смог передать эти массивы mt и nt в определенный ODE и решить с помощью ODE45 в MATLAB без проблем. Я столкнулся с этим RunTimeError, пытаясь воспроизвести код на Python.


person bluetooth    schedule 25.01.2017    source источник
comment
Если вы проследите, как ваши переменные определены и переданы, вы увидите, что m в test() становится mt. mt является массивом numpy длиной 4, поэтому c1*c2*m также является массивом numpy длиной 4 (как и c3*n). Тогда dydt - это массив длины 4. Таким образом, вы фактически возвращаете массив длиной 4 из test().   -  person Warren Weckesser    schedule 25.01.2017
comment
Да, я понял, что -. Как исправить эту проблему, чтобы test () принимал только одно значение mt и nt - n-е значение для n-й итерации - и возвращал только одно значение вместо массива длиной 4?   -  person bluetooth    schedule 25.01.2017
comment
Что вы имеете в виду под n-й итерацией?   -  person Warren Weckesser    schedule 25.01.2017
comment
odeint вызовет функцию test 4 раза для 4 точек в tspan, верно? Я думал, что каждый вызов test со стороны ODE будет называться итерацией - нет?   -  person bluetooth    schedule 25.01.2017
comment
Нет. odeint может вызывать функцию test много раз со значениями t, которые не обязательно находятся в tspan. Вы должны реализовать test как функцию произвольных значений t. То есть ваша функция должна обрабатывать t=1e-3, t=2.5 и т. Д.   -  person Warren Weckesser    schedule 25.01.2017
comment
@WarrenWeckesser, спасибо за ответ - я этого не знал. Где мне найти эту информацию, поскольку она не была доступна в строке документации ODEINT. Кроме того, как я могу улучшить этот код? Какие изменения мне нужно внести в этот код, чтобы a0=2 и yt создавали массив 4X1?   -  person bluetooth    schedule 26.01.2017
comment
Может ли кто-нибудь помочь мне исправить этот код? Я перепробовал все, что мог; но, похоже, ничего не решает проблему. Заранее спасибо!   -  person bluetooth    schedule 29.01.2017
comment
Не могли бы вы прояснить (в вопросе) проблему, которую пытаетесь решить? Моя интерпретация состоит в том, что у вас есть дифференциальное уравнение первого порядка dy/dt = c1*c2*m(t) - c1*y - c3*n(t), но функции m(t) и n(t) известны только в дискретных значениях времени t = 0, 1, 2, 3. Если это так, вы должны решить, как вы хотите для определения m(t) и n(t) для произвольного t. Если вы не можете этого сделать, значит, у вас нет четко определенного дифференциального уравнения. Если мое понимание неверно, поясните, пожалуйста, математическую проблему, объяснив ее более подробно в вопросе.   -  person Warren Weckesser    schedule 30.01.2017
comment
@WarrenWeckesser, я обновил вопрос дополнительными деталями. Пожалуйста, дайте мне знать, если потребуется дополнительная информация / разъяснения.   -  person bluetooth    schedule 30.01.2017
comment
Есть там кто-нибудь?   -  person bluetooth    schedule 03.02.2017


Ответы (1)


Как я упоминал в комментарии, если вы хотите смоделировать эту систему, используя обыкновенное дифференциальное уравнение, вы должны сделать предположение о значениях m и n между временами выборки. Одна из возможных моделей - использовать линейную интерполяцию. Вот сценарий, в котором для создания функции mfunc(t) и nfunc(t) основаны на примерах mt и nt.

import numpy as np
from scipy.integrate import odeint
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

mt = np.array([3,7,4,2])  # Array of constants
nt = np.array([5,1,9,3])  # Array of constants

c1, c2, c3 = [-0.3, 1.4, -0.5] # co-efficients

# Create linear interpolators for m(t) and n(t).
sample_times = np.arange(len(mt))
mfunc = interp1d(sample_times, mt, bounds_error=False, fill_value="extrapolate")
nfunc = interp1d(sample_times, nt, bounds_error=False, fill_value="extrapolate")

# Test ODE function
def test (y, t):
    dydt = c1*c2*mfunc(t) - c1*y - c3*nfunc(t)
    return dydt

a0 = [2]  # Initial Condition
tspan = np.linspace(0, sample_times.max(), 8*len(sample_times)+1)
#tspan = sample_times

# Solving the ODE
yt = odeint(test, a0, tspan)

# Plotting the ODE
plt.plot(tspan, yt, 'g')
plt.title('Multiple Parameters Test')
plt.xlabel('Time')
plt.ylabel('Magnitude')
plt.show()

Вот сюжет, созданный сценарием:

сюжет

Обратите внимание, что вместо того, чтобы генерировать решение только в sample_times (т.е. в моменты времени 0, 1, 2 и 3), я установил tspan на более плотный набор точек. Это показывает поведение модели между временами выборки.

person Warren Weckesser    schedule 03.02.2017
comment
Большой! Спасибо, @WarrenWeckesser! - person bluetooth; 04.02.2017