Community Engee

Идентификация объекта САУ с нечетким ПИД-регулятором

作者
avatar-svetlanasvetlana
Notebook

Идентификация объекта системы управления с нечетким ПИД-регулятором

В этом примере решается сразу две задачи. Во-первых, мы идентифицируем объект управления на основе экспериментальных данных. Во-вторых, реализуем систему нечёткого вывода для ПИД-регулятора.

In [ ]:
EngeePkg.purge()
In [ ]:
Pkg.add(["ControlSystemIdentification", "FuzzyLogic"])
using ControlSystemIdentification, FuzzyLogic

Напомню, что рабочий процесс идентификации выглядит следующим образом:

  1. Сбор данных эксперимента

  2. Выбор структуры модели

  3. Идентификация модели

  4. Валидация модели

Идентификация объекта управления

Сбор экспериментальных данных с объекта управления

Имитация экспериментальной установки объекта управления представлена в модели plant.engee. Объект управления - это дискретная система с одним входом и одним выходом. Также в модель добавлен шум и небольшое запаздывание.

Идентификация объекта будет производиться по переходному процессу, для этого на вход системы подадим ступеньку.

Plant--1753359832841.png

Запишем данные для идентификации:

In [ ]:
mode = 1; # Запись данных для идентификации
if "Plant" in [m.name for m in engee.get_all_models()]
    m = engee.open( "Plant" ) # загрузка модели
else
    m = engee.load( "Plant.engee" )
end
results = engee.run(m, verbose=true)
Building...
Progress 0%
Progress 100%
Progress 100%
Out[0]:
SimulationResult(
    run_id => 1,
    "out" => WorkspaceArray{Float64}("Plant/out")
,
    "in" => WorkspaceArray{Float64}("Plant/in")

)
In [ ]:
dataout = collect(results["out"]);
datain = collect(results["in"]);
# Частота дискретизации системы из вектора времени
Ts = dataout.time[2] - dataout.time[1]
ident_data = iddata(dataout.value, datain.value, Ts)
plot(ident_data)
Out[0]:

Запишем данные для валидации модели:

In [ ]:
mode = 0; # Запись данных для валидации
if "Plant" in [m.name for m in engee.get_all_models()]
    m = engee.open( "Plant" ) # загрузка модели
else
    m = engee.load( "Plant.engee" )
end
results = engee.run(m, verbose=true)
Building...
Progress 0%
Progress 100%
Progress 100%
Out[0]:
SimulationResult(
    run_id => 2,
    "out" => WorkspaceArray{Float64}("Plant/out")
,
    "in" => WorkspaceArray{Float64}("Plant/in")

)
In [ ]:
dataout = collect(results["out"]);
datain = collect(results["in"]);
# Частота дискретизации системы из вектора времени
Ts = dataout.time[2] - dataout.time[1]
val_data = iddata(dataout.value, datain.value, Ts)
plot(val_data)
Out[0]:

Выбор структуры модели и идентификация

Будем идентифицировать линейную стационарную систему в пространстве состояний. Порядок системы выберем равным 3.

Для идентификации выберем метод ошибки прогнозирования PEM ( prediction-error method). Это простой, но эффективный алгоритм идентификации линейных стационарных систем с дискретным временем в форме пространства состояний. Метод также позволяет получить начальные состояния системы.

In [ ]:
nx = 3
sys_obj = subspaceid(ident_data, nx; r = 20);
sys, x0 = newpem(
    ident_data, nx;
    sys0   = sys_obj.sys,   # модель из subspaceid
    focus  = :simulation
);
Warning: x_tol is deprecated. Use x_abstol or x_reltol instead. The provided value (0) will be used as x_abstol.
@ Optim /usr/local/ijulia-demos/packages/Optim/gmigl/src/types.jl:110
Iter     Function value   Gradient norm 
     0     6.209732e-03     1.261412e+00
 * time: 0.0360410213470459
    50     2.080925e-04     4.100484e-03
 * time: 1.891798973083496
   100     2.061785e-04     4.294817e-04
 * time: 1.9036390781402588
   150     2.059015e-04     4.564776e-04
 * time: 1.9153389930725098
   200     2.058087e-04     2.349875e-04
 * time: 1.9857029914855957

Валидация модели

Проверим идентификацию на тех же данных, на которых проводилась идентификация

