示例#1
0
def smp_nonlinear_model(plotting=False):
    """Пример идентификации объекта, описываемого 
    нелинейной моделью, с использованием простейшего 
    адаптивного алгоритма."""

    def obj(x, u):
        return 10 + 2 * np.sin(1 * x) + 4 * u + np.random.uniform(-1, 1)

    m = create_model('a0+a1*sin(a2*x1(t-1))+a3*u1(t-1)')
    idn = identifier.Identifier(m)
    idn.init_data(x=[[0, 9.94, 13.41, 15.44]],
                  a=[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]],
                  u=[[0, 1, 1, 1]])
    smp = alg_old.Adaptive(idn, method='smp')
    n = 20  # количество тактов
    a = np.zeros((n, 4))
    o_ar = np.zeros((n,))
    m_ar = np.zeros((n,))
    u_ar = [i+1 for i in range(n)]
    for i in range(n):
        obj_val = [obj(*idn.model.last_x, *idn.model.get_var_values(t='u')[0])]
        new_a = smp.update(obj_val)
        idn.update_x(obj_val)
        idn.update_u([u_ar[i]])
        idn.update_a(new_a)
        a[i] = new_a
        o_ar[i] = obj_val[0]
        m_ar[i] = idn.model.get_last_model_value()

    print(a)

    if plotting:
        t = np.array([i for i in range(n)])
        real_a = [10, 2, 1, 4]
        draw(t, o_ar, m_ar, a, real_a)
示例#2
0
def lsm_nonlinear_model(plotting=False):
    """Пример с нелинейной моделью, внешним 
    воздействим и алгоритмом на основе МНК."""
    def obj(x, j):
        res = 3 + 0.1 * np.power(x, 1.5) + np.random.uniform(-0.2, 0.2)
        if 10 < j <= 15:
            res += 5
        return res
    m = create_model('a0+a1*(x(t-1)**a2)')
    idn = identifier.Identifier(m)
    idn.init_data(x=[[2.82, 3.43, 3.617]],
                  a=[[1, 1, 1], [1, 1, 1], [1, 1, 1]],
                  u=[])
    lsm = alg_old.Adaptive(idn, m='lsm')
    n = 20
    a = np.zeros((n, 3))
    o_ar = np.zeros((n,))
    m_ar = np.zeros((n,))
    for i in range(n):
        obj_val = [obj(*idn.model.last_x, i)]
        new_a = lsm.update(obj_val, w=0.04, init_weight=0.04)
        idn.update_x(obj_val)
        idn.update_a(new_a)

        a[i] = new_a
        o_ar[i] = obj_val[0]
        m_ar[i] = idn.model.get_last_model_value()

    print(a)

    if plotting:
        real_a = [3, 0.1, 1.5]
        t = np.array([i for i in range(n)])
        draw(t, o_ar, m_ar, a, real_a)
示例#3
0
def lsm_linear_model(plotting=False):
    """Пример идентификации модели с чистым 
    запаздыванием с использованием алгоритма 
    на основе МНК."""
    def obj(x, u):
        return 10 + 0.1 * x + 5 * u + np.random.uniform(-1, 1)
    m = create_model('a_0+a1*x1(t-1)+a_2*u1(t-3)')
    idn = identifier.Identifier(m)
    idn.init_data(x=[[10, 12, 11.2]], a=[[1, 1, 1], [1, 1, 1], [1, 1, 1]], u=[[0, 0, 1, 0, 0]])
    lsm = alg_old.Adaptive(idn, m='lsm')
    n = 20
    a = np.zeros((n, 3))
    o_ar = np.zeros((n,))
    m_ar = np.zeros((n,))
    u_ar = [i + 1 for i in range(n)]
    for i in range(n):
        obj_val = [obj(*idn.model.last_x, *idn.model.get_var_values(t='u')[0])]
        new_a = lsm.update(obj_val, w=0.01, init_weight=0.01)
        idn.update_x(obj_val)
        idn.update_u([u_ar[i]])
        idn.update_a(new_a)

        a[i] = new_a
        o_ar[i] = obj_val[0]
        m_ar[i] = idn.model.get_last_model_value()

    print(a)

    if plotting:
        real_a = [10, 0.1, 5]
        t = np.array([i for i in range(n)])
        draw(t, o_ar, m_ar, a, real_a)
