Рассмотрим кратко построение моделей на основе нечеткой логики в GNU R на примере пакета sets. Это достаточно простой пакет, в нём есть определенные ограничения, но у него есть немаловажное достоинство — он работает. Тест по материалу для самопроверки доступен вот здесь.
Если данный пакет не установлен, его необходимо предварительно установить.
Подключаем пакет.
library(sets)
Для примера рассмотрим простую систему терморегулятора на основе нечеткой логики. Возьмем в качестве комфортной температуру 18-24 градуса. Температуру ниже 20 градусов будем считать холодной (COLD), а выше 22 градусов жаркой. Температуру от 18 до 24 будем считать комфортной.
Рассмотрим также состояние клапана регулятора батареи отопления, который может быть закрыт, частично закрыт, частично открыт и открыт. Опишем систему с помощью команд пакета sets.
Для начала задам “вселенную”, т.е. то пространство, на котором будет проводиться вычисление.
sets_options("universe", seq(from = 0, to = 100, by = 0.1))
Теперь опишем обе переменные, используя в первом случае трапецоиды, во втором треугольники.
variables <-set(
TEMP=fuzzy_variable(COLD=fuzzy_trapezoid(corners = c(-1,0,17,20)),
NORMAL=fuzzy_trapezoid(corners = c(18,19,21,24)),
HOT=fuzzy_trapezoid(corners = c(22,25,100,101))),
VALVE = fuzzy_variable(CLOSED=fuzzy_triangular(corners = c(-1,0,25.1)),
PART.CLOSED=fuzzy_triangular(corners = c(0,25,75.1)),
PART.OPENED=fuzzy_triangular(corners = c(26,75.2,100)),
OPENED=fuzzy_triangular(corners = c(75.1,100,101)))
)
Опишем простые правила регулирования клапана. Если холодно, то открыть, если жарко, то закрыть, если комфортно то не менять. Обратите внимание, что надо предусмотреть все возможные состояния системы. Если мы что-то пропустим, то результат может нас неприятно удивить.
rules <-set(
fuzzy_rule(TEMP %is% COLD, VALVE %is% OPENED),
fuzzy_rule(TEMP %is% HOT, VALVE %is% CLOSED),
fuzzy_rule(TEMP %is% NORMAL && VALVE %is% CLOSED ,VALVE %is% CLOSED),
fuzzy_rule(TEMP %is% NORMAL && VALVE %is% PART.CLOSED, VALVE %is% PART.CLOSED),
fuzzy_rule(TEMP %is% NORMAL && VALVE %is% PART.OPENED, VALVE %is% PART.OPENED),
fuzzy_rule(TEMP %is% NORMAL && VALVE %is% OPENED, VALVE %is% OPENED)
)
Сформируем систему и выведем о ней данные.
system <- fuzzy_system(variables, rules)
print(system)
## A fuzzy system consisting of 2 variables and 6 rules.
##
## Variables:
##
## TEMP(COLD, NORMAL, HOT)
## VALVE(CLOSED, PART.CLOSED, PART.OPENED, OPENED)
##
## Rules:
##
## TEMP %is% NORMAL && VALVE %is% CLOSED => VALVE %is% CLOSED
## TEMP %is% NORMAL && VALVE %is% OPENED => VALVE %is% OPENED
## TEMP %is% NORMAL && VALVE %is% PART.CLOSED => VALVE %is% PART.CLOSED
## TEMP %is% NORMAL && VALVE %is% PART.OPENED => VALVE %is% PART.OPENED
## TEMP %is% HOT => VALVE %is% CLOSED
## TEMP %is% COLD => VALVE %is% OPENED
plot(system)
Получилось, мягко говоря, не ахти. Выведем отдельный графики с русскими подписями осей.
vars<-as.list(system$variables)
nams <- names(vars)
plot(vars[[2]], main = nams[2],col=rainbow(4),xlab="Температура, град. C",ylab="Степень принадлежности")
Теперь проверим как работает система. Зададим начальные условия.
data<-list(TEMP=5,VALVE=0)
fc1<-fuzzy_inference(system,data)
plot(fc1)
Проведем дефаззификацию, под которой в системах нечеткого вывода понимают процесс перехода от функции принадлежности выходной лингвистической переменной к её четкому (числовому) значению. Обращаю ваше внимание, что это всего лишь один из возможных методов.
gset_defuzzify(fc1, "centroid")
## [1] 91.73333
Получили результат, что клапан открыт на 91.7%. ПУсть прошло какое-то время и при таком положении клапана воздух в помещении нагрелся до 17 градусов.
data<-list(TEMP=17,VALVE=91.7)
fc1<-fuzzy_inference(system,data)
plot(fc1)
gset_defuzzify(fc1, "centroid")
## [1] 91.73333
Ничего не поменялось. Нагрелось до 18 градусов:
data<-list(TEMP=18,VALVE=91.7)
fc1<-fuzzy_inference(system,data)
plot(fc1)
gset_defuzzify(fc1, "centroid")
## [1] 91.03544
Мы прикрыли клапан до 91%. Температура выросла еще на 1 градус.
data<-list(TEMP=19,VALVE=91)
fc1<-fuzzy_inference(system,data)
plot(fc1)
gset_defuzzify(fc1, "centroid")
## [1] 70.63561
Температура стабилизировалась, клапан ещё чуть прикрыт.
data<-list(TEMP=19,VALVE=70.6)
fc1<-fuzzy_inference(system,data)
plot(fc1)
gset_defuzzify(fc1, "centroid")
## [1] 64.90177
Температура падает.
data<-list(TEMP=18.1,VALVE=64.9)
fc1<-fuzzy_inference(system,data)
plot(fc1)
gset_defuzzify(fc1, "centroid")
## [1] 69.54573
Тогда немного приоткроем клапан…
Имитационная модель
Рассмотрим некое абстракное помещение, которое мы обогреваем. Пусть теплопотери будут прямо пропорциональны разнице температур между наружним и внутренним помещением с учетом площади поверхности и коэффициента теплопотерь.
Пусть наружняя температура равна 0, а теплопотери в минуту равны T/30, где Т — температура в помещении. Пусть нагреватель при ста процентах мощности нагревает воздух на 1 градус за 1 минуту.
Промоделируем работу двух систем с использованием различных подходов к дефаззификации.
result<-data.frame(time=1:100,TEMP=rep(0.0,100),K=rep(0.0,100),TEMP1=rep(0.0,100),K1=rep(0.0,100))
for(i in 1:99) {
fc1<-fuzzy_inference(system,list(TEMP=result$TEMP[i],VALVE=result$K[i]))
result$K[i+1]<-round(gset_defuzzify(fc1, "centroid"),1)
result$TEMP[i+1]<-round(result$TEMP[i]+(1-result$TEMP[i+1]/30)*result$K[i+1]/100,1)
fc1<-fuzzy_inference(system,list(TEMP=result$TEMP1[i],VALVE=result$K1[i]))
result$K1[i+1]<-round(gset_defuzzify(fc1, "meanofmax"),1)
result$TEMP1[i+1]<-round(result$TEMP1[i]+(1-result$TEMP1[i+1]/30)*result$K1[i+1]/100,1)
}
plot(TEMP~time,data=result,col="red",xlab="Время, мин.", ylab="Температура, градусы.",type="l")
lines(result$TEMP1, col="blue")
plot(K~time,data=result,col="red",xlab="Время, мин.", ylab="Открытие вентиля, проценты.",type="l")
lines(result$K1, col="blue")
Обратите внимание, что модель с центроидом не стабилизируется.
Примерно так всё оно и работает и в реальной жизни, поэтому надо достаточно вдумчиво подходить к проектированию таких систем.