In [ ]:
simplot(ident_data, sys)
Out[0]:

И проверим на специальном валидационном наборе данных

In [ ]:
simplot(val_data, sys)
Out[0]:

Метод показал хороший результат идентификации.

Система управления с нечетким ПИД-регулятором

Вернемся к моделированию системы управления с нечетким контроллером. Мы получили модель объекта управления из экспериментальных данных.

Fuzzycontroller--1753369066574.png

Результат идентификации будет использоваться в блоке Дискретное пространство состояний (Discrete State Space) для моделирования объекта управления.

Fuzzycontroller--1753369100219.png

Осталось добавить контроллер в контур системы управления. В этом примере используется следующая структура контроллера с нечёткой логикой:

Fuzzycontroller--1753362744936.png

На вход системы нечеткого вывода поступают нормализованные значения ошибки и производной ошибки . Входные значения нормализуются с помощью коэффициентов масштабирования и так, чтобы они находились в диапазоне [-1,1].

Система нечеткого вывода выдает результат в диапазоне [-1, 1], который масштабируется коэффициентами и .

In [ ]:
CE = 10;
CD = 4.9829;
C0 = 2.5179;
C1 = 1.8103;

Система нечеткого вывода представлена в виде блока Табличной функции (Lookup table). Процесс формирования поверхности отклика для этой таблицы показан ниже:

In [ ]:
fis = @sugfis function FCtrl(E, delE)::U
    E := begin
        domain = -10.0:10.0
        N = GaussianMF(-10.0, 7.0)
        P = GaussianMF(10.0, 7.0)
    end

    delE := begin
        domain = -10.0:10.0
        N = GaussianMF(-10.0, 7.0)
        P = GaussianMF(10.0, 7.0)
    end    

    U := begin
        domain = -20.0:20.0
        Min = -20.0
        Zero = 0.0
        Max  = 20.0
    end

   # Работающие правила
   E == N  && delE == N  -->  U == Min
   E == N  && delE == P  -->  U == Zero
   E == P  && delE == N  -->  U == Zero
   E == P  && delE == P  -->  U == Max

end;
In [ ]:
plot(fis, :E, ylabel="Функция принадлежности", w = 2)
Out[0]:
In [ ]:
plot(fis, :delE, ylabel="Функция принадлежности", w = 2)
Out[0]:

Сформируем поверхность отклика для того, чтобы поместить ее в блок Табличной функции (Lookup table).

In [ ]:
errBrkpts = -10.0:0.5:10.0 
rateBrkpts = -10.0:0.5:10.0
LookUpTableData = zeros(length(errBrkpts), length(rateBrkpts))
i = 0;
for e in errBrkpts
    i = i+1
    j = 0;
    for de in rateBrkpts
        j = j+1
        LookUpTableData[i, j] = fis([e, de])[:U]
    end
end
surface(errBrkpts, rateBrkpts, LookUpTableData, xlabel="ΔE", ylabel="E", zlabel="U", title="Поверхность отклика", camera=(30, 30))
Out[0]:

Запустим модель системы управления и проверим работу регулятора.

In [ ]:
if "Fuzzycontroller" in [m.name for m in engee.get_all_models()]
    m = engee.open( "Fuzzycontroller" ) # загрузка модели
else
    m = engee.load( "Fuzzycontroller.engee" )
end
fuzzyresults = engee.run(m, verbose=true)
Building...
Progress 0%
Progress 100%
Progress 100%
Out[0]:
SimulationResult(
    run_id => 3,
    "out" => WorkspaceArray{Float64}("Fuzzycontroller/out")
,
    "in" => WorkspaceArray{Float64}("Fuzzycontroller/in")

)
In [ ]:
fuzzydataout = collect(fuzzyresults["out"]);
fuzzydatain = collect(fuzzyresults["in"]);

На графики мы видим реакцию системы управления на ступенчатое воздействие.

In [ ]:
plot(fuzzydataout.time, fuzzydataout.value, titel = "Система управления с нечетким ПИД-регулятором", label="выход")
plot!(fuzzydatain.time, fuzzydatain.value, label="вход")
Out[0]:

Вывод

В результате мы получили работающую систему управления с нечетким ПИД-регулятором. Модель объекта управления не была заранее известна, а получена идентификацией на основе экспериментальных данных.