示例#4
0
def smp_linear_model(plotting=False):
    """Пример идентификации для простой модели с 
    импользованием простейшего адаптивного алгоритма."""
    # функция имитирующая объект
    def obj(x):
        return 5 + 0.5 * x + np.random.uniform(-1, 1)

    # создаем модель, имеет два неизвестных коэффициентов a0 и a1
    m = create_model('a0+a1*x(t-1)')

    # создаем идентификатор
    idn = identifier.Identifier(m)
    # проводим инициализацию начальных значений,
    # простейший адаптивный алгоритм не сольно чувствителен
    # к начальным данным, но если все входы/выходы
    # инициализировать нулями, то свободный коэффициент
    # (если есть) вычислиться точнее.
    # Закомментируйте следующую строку и раскомментируйте
    # строку за ней, посмотрите на результат.
    idn.init_data(x=[[0, 0]], a=[[1, 1], [1, 1]])
    # idn.init_data(x=[[0, 5]], a=[[1, 1], [1, 1]])

    # выбор простейшего адаптивного алгоритма
    smp = alg_old.Adaptive(idn, method='smp')

    n = 20  # количество тактов
    a = np.zeros((n, 2))
    o_ar = np.zeros((n, ))
    m_ar = np.zeros((n, ))
    # основной цикл, имитируем 20 тактов
    for i in range(n):
        # измерение выхода объекта
        obj_val = [obj(*idn.model.last_x)]
        # идентификация коэффициентов
        new_a = smp.update(obj_val)
        # обновление данных идентификатора
        idn.update_x(obj_val)
        idn.update_a(new_a)

        a[i] = new_a
        o_ar[i] = obj_val[0]
        m_ar[i] = idn.model.get_last_model_value()

    print(a)

    if plotting:
        t = np.array([i for i in range(n)])
        real_a = [5, .5]
        draw(t, o_ar, m_ar, a, real_a)
