Постановка задач
Решётчатые функции определены в дискретные моменты времени, которые, в общем случае, могут находиться на разном расстоянии друг от друга. Пусть — шаг решётки, тогда, в общем случае, . Для нас наиболее интересна ситуация когда . Это соответствует характеру работы аналого-цифрового преобразователя (АЦП) управляющего цифрового устройства, когда значения технологического параметра преобразуются в цифровой формат с некоторой дискретностью. Последовательность таких значений описывает непрерывную функцию технологического параметра в решётчатом виде.
Линейная регрессия показала себя исключительно хорошо в решении задач машинного обучения и прогнозирования данных на некоторое время вперёд по ретроспективным данным. Линейная регрессия обладает низкими накладными вычислительными расходами, поэтому крайне привлекательна для решения задач моделирования изменений технологических параметров в режиме реального времени.
Выделим следующие задачи:
Прямую, которая сводится к применению линейной регрессии для расчёта последовательных значений решётчатой функции на основании дифференциального уравнения типового звена.
Обратная, которая сводится к определению коэффициентов линейной регрессии по временным рядам решётчатой функции.
Выбор метрики
На практике широко используются относительная и приведённая погрешности.
Относительная погрешность чаще всего рассчитывается в процентах:
где — измеренное значение параметра в текущий момент времени, — истинное значение параметра в этот момент времени.
Для подсчитанных значений относительной погрешности можно рассчитать среднюю относительную погрешность на данных измерениях:
Назовем среднюю относительную погрешность метрикой MLE — Mean reLative Error.
Смысл MLE практически осязаем — они показывают среднее отклонение прогнозной / измеренной величины от истинного значения, выраженное в процентах. Однако они имеют очевидный существенный недостаток — их значение не определено или равно бесконечности, когда истинное значение величины равно или очень близко к нулю.
Приведённая погрешность также чаще всего вычисляется в процентах:
где — измеренное значение параметра в текущий момент времени, — нормирующее значение, равное диапазону изменения измеряемой величины или, иными словами, шкале измерительного прибора.
Средняя приведённая погрешность:
Назовем среднюю приведённую погрешность метрикой MRE — Mean Reduced Error.
MRE, как и MLE, имеет ясный физический смысл — она показывает насколько в среднем в процентах отклонилась прогнозная / измеренная величина от диапазона изменения / шкалы прибора истинной величины. Величина всегда больше нуля. Поэтому MRE лишена недостатков MLE и может быть смело использована для оценки качества прогноза.
Hidden text
def MRE(y_true, y_pred, arr=False):
"""
Средняя приведенная к диапазону изменения переменной ошибка
y_true - истинное значение
y_pred - прогнозное значение
arr - массив значений абсолютной ошибки, в долях единицы
к истинному значению:
True - вернуть
False - не возвращать
По умолчанию возвращает среднюю абсолютную процентную ошибку, %
"""
y_t = list(y_true)
y_p = list(y_pred)
interval = max(y_t) - min(y_t)
mre = []
for i in range(len(y_t)):
mre.append(np.abs((y_t[i] - y_p[i]) / interval))
if arr:
return mre
else:
if np.isinf(np.mean(mre)):
return BIGNUM
else:
return np.mean(mre) * 100
Моделирование типовых динамических звеньев
# Импорт библиотек
import math
import sys
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import control as ct
BIGNUM = sys.maxsize
s = ct.tf('s') # Оператор передаточной функции в преобразовании Лапласа
mt = 100 # Время моделирования, с
hp = 0.1 # Шаг решетчатой функции, с
mtl = [i * hp for i in np.arange(int(math.ceil((mt + hp)/hp)))] # ВременнАя шкала моделирования, с
Апериодическое звено 1-го порядка
k = 1
T = 15
A1 = (k) / (T * s + 1)
t, y_A1 = ct.step_response(A1, T=mtl)
Апериодическое звено 2-го порядка
k = 1
T1 = 20
T2 = 10
A2 = (k) / (T2**2 * s**2 + T1 * s + 1)
t, y_A2 = ct.step_response(A2, T=mtl)
Колебательное звено
k = 1
T = 4
ksi = 0.25
Ksi = (k) / (T**2 * s**2 + 2 * ksi * T * s + 1)
t, y_Ksi = ct.step_response(Ksi, T=mtl)
Консервативное звено
k = 0.75
T = 4
Cons = (k) / (T**2 * s**2 + 1)
t, y_Cons = ct.step_response(Cons, T=mtl)
Аддитивный белый гауссовский шум
Измеренное значение технологического параметра, в общем случае, будет отличаться от истинного. Это связано с ограниченной точностью измерительных приборов, внешними воздействиями на каналы передачи данных, ограниченной точностью преобразователя полученной информации и т.д. Погрешность измерения показывает, что эти отклонения измерений от истинных значений не будут превышать некоторой величины. Отклонения носят случайный характер как по величине, так и по знаку и статистически не зависят от истинного значения параметра, т.е. носят характер аддитивного белого гауссовского шума.
Ступенчатое гауссовское возмущение
В качестве возмущающего будем применять стахостическое (гауссовское) ступенчатое воздействие. Назовём его функцией Хевисайда-Гаусса.
Моделирование линейной регрессией типовых динамических звеньев
Динамические свойства звеньев будем описывать соответствующими дифференциальными уравнениями (ДУ). Затем будем переходить к формам ДУ для решётчатых функций и строить на их основе итерируемые схемы прогнозирования очередного значения функции.
Для нахождения дифференциалов решётчатых функций широко применяются численные методы.
Дифференциалы (производные) решётчатой функции будем обозначать, как .
Используя формулу Лагранжа для случая равных промежутков формула численного дифференцирования производной первого порядка с четвёртым порядком погрешности примет вид:
Производная второго порядка с третьим порядком погрешности примет вид:
Апериодическое звено 1-го порядка
А-звено 1-го порядка (А1-звено) описывается следующим дифференциальным уравнением:
Для решётчатой функции данное уравнение примет вид:
Применяя формулы Тейлора, для -го значения решётчатой функции дифференциальное уравнение звена примет вид:
Тогда:
hp = 0.1
k = 1
T = 15
x_t = [next(pg) for i in mtl]
t, y_A1 = ct.forced_response(A1, T=mtl, U=x_t)
C1 = 12 * k * hp / (25 * T + 12 * hp)
C2 = 48 / (25 + 12 * hp / T)
C3 = 36 / (25 + 12 * hp / T)
C4 = 16 / (25 + 12 * hp / T)
C5 = 3 / (25 + 12 * hp / T)
y_A1_lr = [0, 0, 0, 0] # Нулевые начальные условия
for i in range(0, len(x_t)):
y_A1_lr.append(
C1 * x_t[i] + C2 * y_A1_lr[-1] - C3 * y_A1_lr[-2] + C4 * y_A1_lr[-3] - C5 * y_A1_lr[-4]
)
y_A1_lr = y_A1_lr[4:]
Апериодическое звено 2-го порядка
А-звено 2-го порядка описывается (А2-звено) следующим дифференциальным уравнением:
Для решётчатой функции данное уравнение примет вид:
Для решётчатой функции данное уравнение примет вид:
Тогда:
k = 1
T1 = 20
T2 = 10
x_t = [next(pg) for i in mtl]
t, y_A2 = ct.forced_response(A2, T=mtl, U=x_t)
_d = (35 * T2**2) / (12 * hp**2) + (25 * T1) / (12 * hp) + 1
C1 = k / _d
C2 = ((104 * T2**2) / (12 * hp**2) + (48 * T1) / (12 * hp)) / _d
C3 = ((114 * T2**2) / (12 * hp**2) + (36 * T1) / (12 * hp)) / _d
C4 = ((56 * T2**2) / (12 * hp**2) + (16 * T1) / (12 * hp)) / _d
C5 = ((11 * T2**2) / (12 * hp**2) + (3 * T1) / (12 * hp)) / _d
y_A2_lr = [0, 0, 0, 0] # Нулевые начальные условия
for i in range(0, len(x_t)):
y_A2_lr.append(
C1 * x_t[i] + C2 * y_A2_lr[-1] - C3 * y_A2_lr[-2] + C4 * y_A2_lr[-3] - C5 * y_A2_lr[-4]
)
y_A2_lr = y_A2_lr[4:]
Колебательное звено
Колебательное звено (-звено) описывается следующим дифференциальным уравнением:
Для решётчатой функции данное уравнение примет вид:
Применяя формулы Тейлора, для -го значения решётчатой функции дифференциальное уравнение звена примет вид:
Тогда:
k = 1
T = 4
ksi = 0.25
x_t = [next(pg) for i in mtl]
t, y_Ksi = ct.forced_response(Ksi, T=mtl, U=x_t)
_d = (35 * T**2) / (12 * hp**2) + (50 * ksi * T) / (12 * hp) + 1
C1 = k / _d
C2 = ((104 * T**2) / (12 * hp**2) + (96 * ksi * T) / (12 * hp)) / _d
C3 = ((114 * T**2) / (12 * hp**2) + (72 * ksi * T) / (12 * hp)) / _d
C4 = ((56 * T**2) / (12 * hp**2) + (32 * ksi * T) / (12 * hp)) / _d
C5 = ((11 * T**2) / (12 * hp**2) + (6 * ksi * T) / (12 * hp)) / _d
y_Ksi_lr = [0, 0, 0, 0] # Нулевые начальные условия
for i in range(0, len(x_t)):
y_Ksi_lr.append(
C1 * x_t[i] + C2 * y_Ksi_lr[-1] - C3 * y_Ksi_lr[-2] + C4 * y_Ksi_lr[-3] - C5 * y_Ksi_lr[-4]
)
y_Ksi_lr = y_Ksi_lr[4:]
Консервативное звено
Консервативное звено (-звено) описывается следующим дифференциальным уравнением:
Для решётчатой функции данное уравнение примет вид:
Применяя формулы Тейлора, для -го значения решётчатой функции дифференциальное уравнение звена примет вид:
Тогда:
k = 0.75
T = 4
x_t = [next(pg) for i in mtl]
t, y_Cons = ct.forced_response(Cons, T=mtl, U=x_t)
C1 = 12 * k * hp**2 / (35 * T**2 + 12 * hp**2)
C2 = 104 / (35 + 12 * hp**2 / T**2)
C3 = 114 / (35 + 12 * hp**2 / T**2)
C4 = 56 / (35 + 12 * hp**2 / T**2)
C5 = 11 / (35 + 12 * hp**2 / T**2)
y_Cons_lr = [0, 0, 0, 0] # Нулевые начальные условия
for i in range(0, len(x_t)):
y_Cons_lr.append(
C1 * x_t[i] + C2 * y_Cons_lr[-1] - C3 * y_Cons_lr[-2] + C4 * y_Cons_lr[-3] - C5 * y_Cons_lr[-4]
)
y_Cons_lr = y_Cons_lr[4:]
Первые результаты качества моделирования типовых динамических звеньев линейной регрессией получены.
# A1-звено
MRE(y_A1, y_A1_lr)
0.037048140997006936
# A2-звено
MRE(y_A2, y_A2_lr)
0.04460863218205424
#Ksi-звено
MRE(y_Ksi, y_Ksi_lr)
0.013608750809221084
#Cons-звено
MRE(y_Cons, y_Cons_lr)
0.026759652627513193
Поскольку на практике чаще встречаются технологические параметры, описываемые ДУ второго и более высоких порядков и поскольку колебательное и консервативное звенья являются частными случаями А2-звена, далее будем исследовать А2-звено.
Определение коэффициентов линейной регрессии по временным рядам решётчатой функции
Поиск параметров аналитическим способом если и возможен, то крайне затруднителен. В конечном итоге он сводится к подбору таких значений , при которых MRE минимальна. Иными словами:
и наша задача — .
Параметры рассчитываются как комбинации параметров звена, в случае -звена — . Тогда:
Задача — задача поиска глобального минимума функции трёх переменных.
Для поиска глобального минимума функции нескольких переменных воспользуемся, например, функцией minimize()
библиотеки scipy
.
Hidden text
from scipy.optimize import minimize
def f_A2(n, *args):
'''
Функция проверки коэффициентов A2-звена
n - параметры звена
args[0] - x - входные данные (возмущение)
args[1] - y - выходные данные (реакция)
hp - шаг решётчатой функции
p - глубина истории, n-1 для n-точечного шаблона
'''
x = args[0].copy()
y = args[1].copy()
hp = 0.1
p = 4
k = n[0]
T1 = n[1]
T2 = n[2]
_d = (35 * T2**2) / (12 * hp**2) + (25 * T1) / (12 * hp) + 1
C1 = k / _d
C2 = ((104 * T2**2) / (12 * hp**2) + (48 * T1) / (12 * hp)) / _d
C3 = ((114 * T2**2) / (12 * hp**2) + (36 * T1) / (12 * hp)) / _d
C4 = ((56 * T2**2) / (12 * hp**2) + (16 * T1) / (12 * hp)) / _d
C5 = ((11 * T2**2) / (12 * hp**2) + (3 * T1) / (12 * hp)) / _d
x_t = x
y_t = args[2].copy() # Начальные условия
for i in range(0, len(x_t)): # Учет нулевых начальных значений -- y(x_t) = 0
y_t.append(C1 * x_t[i]
+ C2 * y_t[-1]
- C3 * y_t[-2]
+ C4 * y_t[-3]
- C5 * y_t[-4]
)
y_t = y_t[p:]
return MRE(y, y_t)
x_t = [next(pg) for i in mtl]
t, y_A2 = ct.forced_response(A2, T=mtl, U=x_t)
Проверим работоспособность подхода на ненулевых исходных данных.
res = minimize(f_A2,
[0.01, 0.01, 0.01],
args=(x_t, y_A2, [0, 0, 0, 0]),
method="Powell",
options={'xtol': 1e-8, 'disp': True},
bounds=[(0.01, 5), (0.01, 30), (0.01, 20)])
print('\nMRE:', res.fun)
print('k:', res.x[0])
print('T1:', res.x[1])
print('T2:', res.x[2])
#--------------------------------------
# Optimization terminated successfully.
# Current function value: 0.128574
# Iterations: 13
# Function evaluations: 1505
#
# MRE: 0.12857363263770344
# k: 0.9997163477435754
# T1: 19.998935106980777
# T2: 9.9991512679897
Проверим работоспособность подхода на ненулевых исходных данных.
j = 100
res = minimize(f_A2,
[0.01, 0.01, 0.01],
args=(x_t[j:], y_A2[j:], [y_A2[j-4], y_A2[j-3], y_A2[j-2], y_A2[j-1]]),
method="Powell",
options={'xtol': 1e-8, 'disp': True},
bounds=[(0.01, 5), (0.01, 30), (0.01, 20)])
print('\nMRE:', res.fun)
print('k:', res.x[0])
print('T1:', res.x[1])
print('T2:', res.x[2])
#--------------------------------------
# Optimization terminated successfully.
# Current function value: 0.000829
# Iterations: 9
# Function evaluations: 999
#
# MRE: 0.0008285555371525098
# k: 0.9999871396033223
# T1: 19.99983473603636
# T2: 9.99994226212653
Полученный результат практически идеален.
Зашумлённые данные
Выше было отмечено, что реальные измеренные значения параметров близки к аддитивному гауссовскому шуму. Гауссовский шум вносит нелинейность в значения решётчатой функции, что ухудшает точность результатов по поиску параметров звена. Покажем это.
x_t = [next(pg) for i in mtl]
t, y_A2 = ct.forced_response(A2, T=mtl, U=x_t)
ln = max(abs(max(y_A2)), abs(min(y_A2))) * 0.1
y_A2_g = [y_A2[i]+gauss()*ln for i in range(len(mtl))]
j = 100
res = minimize(f_A2,
[0.01, 0.01, 0.01],
args=(x_t[j:], y_A2_g[j:], [y_A2_g[j-4], y_A2_g[j-3], y_A2_g[j-2], y_A2_g[j-1]]),
method="Powell",
options={'xtol': 1e-8, 'disp': True},
bounds=[(0.01, 5), (0.01, 30), (0.01, 20)])
print('\nMRE:', res.fun)
print('k:', res.x[0])
print('T1:', res.x[1])
print('T2:', res.x[2])
#--------------------------------------
# Optimization terminated successfully.
# Current function value: 2.530822
# Iterations: 6
# Function evaluations: 676
#
# MRE: 2.5308224410672238
# k: 1.014091723635805
# T1: 20.44728805919973
# T2: 10.622387452988548
Полученные результаты будут ухудшаться при росте амплитуды аддитивного гауссовского шума. Это связано с тем, что начальные условия -- четыре значения функции до момента начала прогнозирования -- не совпадают с истинными.
Обозначим как значения начальных условий. Тогда задача примет вид:
Hidden text
def f_A2_g(n, *args):
'''
Функция проверки коэффициентов A2-звена
n - параметры звена, начальные условия
args[0] - x - входные данные (возмущение)
args[1] - y - выходные данные (реакция)
hp - шаг решётчатой функции
p - глубина истории, n-1 для n-точечного шаблона
'''
x = args[0].copy()
y = args[1].copy()
hp = 0.1
p = 4
k = n[0]
T1 = n[1]
T2 = n[2]
_d = (35 * T2**2) / (12 * hp**2) + (25 * T1) / (12 * hp) + 1
C1 = k / _d
C2 = ((104 * T2**2) / (12 * hp**2) + (48 * T1) / (12 * hp)) / _d
C3 = ((114 * T2**2) / (12 * hp**2) + (36 * T1) / (12 * hp)) / _d
C4 = ((56 * T2**2) / (12 * hp**2) + (16 * T1) / (12 * hp)) / _d
C5 = ((11 * T2**2) / (12 * hp**2) + (3 * T1) / (12 * hp)) / _d
x_t = x
y_t = [n[3], n[4], n[5], n[6]] # Начальные условия
for i in range(0, len(x_t)): # Учет нулевых начальных значений -- y(x_t) = 0
y_t.append(C1 * x_t[i]
+ C2 * y_t[-1]
- C3 * y_t[-2]
+ C4 * y_t[-3]
- C5 * y_t[-4]
)
y_t = y_t[p:]
return MRE(y, y_t)
x_t = [next(pg) for i in mtl]
t, y_A2 = ct.forced_response(A2, T=mtl, U=x_t)
ln = max(abs(max(y_A2)), abs(min(y_A2))) * 0.1
y_A2_g = [y_A2[i]+gauss()*ln for i in range(len(mtl))]
j = 100
max_v = max(y_A2_g[j-4],
y_A2_g[j-3],
y_A2_g[j-2],
y_A2_g[j-1])
min_v = min(y_A2_g[j-4],
y_A2_g[j-3],
y_A2_g[j-2],
y_A2_g[j-1])
mean_v = (min_v + max_v) / 2
res = minimize(f_A2_g,
[0.01, 0.01, 0.01, mean_v, mean_v, mean_v, mean_v],
args=(x_t[j:], y_A2_g[j:]),
method="Powell",
options={'xtol': 1e-12, 'disp': True},
bounds=[(0.01, 5), (0.01, 30), (0.01, 20), (min_v, max_v), (min_v, max_v), (min_v, max_v), (min_v, max_v)])
print('\nMRE:', res.fun)
print('k:', res.x[0])
print('T1:', res.x[1])
print('T2:', res.x[2])
#--------------------------------------
# Optimization terminated successfully.
# Current function value: 2.318385
# Iterations: 8
# Function evaluations: 2286
#
# MRE: 2.318384907285262
# k: 0.9939295663300647
# T1: 19.81697562916168
# T2: 9.959654243923332
x_t = [next(pg) for i in mtl]
t, y_A2 = ct.forced_response(A2, T=mtl, U=x_t)
ln = max(abs(max(y_A2)), abs(min(y_A2))) * 0.5
y_A2_g = [y_A2[i]+gauss()*ln for i in range(len(mtl))]
j = 100
max_v = max(y_A2_g[j-4],
y_A2_g[j-3],
y_A2_g[j-2],
y_A2_g[j-1])
min_v = min(y_A2_g[j-4],
y_A2_g[j-3],
y_A2_g[j-2],
y_A2_g[j-1])
mean_v = (min_v + max_v) / 2
res = minimize(f_A2_g,
[0.01, 0.01, 0.01, mean_v, mean_v, mean_v, mean_v],
args=(x_t[j:], y_A2_g[j:]),
method="Powell",
options={'xtol': 1e-12, 'disp': True},
bounds=[(0.01, 5), (0.01, 30), (0.01, 20), (min_v, max_v), (min_v, max_v), (min_v, max_v), (min_v, max_v)])
print('\nMRE:', res.fun)
print('k:', res.x[0])
print('T1:', res.x[1])
print('T2:', res.x[2])
#--------------------------------------
# Optimization terminated successfully.
# Current function value: 9.330137
# Iterations: 6
# Function evaluations: 1751
#
# MRE: 9.330136803293637
# k: 1.0239929423715524
# T1: 20.242199361067595
# T2: 10.38718689811098
x_t = [next(pg) for i in mtl]
t, y_A2 = ct.forced_response(A2, T=mtl, U=x_t)
ln = max(abs(max(y_A2)), abs(min(y_A2))) * 1.0
y_A2_g = [y_A2[i]+gauss()*ln for i in range(len(mtl))]
j = 100
max_v = max(y_A2_g[j-4],
y_A2_g[j-3],
y_A2_g[j-2],
y_A2_g[j-1])
min_v = min(y_A2_g[j-4],
y_A2_g[j-3],
y_A2_g[j-2],
y_A2_g[j-1])
mean_v = (min_v + max_v) / 2
res = minimize(f_A2_g,
[0.01, 0.01, 0.01, mean_v, mean_v, mean_v, mean_v],
args=(x_t[j:], y_A2_g[j:]),
method="Powell",
options={'xtol': 1e-12, 'disp': True},
bounds=[(0.01, 5), (0.01, 30), (0.01, 20), (min_v, max_v), (min_v, max_v), (min_v, max_v), (min_v, max_v)])
print('\nMRE:', res.fun)
print('k:', res.x[0])
print('T1:', res.x[1])
print('T2:', res.x[2])
#--------------------------------------
# Optimization terminated successfully.
# Current function value: 10.792331
# Iterations: 8
# Function evaluations: 2412
#
# MRE: 10.792331083024271
# k: 0.9866685845822787
# T1: 19.643955217189404
# T2: 7.761183216604419
Полученные результаты вычисления значений параметров А2-звена вполне удовлетворительны даже при сильном зашумлении данных.
Применение описанных подходов и инструментов к реальным данным, вполне очевидно, выявит новые проблемы и трудности в интерпретации и детерминировании параметров звений, которые заставят искать пути их решения. На текущий момент есть инструменты, которые облегчат поиски эти путей, например, инструменты поиска глобального минимума функции в библиотеке scipy
, библиотеки pygad
и pyomo
, которые для поиска глобального минимума функции многих переменных используют нейросетевые инструменты.
Итоги
Основной посыл статьи -- демонстрация возможности детерминирования динамических свойств технологических параметров, описываемых решётчатыми функциями, и возможности прогнозирования изменения значений этих параметров, применяя простые, а оттого высокопроизводительные вычислительные инструменты.
Эти возможности позволят решить, например, следующие практические задачи:
реализация алгоритма автоматической настройки регуляторов систем автоматического регулирования по известным динамическим свойствам объекта управления;
реализация алгоритма предиктивного ПИД-регулятора, в котором наряду с П-, И-, Д- компонентами присутствует компонента прогноза изменения регулируемого технологического параметра;
-
создание модели технологического многопараметрического объекта управления, работающей в режиме реального времени, которая позволяет решить следующие задачи:
проведение исследований и экспериментов над технологическим объектом управления при разработке новых решений в управлении;
создание полнофункциональных тренажёрных комплексов систем управления реальными технологическими объектами;
создание систем прогнозирования хода технологического процесса и формирование рекомендаций оператору по безопасному и более эффективному его ведению.
Использованная литература
Ротач, В. Я. Теория автоматического управления теплоэнергетическими процессами: Учебник для вузов. — М.: Энергоатомиздат. 1985. — 296 с., ил.
Киреев В. И., Пантелеев А. В. Численные методы в примерах и задачах: Учебное пособие. — 4-е изд., испр. — СПб.: Издательство «Лань», 2015. — 448 с.: ил. — (Учебники для вузов. Специальная литература).
Калиткин Н. Н., Численные методы: учеб. пособие. — 2-е изд., исправленное. — СПб.: БХВ-Петербург, 2011. — 592 с.: ил. — (Учебная литература для вузов)
Березин, И. С., Жидков Н. П. Методы вычислений. — 2-е изд. — М.: Физматлит, 1962. — Т. I.