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)
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)
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)
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)
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()
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])
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()
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()
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()