示例#5
0
def example_6(use_lsm=False, with_err=False):
    """
    Пример использования библиотеки CotPy для модели с дополнительными входами.
    :param use_lsm: Если уставновлен True используется адаптивный МНК, 
                    иначе простейший адаптивный алгоритм.
    :param with_err: Добавление аддитивной равномерно 
                     распределенной помехи амплитудой 0.1 к выходу объекта 
    :return: None
    """

    a = np.array([1.68, 1.235, -0.319, 0.04, 0.027, 0.1, 0.05])

    def obj(x1, x2, u1, u2, z1, z2):
        """Имитация объекта"""
        val = a[0] + a[1] * x1 + a[2] * x2 + a[3] * u1 + a[4] * u2 + a[
            5] * z1 + a[6] * z2
        if with_err:
            return val + np.random.uniform(-0.05, 0.05)
        else:
            return val

    def xt():
        """Уставка"""
        return 65

    # создание модели
    expr = "a0+a1*x(t-1)+a2*x(t-2)+a3*u(t-6)+a4*u(t-7)+a5*z1(t-1)+a6*z2(t-1)"
    m = model.create_model(expr)
    idn = identifier.Identifier(m)
    print('Модель:', m.sp_expr)

    # TODO: сделать для случая когда память меньше memory_size = 1
    if use_lsm:
        init_x = [[20, 20, 20.9885, 22.27, 23.39, 24.57, 25.51, 26.06]]
        init_u = [[10, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]]
        init_z = np.array([[5.765, 5.24, 5.00, 5.77, 5.32, 5.90, 5.13],
                           [2.84, 2.54, 2.76, 2.51, 2.95, 2.52, 2.59]])
        method = 'lsm'
    else:
        init_x = np.full((1, 8), 20.)
        init_u = np.zeros((1, 13))
        init_z = np.array(
            [np.random.uniform(5, 6, 7),
             np.random.uniform(2, 2.5, 7)])
        method = 'smp'

    idn.init_data(a=np.ones((7, 7)),
                  x=init_x,
                  u=init_u,
                  z=init_z,
                  type_memory='min',
                  memory_size=5)
    algorithm = alg_old.Adaptive(idn, m=method)

    r = Regulator(m)
    r.set_limit(0, 100)
    r.synthesis()
    print('Закон управления:', r.expr)
    print('Аргументы:', r.expr_args)

    n = 240
    u_ar = np.zeros((n, ))
    o_ar = np.zeros((n, ))
    a_ar = np.zeros((n, 7))
    xt_ar = np.zeros((n, ))

    er = np.zeros((n, 7))

    for i in range(n):
        x = [
            obj(*np.hstack(idn.model.get_var_values(t='x')),
                *np.hstack(idn.model.get_var_values(t='u')),
                *np.hstack(idn.model.get_var_values(t='z')))
        ]
        if use_lsm:
            # В адаптивном МНК применяется метод последовательной линеаризации (МПЛ) и адаптивный вес
            new_a = algorithm.update(x,
                                     w=0.01,
                                     init_weight=0.01,
                                     uinc=True,
                                     adaptive_weight=False)
        else:
            # Используется простейший адаптивный с памятью
            new_a = algorithm.update(x,
                                     gamma=1,
                                     gt='a',
                                     weight=0.9,
                                     h=0.1,
                                     use_memory=True)

        idn.update_a(new_a)

        # Дополнительные входы являются случайными возмущениями (которые можно только измерять)
        # и, например, принимают случайные в определенных интервалах
        z = [np.random.uniform(5, 6), np.random.uniform(2.5, 3)]
        new_u = r.update(x, xt(), ainputs=z)

        u_ar[i] = new_u[0]
        o_ar[i] = x[0]
        a_ar[i] = new_a
        xt_ar[i] = xt()

        idn.update_x(x)
        idn.update_u(new_u)
        idn.update_z(z)

        er[i] = a - new_a

    print('Last coefficients:', idn.model.last_a)

    t = np.array([i for i in range(n)])
    # График движенияя объекта
    draw_object_movement(t, o_ar, xt_ar, u_ar)

    # График процесса идентификации
    fig, axs = plt.subplots(nrows=4, ncols=1)
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']

    plot_coefficient(axs[0], t, a_ar[:, 0], a[0], '$t$', '$\\alpha_{0}$',
                     colors[0])

    n_ax = 1
    for i in range(1, len(a) - 1, 2):
        for k in range(2):
            axs[n_ax].plot(t,
                           a_ar[:, i + k],
                           label=f'$\\alpha_{{{str(i+k)}}}$',
                           linestyle='-',
                           color=colors[k + 1])
            axs[n_ax].plot(t, [a[i + k] for _ in range(n)],
                           linestyle='--',
                           color=colors[k + 1])
        axs[n_ax].set_xlabel('$t$')
        axs[n_ax].set_ylabel(
            f'$\\alpha_{{{str(i)}}},\\alpha_{{{str(i + 1)}}}$',
            rotation='horizontal',
            ha='right')
        axs[n_ax].grid(True)
        l = axs[n_ax].legend(labelspacing=0, borderpad=0.3)
        l.set_draggable(True)
        n_ax += 1

    plt.show()
