Система управления теплицей
Система управления теплицей
Задача системы управления теплицей состоит в поддержании в теплице заданных значений температуры и влажности. Система управления состоит из регуляторов и объекта управления. В данной модели регуляторы представлены двумя нечеткими логическими контроллерами — по одному для температуры (Heater Control) и влажности (Humidity Control), а объект управления — математической моделью теплицы (Greenhouse).
Схема модели в Engee:

Объект управления — подсистема Greenhouse
Поскольку предполагается управление двумя показателями — температурой и влажностью — подсистема теплицы разделена на две подсистемы: Termal Model и Humidity Model соответственно.

Математическая модель изменения температуры — подсистема Termal Model
Подсистема принимает два входных сигнала: Heater и Ventilation, обозначающие воздействие системы отопления и воздействие системы вентиляции соответственно, — и возвращает два выходных сигнала: OutsideTemperature и InsideTemperature, обозначающие значение температуры снаружи и внутри теплицы соответственно.
Дифференциальное уравнение, описывающее изменение температуры в теплице, имеет следующий вид:
где:
- — Плотность воздуха внутри, ;
- — Удельная теплоемкость воздуха, ;
- — Объем теплицы, ;
- — Температура внутри, ℃;
- — Тепло, полученное от коротковолнового излучения;
- — Конвекционные и конденсационные тепловые потери;
- — Тепловые потери от проникновения тепла через покрытие наружу;
- — Длинноволновые тепловые потери;
- — Тепло, полученное от системы отопления;
- — Тепловые потери от системы вентиляции.
Схема модели в Engee:
.png)
Рамкой на схеме выделены настраиваемые параметры системы:
V— Объем теплицы, ;L— Длина теплицы, ;S— Площадь поверхности, ;alpha_c— Поглощающая способность покрытия;tau_c— Пропускная способность покрытия;L_c— Толщина покрытия, ;K_c— Коэффициент покрытия; ;S_c— Площадь теплицы, ;R— Воздухообмен в час, ;p_out— Давление насыщенного пара снаружи;p_in— Давление насыщенного пара внутри;C_e— Коэффициент переноса водяного пара;rho_a— Плотность воздуха внутри, ;C_a— Удельная теплоемкость воздуха, ;N_h— Число обогревателей.
Математическая модель изменения влажности — подсистема Humidity Model
Подсистема принимает три входных сигнала: Ventilation, Humidifying, Dehumidifying обозначающие воздействие системы вентиляции, воздействие увлажнения и осушения системы контроля уровня влажности соответственно, — и возвращает два выходных сигнала: OutsideHumidity и InsideHumidity, обозначающие значение уровня влажности воздуха снаружи и внутри теплицы соответственно.
Дифференциальное уравнение, описывающее изменение температуры в теплице, имеет следующий вид:
где:
- — Плотность воздуха внутри, ;
- — Объем теплицы, ;
- — Относительная влажность воздуха внутри;
- — Пар, переносимый из почвы в воздух внутри помещения в результате испарения;
- — Инфильтрационные потери;
- — Увлажнение;
- — Осушение.
Схема модели в Engee:
.png)
Рамкой на схеме выделены настраиваемые параметры системы:
C_e— Коэффициент переноса водяного пара, ;p_out— Давление насыщенного пара снаружи, ;p_in— Давление насыщенного пара внутри, ;rho_a— Плотность воздуха внутри, ;V— Объем теплицы, .
Регуляторы — контроллеры на основе нечеткой логики
Другим элементом системы управления являются контроллеры на основе нечеткой логики — они реализованы с помощью блока Engee Function.
Для создания регуляторов на основе нечеткой логики используется библиотека FuzzyLogic:
# Установка библиотеки FuzzyLogic и Plots
Pkg.add(["FuzzyLogic", "Plots"])
# Подключение библиотек FuzzyLogic и Plots
using FuzzyLogic
using Plots
Настройка регулятора температуры
Далее осуществляется построение системы нечёткого вывода Мамдани (Mamdani fuzzy inference system) с помощью макроса @mamfis. Для этого необходимо определить функций принадлежности (Membership functions).
В случае регулятора температуры объявляются функции controller_heater и controller_ventilation, принимающие на вход аргумент Error_T, который представляет собой ошибку между заданным и текущим значениями температуры внутри теплицы.
Функции принадлежности включают в себя:
- треугольную функцию принадлежности
TriangularMF(x, y, z), где x - левый угол треугольника, z - правый, а y - пик треугольника; - трапециевидную функцию принадлежности
TrapezoidalMF(x, y, z, k), где x - левый нижний угол трапеции, k - правый нижний угол, y и z - левый верхний и правый верхний углы соответственно.
В переменной domain определяются диапазоны в которых будут определены функции принадлежности. В последнем блоке задаются правила нечёткой логики, которые устанавливают зависимость входных и выходных переменных.
fis_heater = @mamfis function controller_heater(Error_T)::Heater
# Задание функций принадлежности
Error_T := begin
domain = -10.0:10.0
NNN = TrapezoidalMF(-30.0, -11.0, -2.0, -0.6)
NN = TriangularMF(-2.0, -1.0, -0.05)
Z = TriangularMF(-0.3, 0.0, 0.3)
PP = TriangularMF(0.05, 1.0, 2.0)
PPP = TrapezoidalMF(0.5, 2.0, 11.0, 30.0)
end
Heater := begin
domain = 0.0:1000.0
Z = TrapezoidalMF(-0.5, 0.0, 86.5, 232.0)
M = TrapezoidalMF(20.0, 200.0, 303.0, 394.0)
H = TrapezoidalMF(303.0, 507.0, 1000.0, 1000.5)
end
# Задание правил
Error_T == NNN --> Heater == Z
Error_T == NN --> Heater == Z
Error_T == Z --> Heater == Z
Error_T == PP --> Heater == M
Error_T == PPP --> Heater == H
end
fis_ventilation = @mamfis function controller_ventilation(Error_T)::Ventilation
# Задание функций принадлежности
Error_T := begin
domain = -10.0:10.0
NNN = TrapezoidalMF(-30.0, -11.0, -2.0, -0.56)
NN = TriangularMF(-2.0, -1.0, -0.05)
Z = TriangularMF(-0.3, 0.0, 0.3)
PP = TriangularMF(0.05, 1.0, 2.0)
PPP = TrapezoidalMF(0.5, 2.0, 11.0, 30.0)
end
Ventilation := begin
domain = 0.0:3.5
Z = TrapezoidalMF(-1.5, -1.0, 0.1, 0.3)
M = TrapezoidalMF(0.0, 0.2, 0.5, 1.0)
H = TrapezoidalMF(0.5, 1.0, 4.0, 4.5)
end
# Задание правил
Error_T == NNN --> Ventilation == H
Error_T == NN --> Ventilation == M
Error_T == Z --> Ventilation == Z
Error_T == PP --> Ventilation == Z
Error_T == PPP --> Ventilation == Z
end
Построение графика функции принадлежности для входной переменной Error_T:
plot(fis_heater, :Error_T)
Построение графика функции принадлежности для выходной переменной Heater:
plot(fis_heater, :Heater)
Построение графика функции принадлежности для выходной переменной Ventillation:
plot(fis_ventilation, :Ventilation)
Настройка регулятора влажности
Аналогичным образом осуществляется построение системы нечеткого вывода Мамдани для регулятора влажности. В этом случае объявляются функции controller_humidifying и controller_dehumidifying, принимающие на вход аргумент Error_H, который представляет собой ошибку между заданным и текущим значениями влажности внутри теплицы.
fis_humidifying = @mamfis function controller_humidifying(Error_H)::Humidifying
# Задание функций принадлежности
Error_H := begin
domain = -50.0:50.0
NNN = TrapezoidalMF(-60.5, -60.0, -7.0, -5.0)
NN = TrapezoidalMF(-7.0, -5.0, -3.0, -1.0)
Z = TriangularMF(-2.0, 0.0, 2.0)
PP = TrapezoidalMF(1.0, 3.0, 5.0, 7.0)
PPP = TrapezoidalMF(5.0, 7.0, 60.0, 60.5)
end
Humidifying := begin
domain = 0.0:50.0
Z = TrapezoidalMF(-0.5, 0.0, 5.0, 10.0)
M = TrapezoidalMF(5.0, 10.0, 30.0, 35.0)
H = TrapezoidalMF(26.0, 35.0, 51.0, 51.5)
end
# Задание правил
Error_H == NNN --> Humidifying == Z
Error_H == NN --> Humidifying == Z
Error_H == Z --> Humidifying == Z
Error_H == PP --> Humidifying == M
Error_H == PPP --> Humidifying == H
end
fis_dehumidifying = @mamfis function controller_dehumidifying(Error_H)::Dehumidifying
# Задание функций принадлежности
Error_H := begin
domain = -50.0:50.0
NNN = TrapezoidalMF(-60.5, -60.0, -7.0, -5.0)
NN = TrapezoidalMF(-7.0, -5.0, -3.0, -1.0)
Z = TriangularMF(-2.0, 0.0, 2.0)
PP = TrapezoidalMF(1.0, 3.0, 5.0, 7.0)
PPP = TrapezoidalMF(5.0, 7.0, 60.0, 60.5)
end
Dehumidifying := begin
domain = 0.0:50.0
Z = TrapezoidalMF(-0.5, 0.0, 5.0, 10.0)
M = TrapezoidalMF(5.0, 10.0, 30.0, 35.0)
H = TrapezoidalMF(26.0, 35.0, 51.0, 51.5)
end
# Задание правил
Error_H == NNN --> Dehumidifying == H
Error_H == NN --> Dehumidifying == M
Error_H == Z --> Dehumidifying == Z
Error_H == PP --> Dehumidifying == Z
Error_H == PPP --> Dehumidifying == Z
end
Построение графика функции принадлежности для входной переменной Error_H:
plot(fis_humidifying, :Error_H)
Построение графика функции принадлежности для выходной переменной Humidifying:
plot(fis_humidifying, :Humidifying)
Построение графика функции принадлежности для выходной переменной Deumidifying:
plot(fis_dehumidifying, :Dehumidifying)
Компиляция систем нечеткого вывода и сохранение результата
Далее настроенные системы нечеткого вывода компилируются с помощью функции compilefis. Аргументами функции являются файл, в который сохраняется результат компиляции, и система нечеткого вывода.
asd_heater = compilefis("$(@__DIR__)/asd_heater.jl", fis_heater)
asd_ventilation = compilefis("$(@__DIR__)/asd_ventilation.jl", fis_ventilation)
asd_humidifying = compilefis("$(@__DIR__)/asd_humidifying.jl", fis_humidifying)
asd_dehumidifying = compilefis("$(@__DIR__)/asd_dehumidifying.jl", fis_dehumidifying)
Теперь функции, полученные в результате компиляции, могут быть использованы в блоках Engee Function.
Определение параметров системы и начальных условий
Параметры системы и начальные условия задаются в кодовой ячейке:
alpha_c = 0.1 # Поглощающая способность покрытия
rho_a = 1.137 # Плотность воздуха внутри
R = 2.0 # Длина теплицы
L_c = 0.0001 # Толщина покрытия
K_c = 0.028 # Коэффициент k покрытия
S_c = 10.0 # Площадь теплицы
L = 3.0 # Длина теплицы
tau_c = 0.85 # Пропускная способность покрытия
N_h = 10.0 # Число обогревателей
S = 26.3 # Площадь поверхности
C_a = 1005.0 # Удельная теплоемкость воздуха
V = 12.6 # Объем теплицы
C_e = 0.05 # Коэффициент переноса водяного пара
p_out = 1010 # Давление насыщенного пара снаружи
p_in = 1050 # Давление насыщенного пара внутри
FixedStep = 0.5 # Шаг расчета
StartTime = 0.0 # Начало симуляции
StopTime = 172800.0 # Конец симуляции
SolverType = "fixed-step" # Тип решателя
SolverName = "Euler" # Название решателя
Затем преобразуем CSV-файлы с данными, необходимыми в ходе симуляции, в структуры WorkspaceArray
# Установка библиотеки CSV и DataFrames
Pkg.add(["CSV", "DataFrames"])
# Подключение библиотек CSV и DataFrames
using CSV
using DataFrames
# Импорт данных из CSV в виде DataFrame
T_out = CSV.read("T_out.csv", DataFrame)
H_out = CSV.read("H_out.csv", DataFrame)
V_w = CSV.read("V_w.csv", DataFrame)
I = CSV.read("I.csv", DataFrame)
# Переименуем поля структур DataFrame
rename!(T_out, :T_out_time => :time, :T_out_values => :value)
rename!(H_out, :H_out_time => :time, :H_out_values => :value)
rename!(V_w, :V_w_time => :time, :V_w_values => :value)
rename!(I, :I_time => :time, :I_values => :value)
# Преобразуем тип данных полей в Float64
T_out.time = Float64.(T_out.time)
H_out.time = Float64.(H_out.time)
V_w.time = Float64.(V_w.time)
I.time = Float64.(I.time)
# Преобразуем данные в структуры WorkspaceArray
T_out_wa = WorkspaceArray(string(rand()), T_out)
H_out_wa = WorkspaceArray(string(rand()), H_out)
V_w_wa = WorkspaceArray(string(rand()), V_w)
I_wa = WorkspaceArray(string(rand()), I)
Запуск и загрузка модели
В данной ячейке с кодом применяются методы для взаимодействия с потоком управления программы, try/catch:
try
engee.close("GreenhouseControl", force=true) # Закрытие модели
catch err # В случае, если нет модели, которую нужно закрыть и engee.close() не выполняется, то будет выполнена её загрузка после catch
m = engee.load("$(@__DIR__)/GreenhouseControl.engee") # Загрузка модели
end;
engee.set_param!(m, "StartTime" => StartTime, "StopTime" => StopTime, "SolverType" => SolverType, "SolverName" => SolverName, "FixedStep" => FixedStep) # Настройка параметров симуляции
try
engee.run(m, verbose=true) # Запуск модели
catch err # В случае, если модель не загружена и engee.run() не выполняется, то будут выполнены две нижние строки после catch
m = engee.load("$(@__DIR__)/GreenhouseControl.engee") # Загрузка модели
engee.run(m, verbose=true) # Запуск модели
end
Загрузка и визуализация данных, полученных в ходе симуляции
Чтение CSV-файлов с данными об изменении температуры и влажности:
ref_InsideTemperature = Matrix(CSV.read("ref_InsideTemperature.csv", DataFrame)); # Загрузка данных об изменении заданного значения температуры
OutsideTemperature = Matrix(CSV.read("OutsideTemperature.csv", DataFrame)); # Загрузка данных об изменении значения температуры внутри теплицы
InsideTemperature = Matrix(CSV.read("InsideTemperature.csv", DataFrame)); # Загрузка данных об изменении значения температуры снаружи теплицы
ref_InsideHumidity = Matrix(CSV.read("ref_InsideHumidity.csv", DataFrame)); # Загрузка данных об изменении заданного значения влажности
OutsideHumidity = Matrix(CSV.read("OutsideHumidity.csv", DataFrame)); # Загрузка данных об изменении значения влажности снаружи теплицы
InsideHumidity = Matrix(CSV.read("InsideHumidity.csv", DataFrame)); # Загрузка данных об изменении значения влажности внутри теплицы
Подключение бэкэнда — метода отображения графики:
gr()
Построение графиков изменения температуры
plot(ref_InsideTemperature[:,1], ref_InsideTemperature[:,2], label="Заданное значение температуры")
plot!(OutsideTemperature[:,1], OutsideTemperature[:,2], label="Значение температуры снаружи")
plot!(InsideTemperature[:,1], InsideTemperature[:,2], label="Значение температуры внутри")
Построение графиков изменения уровня влажности
plot(ref_InsideHumidity[:,1], ref_InsideHumidity[:,2], label="Заданное значение уровня влажности")
plot!(OutsideHumidity[:,1], OutsideHumidity[:,2], label="Значение уровня влажности снаружи")
plot!(InsideHumidity[:,1], InsideHumidity[:,2], label="Значение уровня влажности внутри")