示例#6
0
def example_5(with_err=False):
    """
    Пример использование библиотеки CotPy для адаптивного 
    управления на основе нелинейной модели с чистым 
    запаздыванием в 1 такт.
    :param with_err: Добавление аддитивной равномерно 
                     распределенной помехи амплитудой 0.2 к выходу объекта 
    :return: None
    """

    a = [1.3, 0.52]

    def obj(x, u):
        """Имитация объекта, описываемого нелинейной относительно входов/выходов моделью."""
        val = a[0] + a[1] * x * u
        if with_err:
            return val + np.random.uniform(-0.1, 0.1)
        return val

    def xt(j):
        """Уставка"""
        if j <= 75:
            return 75
        elif 75 < j <= 100:
            return 35
        elif 100 < j <= 120:
            return 25
        else:
            return 60

    expr = "a0+a1*x(t-1)*u(t-2)"
    m = model.create_model(expr)
    idn = identifier.Identifier(m)

    idn.init_data(a=np.ones((2, 2)), x=[[1.3, 1.3]], u=[[0, 0, 0]])
    # В данном случае простейший адаптивный алгоритм отлично справиться
    smp = alg_old.Adaptive(idn, m='smp')

    r = Regulator(m)
    r.set_limit(0, 100)
    r.synthesis()

    n = 240
    u_ar = np.zeros((n, ))
    o_ar = np.zeros((n, ))
    a_ar = np.zeros((n, len(a)))
    xt_ar = np.zeros((n, ))

    for i in range(n):
        x_val = [
            obj(*idn.model.get_var_values(t='x')[0],
                *idn.model.get_var_values(t='u')[0])
        ]

        new_a = smp.update(x_val,
                           gamma=1,
                           gt='a',
                           weight=0.9,
                           h=0.1,
                           deep_tuning=False,
                           aw=False)
        idn.update_a(new_a)

        new_u = r.update(x_val, xt(i + 1))

        u_ar[i] = new_u[0]
        o_ar[i] = x_val[0]
        a_ar[i] = new_a
        xt_ar[i] = xt(i)

        idn.update_x(x_val)
        idn.update_u(new_u)

    print('Last coefficients:', idn.model.last_a)

    t = np.array([i for i in range(n)])

    # График движенияя объекта
    draw_object_movement(t, o_ar, xt_ar, u_ar)

    # График процесса идентификации
    fig, axs = plt.subplots(nrows=2, ncols=1)
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']

    plot_coefficient(axs[0], t, a_ar[:, 0], a[0], '$t$', '$\\alpha_{0}$',
                     colors[0])
    plot_coefficient(axs[1], t, a_ar[:, 1], a[1], '$t$', '$\\alpha_{1}$',
                     colors[0])
示例#7
0
def example_1(with_err=False):
    """
    Пример использования библиотеки CotPy 
    для синтеза закона адаптивного управления 
    с идентификацией. Используется модель с 
    чистым запаздыванием в 2 такта.
    :param with_err: если True добавляется аддитивная равномерно распределенная помеха 
                     амплитудой 0.2 к измерению выхода объекта
    :return: None
    """

    a = [-10, 0.3, 3]  # реальные коэффициенты

    def obj(x, u):
        """Функция имитации объекта."""
        val = a[0] + a[1] * x + a[2] * u
        if with_err:
            return val + np.random.uniform(-0.1, 0.1)
        else:
            return val

    def xt(j):
        """Функция генерации уставки."""
        if j < 10:
            return 100
        elif 10 <= j <= 15:
            return 150
        else:
            return 50

    # создание модели (с чистым запаздыванием)
    m = model.create_model('a_0+a1*x1(t-1)+a_2*u1(t-3)')

    # создание идентификатора и инициализация начальных значений
    idn = identifier.Identifier(m)
    idn.init_data(x=[[0, -11.33, -9.37]],
                  a=np.ones((3, 3)),
                  u=[[0, 2, 3, 4, 4]])

    # определение алгоритма идентификации
    smp = alg_old.Adaptive(idn, m='smp')

    n = 30
    # массивы для сохранения промежуточных значений
    u_ar = np.zeros((n, ))
    o_ar = np.zeros((n, ))
    a_ar = np.zeros((n, len(a)))
    xt_ar = np.zeros((n, ))

    # создание регулятора, установка ограничений на управление и синтез закона управления
    r = Regulator(m)
    r.set_limit(0, 100)
    r.synthesis()

    # основной цикл
    for i in range(n):
        # измерение выхода объекта
        obj_val = [
            obj(*idn.model.get_var_values(t='x')[0],
                *idn.model.get_var_values(t='u')[0])
        ]

        # Для идентификации используется простейший адаптивный алгоритм
        # с методом последовательной линеаризации (глубокая подстройка)
        new_a = smp.update(obj_val,
                           gamma=0.01,
                           gt='a',
                           weight=0.9,
                           h=0.1,
                           deep_tuning=True)
        idn.update_a(new_a)

        # расчет управляющего воздействия
        new_u = r.update(obj_val, xt(i + 3))

        # сохранение промежуточных результатов для построения графика
        u_ar[i] = new_u[0]
        o_ar[i] = obj_val[0]
        a_ar[i] = new_a
        xt_ar[i] = xt(i)

        # обновление состояния модели
        idn.update_x(obj_val)
        idn.update_u(new_u)

    t = [i for i in range(n)]
    draw_object_movement(t, o_ar, xt_ar, u_ar)

    # График процесса идентификации
    fig, axs = plt.subplots(nrows=3, ncols=1)
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']

    for i in range(len(a)):
        plot_coefficient(axs[i], t, a_ar[:, i], a[i], '$t$',
                         f'$\\alpha_{{{str(i)}}}$', colors[i])

    plt.show()
示例#8
0
def example_4(use_lsm=False, with_err=False):
    """
    Пример использование библиотеки CotPy для адаптивного 
    управления на основе сложной линейной модели с чистым 
    запаздыванием в 5 тактов.
    Моделируется процесс нагрева и поддержания температуры жидкости.
    :param use_lsm: Использование адаптивного алгоритма МНК. 
                    Есле use_lsm=False используется простейшый адаптивный алгоритм.
    :param with_err: Добавление аддитивной равномерно распределенной помехи.
    :return: None
    """

    # реальные коэффициенты
    a = [1.68, 1.235, -0.319, 0.04, 0.027]

    def obj(x1, x2, u1, u2, j):
        """Имитация объекта"""
        val = a[0] + a[1] * x1 + a[2] * x2 + a[3] * u1 + a[4] * u2
        if with_err:
            return val + np.random.uniform(-0.1, 0.1)
            # return val + np.random.uniform(-0.15, 0.15)
            # return val + np.random.uniform(-0.2, 0.2)
            # return val + np.random.uniform(-1, 1)
            # return val + np.random.uniform(-1.5, 1.5)
            # return val + np.random.uniform(-5, 5)
            # return val + np.random.uniform(-0.5, 0.5)
            # return val - 0.1
            # return val - 0.3
            # return val - 0.5
            # return val + 5
            # return val + 0.1*np.sin(2*np.pi*j/240*100)
        else:
            return val

    def xt(j):
        """Уставка"""
        if j <= 50:
            return 80
        elif 50 < j <= 80:
            return 35
        elif 80 < j <= 100:
            return 25
        elif 100 < j <= 125:
            return 60
        elif 125 < j <= 150:
            return 70
        elif 150 < j <= 175:
            return 20
        elif 175 < j <= 200:
            return 90
        else:
            return 65

    # Создание модели и идентификатора
    expr = "a0+a1*x(t-1)+a2*x(t-2)+a3*u(t-6)+a4*u(t-7)"
    m = model.create_model(expr)
    idn = identifier.Identifier(m)
    print('Модель:', m.sp_expr)
    if m.get_index_fm() is not None:
        print(f'Индекс свободного члена: {m.get_index_fm()}')
    else:
        print('Нет свободного члена')

    # Инициализация начальных значений
    if use_lsm:
        # Для адаптивного алгоритма МНК необходимы "исторические" данные работы объекта.
        # Инициализация управления нулями (при выключенном объекте)
        # приведет к неработоспособности алгоритма.
        init_x = [[20, 20, 20.4, 20.764, 21.246, 21.528]]
        init_u = [[10., 0., 10., 0., 10., 0., 0., 0., 0., 0., 0.]]
        method = 'lsm'
    else:
        # Простейший адаптивный алгоритм не чувствителен к начальным данным.
        init_x = np.full((1, 7), 20.)  # 6
        init_u = np.zeros((1, 12))  # 11
        method = 'smp'

    idn.init_data(a=np.ones((5, 5)),
                  x=init_x,
                  u=init_u,
                  type_memory='min',
                  memory_size=6)  # 5  6
    algorithm = alg_old.Adaptive(idn, m=method)

    # Создание регулятора и синтез закона управления
    r = Regulator(m)
    r.set_limit(0, 100)
    r.synthesis()
    print('Закон управления:', r.expr)
    print('Аргументы:', r.expr_args)

    n = 240  # количество рабочих тактов
    u_ar = np.zeros((n, ))
    o_ar = np.zeros((n, ))
    a_ar = np.zeros((n, len(a)))
    xt_ar = np.zeros((n, ))
    a_er = np.zeros((n, len(a)))  # массив для сохранения ошибки идентификации

    for i in range(n):
        x = [
            obj(*idn.model.get_var_values(t='x')[0],
                *idn.model.get_var_values(t='u')[0], i)
        ]
        # Идентификация коэффициентов
        # Используется глубокая подстройка на основе приращений (deep_tuning=True),
        # а также адаптивный вес при подстройке свободного коэффициента (aw=True)
        if use_lsm:
            # Использование модели в приращениях uinc=True и
            # адаптивного веса при подстройке свободного коэффициента adaptive_weight=False
            new_a = algorithm.update(x,
                                     w=0.01,
                                     init_weight=0.01,
                                     uinc=True,
                                     adaptive_weight=False)
        else:
            # Использование глубокой подстройки (с использованием модели в приращениях) deep_tuning=True,
            # адаптивного веса aw=True,
            # использование памяти use_memory=True
            new_a = algorithm.update(x,
                                     gamma=1,
                                     gt='a',
                                     weight=0.9,
                                     h=0.1,
                                     deep_tuning=True,
                                     aw=False,
                                     use_memory=True)
            # new_a = idn.avr(new_a, avr_type='efi', l=0.98)
            # new_a = idn.avr(new_a, avr_type='std')

        idn.update_a(new_a)

        # Расчет управляющего воздействия ведется с учетом запаздывания в 5 тактов.
        new_u = r.update(x, xt(i + 6))

        u_ar[i] = new_u[0]
        o_ar[i] = x[0]
        a_ar[i] = new_a
        xt_ar[i] = xt(i)
        a_er[i] = np.array(a) - new_a

        idn.update_x(x)
        idn.update_u(new_u)

    print('Last coefficients:', idn.model.last_a)

    t = np.array([i for i in range(n)])

    # График движенияя объекта
    draw_object_movement(t, o_ar, xt_ar, u_ar)

    # График процесса идентификации
    fig, axs = plt.subplots(nrows=3, ncols=1)
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']

    plot_coefficient(axs[0], t, a_ar[:, 0], a[0], '$t$', '$\\alpha_{0}$',
                     colors[0])

    n_ax = 1
    for i in range(1, 5, 2):
        for k in range(2):
            axs[n_ax].plot(t,
                           a_ar[:, i + k],
                           label=f'$\\alpha_{{{str(i+k)}}}$',
                           linestyle='-',
                           color=colors[k + 1])
            axs[n_ax].plot(t, [a[i + k] for _ in range(n)],
                           linestyle='--',
                           color=colors[k + 1])
        axs[n_ax].set_xlabel('$t$')
        axs[n_ax].set_ylabel(
            f'$\\alpha_{{{str(i)}}},\\alpha_{{{str(i + 1)}}}$',
            rotation='horizontal',
            ha='right')
        axs[n_ax].grid(True)
        l = axs[n_ax].legend(labelspacing=0, borderpad=0.3)
        l.set_draggable(True)
        n_ax += 1

    # График ошибки идентификации
    fig, axs = plt.subplots(nrows=1, ncols=1)
    if a_er is not None:
        for i in range(len(a_er[0])):
            axs.plot(t,
                     a_er[:, i],
                     label=f'$e_{{\\alpha_{i}}}$',
                     linestyle='-',
                     color=colors[i])
        axs.set_xlabel('$t$')
        axs.grid(True)
        axs.legend()

    plt.show()
示例#9
0
def example_2(with_err=False):
    """
    Пример использования библиотеки CotPy для синтеза 
    закона адаптивного управления. 
    Для идентификации используется стандартный алгоритм метода наименьших квадратов. 
    Модель простая с небольшой инерцией.
    :param with_err: если True добавляется аддитивная равномерно распределенная помеха 
                     амплитудой 0.4 к измерению выхода объекта
    :return: None
    """

    a = [-10, 0.3, 0.1, 3]

    def obj(x1, x2, u):
        """Функция имитации объекта."""
        val = a[0] + a[1] * x1 + a[2] * x2 + a[3] * u
        if with_err:
            return val + np.random.uniform(-0.2, 0.2)
        else:
            return val

    def xt(j):
        """Функция генерации уставки."""
        if j < 10:
            return 10
        elif 10 <= j < 15:
            return 100
        elif 15 <= j <= 20:
            return 250
        else:
            return 50

    expr = "a0+a1*x(t-1)+a2*x(t-2)+a3*u(t-1)"
    m = model.create_model(expr)
    idn = identifier.Identifier(m)

    # значения коэффициентов 'a' выставляем равными 1 (можно не
    # передавать вовсе, тогда по умолчанию инициализируется единицами)
    # либо другими предполагаемыми значениями.
    idn.init_data(x=[[0, 0, -10, -10, -11]], u=[[0, 1, 1, 1]])
    lsm = alg_old.Adaptive(idn, m='lsm')

    r = Regulator(m)
    r.set_limit(0, 255)
    r.synthesis()

    n = 30
    u_ar = np.zeros((n, ))
    o_ar = np.zeros((n, ))
    a_ar = np.zeros((n, len(a)))
    xt_ar = np.zeros((n, ))

    for i in range(n):
        x = [
            obj(*idn.model.get_var_values(t='x')[0],
                *idn.model.get_var_values(t='u')[0])
        ]

        new_a = lsm.update(x, w=0.01, init_weight=0.01)
        idn.update_a(new_a)

        new_u = r.update(x, xt(i + 1))

        u_ar[i] = new_u[0]
        o_ar[i] = x[0]
        a_ar[i] = new_a
        xt_ar[i] = xt(i)

        idn.update_x(x)
        idn.update_u(new_u)

    print('Last coefficients:', idn.model.last_a)

    t = np.array([i for i in range(n)])

    draw_object_movement(t, o_ar, xt_ar, u_ar)

    # График процесса идентификации
    fig, axs = plt.subplots(nrows=3, ncols=1)
    prop_cycle = plt.rcParams['axes.prop_cycle']
    colors = prop_cycle.by_key()['color']

    plot_coefficient(axs[0], t, a_ar[:, 0], a[0], '$t$', '$\\alpha_{0}$',
                     colors[0])

    for i in range(1, 3):
        axs[1].plot(t,
                    a_ar[:, i],
                    label=f'$\\alpha_{{{str(i)}}}$',
                    linestyle='-',
                    color=colors[i])
        axs[1].plot(t, [a[i] for _ in range(n)],
                    linestyle='--',
                    color=colors[i])
    axs[1].set_xlabel('$t$')
    axs[1].set_ylabel('$\\alpha_{1},\\alpha_{2}$',
                      rotation='horizontal',
                      ha='right')
    axs[1].grid(True)
    l = axs[1].legend(labelspacing=0, borderpad=0.3)
    l.set_draggable(True)

    plot_coefficient(axs[2], t, a_ar[:, 3], a[3], '$t$', '$\\alpha_{3}$',
                     colors[1])

    plt.show()