You are on page 1of 59

FACULTAD DE INGENIERA UNJu INTELIGENCIA ARTIFICIAL 2016

TP2 LGICA FUZZY Y SISTEMAS


DE INFERENCIA
Calificacin

Grupo

Inicio

Entrega

21/04/16

28/04/16

Prez Ricardo Daniel, 6590

MSN
Ponce Cristian Marcelo, 6454

Ramos Pablo Nicols, 6969

Problema 1 (3 ptos.)

Disear y configurar en MATLAB una interfaz grfica de usuario (GUI), para manejar un
Sistema de Inferencia Fuzzy Mamdani (MFIS), de tipo MISO mononivel, que permita:

Incorporar dos variables de entrada y una variable de salida.

Definir o aplicar funciones de pertenencia tipo tringulo (trimf), a las variables del sistema
(entradas/salida) con hasta 7 particiones, relacionadas con el operador fuzzy AND.

Cargar las reglas que formarn la base de reglas, con las caractersticas definidas en el
punto anterior.

Defuzzyficar mediante el mtodo de centro de gravedad (existe una funcin de Matlab que
realiza este clculo).

Seleccionar o disear un caso de uso para mostrar el funcionamiento de la nueva GUI


generada.

PRESENTACIN DE LA INTERFAZ GRFICA DE USUARIO (GUI).


En trminos generales, el programa cuenta bsicamente con 5 (cinco) paneles.

1. Variable de Entrada 1: en ste panel se coloca, en el campo Nombre, el nombre


correspondiente a la primera variable de entrada; en el campo Rango se establece el rango
de valores que toma dicha variable. Paso siguiente se escribe para cada particin su nombre y
sus parmetros, el formato de escritura de los parmetros debe ser [X1 X2 X3] (siendo X1, X2
y X3 nmeros). Se admite hasta 7 (siete) particiones, dejando vaco aquellos campos que no
se requieren, es decir, si el problema requiere 3 (tres) particiones se deja en blanco los
campos correspondientes al resto de particiones. Rellenado los campos se presiona el botn
Cargar y automticamente se muestra en la lista todas las particiones, opcionalmente se
puede visualizar un grfico de las particiones para mayor claridad presionando el botn Ver
Grfico.

2. Variable de Entrada 2: dem al panel anterior.

3. Variable de Salida: dem al panel anterior pero para el caso de una variable de salida.

4. Reglas: en ste panel es donde se aade (o elimina) las reglas de nuestro sistema de
inferencia fuzzy. El mecanismo es sencillo, se selecciona, de la lista correspondiente a cada
panel de variables (Entrada 1, Entrada 2 y Salida), una particin. Opcionalmente se puede
operar de modo negado con la particin, marcando el checkbox not. Seleccionada las
particiones se presiona el botn Agregar Regla del panel de reglas, y se visualiza en la lista,
de manera inmediata, la regla agregada. Procediendo de la manera anterior se puede agregar
tantas reglas como se necesite. El mecanismo para eliminar una regla consiste en seleccionar
algn tem de la lista y presionar, luego, el botn Eliminar Regla y automticamente la regla
desaparece de la lista.

5. Solucin: en ste ltimo panel se ingresa, en el campo Valor de Entrada 1, algn valor para
la primera variable de entrada y, en el campo Valor de Entrada 2, algn valor para la
segunda variable de entrada. Si se presiona el botn Calcular se muestra, en el campo
Resultado, el resultado (valga la redundancia) de la inferencia. Tambin se puede visualizar
grficamente el resultado presionando el botn Graficar. Para limpiar todos los campos del
programa se presiona el botn Limpiar.

Es importante mencionar que el programa, como se pidi, aplica funciones de pertenencia tipo
tringulo (trimf) a las variables del sistema, relacionadas con el operador fuzzy AND. Adems, el
programa utiliza el mtodo de centro de gravedad (centroide) para defuzzyficar.

FUNCIONAMIENTO DE LA INTERFAZ GRFICA DE USUARIO (GUI).


Como caso de uso, para mostrar el funcionamiento de la interfaz grfica de usuario, se seleccion
el problema de la propina (tipping problem). Problema que el mismo MatLab utiliza para explicar el
funcionamiento de la herramienta Fuzzy Logic Toolbox.
El problema utiliza dos variables de entrada y una nica variable de salida.
Dado un nmero entre 0 y 10 que representa la calidad del servicio de un restaurante (donde 10
es excelente), y otro nmero entre 0 y 10 que representa la calidad de la comida (donde de nuevo
10 es excelente), cul debera ser la propina?
Antes de nada escribimos las reglas de inferencia del problema:
1. Si el servicio es malo y la comida es horrible, entonces la propina es miserable.
2. Si el servicio es bueno, entonces la propina es normal.
3. Si el servicio es excelente y la comida es deliciosa, entones la propina es generosa.
Se asume que una propina normal es del 15%, una propina generosa es del 25%, y una propina
miserable es del 5%.
Aclaradas y definidas las reglas de inferencia (y otras cuestiones) se procede a utilizar el
programa.
Escribimos en la ventana de comandos de MatLab el comando ejercicio1.

Y vemos la siguiente ventana.

Ahora, en el panel Variable de Entrada 1, escribimos el nombre de la primera variable de entrada,


el rango de valores de dicha variable y los nombres y parmetros de las particiones involucradas.
Para nuestro problema el nombre de la primera variable de entrada es servicio y el rango de
valores es [0 10]. Para las particiones tenemos:
1. Particin 1: el nombre es malo y los parmetros son [0 0 3.5].
2. Particin 2: el nombre es bueno y los parmetros son [1.5 5 8.5].
3. Particin 3: el nombre es excelente y los parmetros son [6.5 10 10].
Entonces tenemos.

Presionamos el botn Cargar.

Presionamos el botn Ver Grafico.

Ahora, en el panel Variable de Entrada 2, escribimos el nombre de la segunda variable de


entrada, el rango de valores de dicha variable y los nombres y parmetros de las particiones
involucradas. Para nuestro problema el nombre de la segunda variable de entrada es comida y
el rango de valores es [0 10]. Para las particiones tenemos:
1. Particin 1: el nombre es horrible y los parmetros son [-0.6 0.6 7.5].
2. Particin 2: el nombre es deliciosa y los parmetros son [2.5 9.4 10.6].
Entonces tenemos.

Presionamos el botn Cargar.

Presionamos el botn Ver Grfico.

Ahora, en el panel Variable de Salida, escribimos el nombre de la variable de salida, el rango de


valores de dicha variable y los nombres y parmetros de las particiones involucradas. Para
nuestro problema el nombre de la variable de salida es propina y el rango de valores es [0 30].
Para las particiones tenemos:
1. Particin 1: el nombre es miserable y los parmetros son [0 5 10].
2. Particin 2: el nombre es normal y los parmetros son [10 15 20].
3. Particin 3: el nombre es generosa y los parmetros son [20 25 30].
Entonces tenemos.

Presionamos el botn Cargar.

Presionamos el botn Ver Grfico.

Luego, utilizando los selectores de cada variable, elegimos las particiones para armar las reglas.
En la siguiente captura se muestra como se arm la ltima regla. Elegimos la particin excelente
utilizando el selector del panel Variable de Entrada 1, elegimos la particin deliciosa utilizando el
selector del panel Variable de Entrada 2 y elegimos la particin generosa utilizando el selector
del panel Variable de Salida.

Luego, una vez elegidas las particiones, presionamos el botn Agregar Regla para agregar la
regla.

Por ltimo, nos ubicamos en el panel Solucin para evaluar nuestro sistema de inferencia fuzzy.
En el campo Valor de Entrada 1 introducimos un valor para la primera variable de entrada, y en
el campo Valor de Entrada 2 introducimos un valor para la segunda variable de entrada.

Presionamos el botn Calcular y obtenemos el resultado.

Presionamos el botn Graficar y obtenemos una grfica del resultado.

Comparando el resultado anterior con el obtenido utilizando la herramienta Fuzzy Logic Toolbox,
vemos que ambos programas arrojan el mismo resultado.

CDIGO FUENTE DE LA INTERFAZ GRFICA DE USUARIO (GUI).


Archivo ejercicio1.m:
Funcin inicializarSistemaInferencia
%funcion que inicializa el sistema de inferencia fuzzy
function inicializarSistemaInferencia()
%declaramos la variable fis como global
global fis;
%declaramos la variable numero de reglas como global
global numeroReglas;
%declaramos la variable grado de precision como global
global gradoPrecision;
%creamos un nuevo sistema de inferencia fuzzy
fis = {};
%inicializamos a cero el numero de reglas
numeroReglas = 0;
%inicializamos el grado de precision
gradoPrecision = 0.0001;

Funcin agregarParticiones
%funcion que agrega las particiones al sistema de inferencia fuzzy
function agregarParticiones(id, indice, handles)
%trabajamos con la variable global fis
global fis;
%definimos variables necesarias
j = 0;
celda = {};
%obtenemos la lista de particiones de la variable que se este tratando
listaParticiones = eval(strcat('handles.listaParticiones', num2str(id)));
%recorremos los campos (nombre y parametros) de todas las particiones
for i = 1:1:7
%obtenemos el nombre de la particion
campoNombreParticion = get(eval(strcat('handles.campoNombreParticion', num2str(id),
num2str(i))), 'String');
%obtenemos el rango de valores de la particion
campoParametrosParticion =
str2num(get(eval(strcat('handles.campoParametrosParticion', num2str(id),
num2str(i))), 'String'));
%si los campos nombre y parametros no estan vacios, entonces
if(~isempty(campoNombreParticion) && ~isempty(campoParametrosParticion))
%sumamos en una unidad la variable j
j = j + 1;
%aadimos la particion al sistema de inferencia fuzzy
fis{indice}{3}{j} = {campoNombreParticion, campoParametrosParticion};
%aadimos un nuevo elemento a la celda
celda(j) = {campoNombreParticion};
end;
end;
%sumamos en una unidad la variable j
j = j + 1;

%aadimos el ultimo elemento a la celda


celda(j) = {'Nada'};
%obtenemos la transpuesta de la celda
celda = celda';
%agregamos los elementos de la celda a la lista de particiones
set(listaParticiones, 'String', celda);

Funcin graficarParticiones
%funcion que grafica las particiones de la variable que se este tratando
function graficarParticiones(indice, resultado)
%trabajamos con la variable global fis
global fis;
%trabajamos con la variable global grado de precision
global gradoPrecision;
%guardamos los datos necesarios para poder graficar las particiones
%en otra ventana (grafica.fig)
manejadorVentanaPrincipal = getappdata(0, 'manejadorVentanaPrincipal');
%guardamos el rango de valores de la variable
setappdata(manejadorVentanaPrincipal, 'rango', fis{indice}{2});
%guardamos las particiones de la variable
setappdata(manejadorVentanaPrincipal, 'particiones', fis{indice}{3});
%guardamos el resultado de la inferencia
setappdata(manejadorVentanaPrincipal, 'resultado', resultado);
%abrimos la ventana grafica.fig para graficar las particiones
winopen('grafica.fig');

Funcin actualizarListaReglas
%funcion que actualiza la lista de reglas de la ventana
function actualizarListaReglas(handles)
%trabajamos con la variable global fis
global fis;
%inicializamos una objeto tipo celda para almacenar las reglas
listaReglas = cell(1, size(fis{4}, 2));
%recorremos todas las reglas del sistema de inferencia
for i = 1:1:size(listaReglas, 2)
%definimos una salida (visual) de la regla '. If ...'
salidaRegla = strcat(mat2str(i), '. If', {' '});
%recorremos todas las particiones involucradas en la regla
for j = 1:1:size(fis{4}{i}, 2)
%si es la particion de la variable de salida, entonces
if(j == size(fis{4}{i}, 2))
%la salida es 'then ...'
salidaRegla = strcat(salidaRegla, {' '}, 'then', {' '});
end;
%si la particion es negativa, entonces
if(fis{4}{i}(j) < 0)
%la salida es 'is not...'
salidaRegla = strcat(salidaRegla, '(', fis{j}{1}, {' '}, 'is not', {' '},
fis{j}{3}{abs(fis{4}{i}(j))}{1}, ')');
%si la particion es positiva, entonces
elseif(fis{4}{i}(j) > 0)

%la salida es 'is...'


salidaRegla = strcat(salidaRegla, '(', fis{j}{1}, {' '}, 'is', {' '},
fis{j}{3}{fis{4}{i}(j)}{1}, ')');
end;
%si es la primera particion y es distinta de cero, y la siguiente
%particion es distinta de cero, entonces
if(j == 1 && fis{4}{i}(j) ~= 0 && fis{4}{i}(j + 1) ~= 0)
%la salida es 'and...'
salidaRegla = strcat(salidaRegla, {' '}, 'and', {' '});
end;
end;
%agregamos la regla a la lista de reglas
listaReglas(i) = salidaRegla;
end;
%mostramos las reglas en
set(handles.listaReglas,
%seleccionamos el ultimo
set(handles.listaReglas,

la lista de la ventana
'String', listaReglas);
elemento de la lista
'Value', size(listaReglas, 2));

Funcin obtenerGradoPertenencia
%funcion que obtiene el grado de pertenencia dado un x
function gradoPertenencia = obtenerGradoPertenencia(indiceVariable, indiceParticion,
xPedido)
%trabajamos con la variable global fis
global fis;
%trabajamos con la variable global grado de precision
global gradoPrecision;
%obtenemos los parametros de la curva de la particion
parametrosCurva = fis{indiceVariable}{3}{indiceParticion}{2};
%definimos los valores de x
x = fis{indiceVariable}{2}(1):gradoPrecision:fis{indiceVariable}{2}(2);
%definimos los valores de y
y = max(min((x - parametrosCurva(1)) / (parametrosCurva(2) - parametrosCurva(1)),
(parametrosCurva(3) - x) / (parametrosCurva(3) - parametrosCurva(2))), 0);
%inicializamos a cero el grado de pertenencia
yPedido = 0;
%recorremos todos los valores del vector x
for i = 1:1:size(x, 2)
%si el valor del vector x es mayor o igual al valor de la variable
%xPedido, entonces
if(x(i) >= xPedido)
%encontramos el grado de pertenencia
yPedido = y(i);
break;
end;
end;

%devolvemos el grado de pertenencia


gradoPertenencia = yPedido;

Funcin calcularInferencia
%funcion que calcula el sistema de inferencia fuzzy
function calcularInferencia(handles)
%trabajamos con la variable global fis
global fis;
%trabajamos con la variable global grado de precision
global gradoPrecision;
%obtenemos el valor de la primera variable de entrada
campoValorEntrada1 = str2num(get(handles.campoValorEntrada1, 'String'));
%obtenemos el valor de la segunda variable de entrada
campoValorEntrada2 = str2num(get(handles.campoValorEntrada2, 'String'));
%si los campos valor de entrada no estan vacios, entonces
if(~isempty(campoValorEntrada1) && ~isempty(campoValorEntrada2))
%ubicamos los valores de entrada en un vector
valorEntradas = [campoValorEntrada1, campoValorEntrada2];
%inicializamos el vector que almacenara el grado de pertenencia de
%cada regla
gradoPertenenciaReglas = zeros(1, size(fis{4}, 2));
%recorremos todas las reglas del sistema de inferencia
for i = 1:1:size(gradoPertenenciaReglas, 2)
%inicializamos un contador k
k = 0;
%inicializamos el vector que almacena el grado de pertenencia de
%cada particion
gradoPertenenciaParticiones = [];
%recorremos todas las particiones de la regla, excepto de la
%variable de salida
for j = 1:1:size(fis{4}{i}, 2) - 1
%si la particion es distinta de cero, entonces
if(fis{4}{i}(j) ~= 0)
%agregamos un nuevo grado de pertenencia
k = k + 1;
%si la particion es negativa, entonces
if(fis{4}{i}(j) < 0)
%el grado de pertenencia es 1 - mu
gradoPertenenciaObtenido = 1 - obtenerGradoPertenencia(j,
abs(fis{4}{i}(j)), valorEntradas(j));
%sino
else
%el grado de pertenencia es mu
gradoPertenenciaObtenido = obtenerGradoPertenencia(j, fis{4}{i}(j),
valorEntradas(j));
end;
%aadimos el grado de pertenencia de la particion
gradoPertenenciaParticiones(k) = gradoPertenenciaObtenido;
end;
end;

%tomamanos el minimo de los grados de pertenencia de las


%particiones (operacion AND)
%si la particion de la variable de salida es negativa, entonces
if(fis{4}{i}(3) < 0)
%el grado de pertenencia de la regla es 1 - min
gradoPertenenciaReglas(i) = 1 - min(gradoPertenenciaParticiones);
%sino
else
%el grado de pertenencia de la regla es min
gradoPertenenciaReglas(i) = min(gradoPertenenciaParticiones);
end;
end;
%definimos los valores de x
x = fis{3}{2}(1):gradoPrecision:fis{3}{2}(2);
%definimos una variable y auxiliar
yAuxiliar = cell(1, size(gradoPertenenciaReglas, 2));
%recorremos el grado de pertenencia de todas las reglas
for i = 1:1:size(gradoPertenenciaReglas, 2)
%obtenemos los parametros de la curva de la particion invoclucrada
%en la variable de salida
parametrosCurva = fis{3}{3}{abs(fis{4}{i}(3))}{2};
yActual = max(min((x - parametrosCurva(1)) / (parametrosCurva(2) parametrosCurva(1)), (parametrosCurva(3) - x) / (parametrosCurva(3) parametrosCurva(2))), 0);
%recorremos todos los valores del vector yActual
for j = 1:1:size(yActual, 2)
%si el valor del vector es mayor al grado de pertenencia de la
%regla, entonces
if(yActual(j) > gradoPertenenciaReglas(i))
%le asignamos el valor del grado de pertenencia de la regla
yActual(j) = gradoPertenenciaReglas(i);
end;
end;
%aadimos a la celda un nuevo vector de valores y
yAuxiliar{i} = yActual;
end;
%definimos los valores de y
y = zeros(1, size(yAuxiliar{1}, 2));
%recorremos todos los valores de y
for i = 1:1:size(y, 2)
%definimos un vector para almacenar los valores i de cada vector
%almacenado en la celda yAuxiliar
valoresY = zeros(1, size(yAuxiliar, 2));
%recorremos los valores i de cada vector
for j = 1:1:size(yAuxiliar, 2)
%aadimos el valor i al vector valoresY
valoresY(j) = yAuxiliar{j}(i);
end;
%tomamos el maximo de los valores del vector (Mamdani)
y(i) = max(valoresY);

end;
%calculamos el area total
areaTotal = sum(y);
%si el area total es distinto de cero, entonces
if(areaTotal ~= 0)
%el resultado final es:
resultadoFinal = sum(y.*x) / areaTotal;
%sino
else
%el resultado final es cero
resultadoFinal = areaTotal;
end;
%mostramos el resultado en el campo resultado de la ventana
set(handles.campoResultado, 'String', resultadoFinal);
end;

Funcin figure1_CreateFcn
% --- Executes during object creation, after setting all properties.
function figure1_CreateFcn(hObject, eventdata, handles)
%llamada a la funcion que inicializa el sistema de inferencia fuzzy
inicializarSistemaInferencia();
%configuramos lo necesario para habilitar la comunicacion entre la ventana
%ejercicio1.fig y grafica.fig
setappdata(0, 'manejadorVentanaPrincipal', gcf);

Funcin botonCargar1_Callback
% --- Executes on button press in botonCargar1.
function botonCargar1_Callback(hObject, eventdata, handles)
%trabajamos con la variable global fis
global fis;
%obtenemos el nombre de la primera variable de entrada
campoNombreEntrada1 = get(handles.campoNombreEntrada1, 'String');
%obtenemos el rango de valores de la primera variable de entrada
campoRangoEntrada1 = str2num(get(handles.campoRangoEntrada1, 'String'));
%aadimos la primera variable de entrada al sistema de inferencia fuzzy
fis{1} = {campoNombreEntrada1, campoRangoEntrada1};
%llamada a la funcion que agrega las particiones
agregarParticiones(1, 1, handles);
%modificamos el texto si ... es
set(handles.texto1, 'String', strcat('si', {' '}, campoNombreEntrada1, {' '}, 'es'));
%hacemos visible el texto
set(handles.texto1, 'Visible', 'on');

Funcin botonGraficar1_Callback
% --- Executes on button press in botonGraficar1.
function botonGraficar1_Callback(hObject, eventdata, handles)

%llamada a la funcion que grafica las particiones


graficarParticiones(1, []);

Funcin botonCargar2_Callback
% --- Executes on button press in botonCargar2.
function botonCargar2_Callback(hObject, eventdata, handles)
%trabajamos con la variable global fis
global fis;
%obtenemos el nombre de la segunda variable de entrada
campoNombreEntrada2 = get(handles.campoNombreEntrada2, 'String');
%obtenemos el rango de valores de la segunda variable de entrada
campoRangoEntrada2 = str2num(get(handles.campoRangoEntrada2, 'String'));
%aadimos la segunda variable de entrada al sistema de inferencia fuzzy
fis{2} = {campoNombreEntrada2, campoRangoEntrada2};
%llamada a la funcion que agrega las particiones
agregarParticiones(2, 2, handles);
%modificamos el texto y ... es
set(handles.texto2, 'String', strcat('y', {' '}, campoNombreEntrada2, {' '}, 'es'));
%hacemos visible el texto
set(handles.texto2, 'Visible', 'on');

Funcin botonGraficar2_Callback
% --- Executes on button press in botonGraficar2.
function botonGraficar2_Callback(hObject, eventdata, handles)
%llamada a la funcion que grafica las particiones
graficarParticiones(2, []);

Funcin botonCargar3_Callback
% --- Executes on button press in botonCargar3.
function botonCargar3_Callback(hObject, eventdata, handles)
%trabajamos con la variable global fis
global fis;
%obtenemos el nombre de la variable de salida
campoNombreSalida = get(handles.campoNombreSalida, 'String');
%obtenemos el rango de valores de la variable de salida
campoRangoSalida = str2num(get(handles.campoRangoSalida, 'String'));
%aadimos la variable de salida al sistema de inferencia fuzzy
fis{3} = {campoNombreSalida, campoRangoSalida};
%llamada a la funcion que agrega las particiones
agregarParticiones(3, 3, handles);
%modificamos el texto entonces ... es
set(handles.texto3, 'String', strcat('entonces', {' '}, campoNombreSalida, {'
'}, 'es'));
%hacemos visible el texto
set(handles.texto3, 'Visible', 'on');

Funcin botonGraficar3_Callback
% --- Executes on button press in botonGraficar3.
function botonGraficar3_Callback(hObject, eventdata, handles)
%llamada a la funcion que grafica las particiones
graficarParticiones(3, []);

Funcin botonAgregarRegla_Callback
% --- Executes on button press in botonAgregarRegla.
function botonAgregarRegla_Callback(hObject, eventdata, handles)
%trabajamos con la variable global fis
global fis;
%trabajamos con la variable global numero de reglas
global numeroReglas;
%obtenemos la particion seleccionada en la primera variable de entrada
numeroParticion1 = get(handles.listaParticiones1, 'Value');
%obtenemos la particion seleccionada en la segunda variable de entrada
numeroParticion2 = get(handles.listaParticiones2, 'Value');
%obtenemos la particion seleccionada en la variable de salida
numeroParticion3 = get(handles.listaParticiones3, 'Value');
%obtenemos la lista de particiones de la primera variable de entrada
listaParticiones1 = get(handles.listaParticiones1, 'String');
%obtenemos la lista de particiones de la segunda variable de entrada
listaParticiones2 = get(handles.listaParticiones2, 'String');
%obtenemos la lista de particiones de la variable de salida
listaParticiones3 = get(handles.listaParticiones3, 'String');
%obtenemmos el valor del checkbox de la primera variable de entrada
operacionNot1 = get(handles.checkNot1, 'Value');
%obtenemmos el valor del checkbox de la segunda variable de entrada
operacionNot2 = get(handles.checkNot2, 'Value');
%obtenemmos el valor del checkbox de la variable de salida
operacionNot3 = get(handles.checkNot3, 'Value');
%si el usuario selecciona la ultima opcion de la lista de particiones
%de la primera variable de entrada, entonces
if(size(listaParticiones1, 1) == numeroParticion1)
%no hacer nada
numeroParticion1 = 0;
%sino, si el usuario selecciona una particion, entonces
else
%comprobar si el usuario marca el operador NOT
if(operacionNot1 == 1)
%entonces es menos la particion
numeroParticion1 = -numeroParticion1;
end;
end;
%si el usuario selecciona la ultima opcion de la lista de particiones
%de la segunda variable de entrada, entonces
if(size(listaParticiones2, 1) == numeroParticion2)
%no hacer nada
numeroParticion2 = 0;
%sino, si el usuario selecciona una particion, entonces
else

%comprobar si el usuario marca el operador NOT


if(operacionNot2 == 1)
%entonces es menos la particion
numeroParticion2 = -numeroParticion2;
end;
end;
%si el usuario selecciona la ultima opcion de la lista de particiones
%de la variable de salida, entonces
if(size(listaParticiones3, 1) == numeroParticion3)
%no hacer nada
numeroParticion3 = 0;
%sino, si el usuario selecciona una particion, entonces
else
%comprobar si el usuario marca el operador NOT
if(operacionNot3 == 1)
%entonces es menos la particion
numeroParticion3 = -numeroParticion3;
end;
end;
%si el usuario selecciona una particion de la variable de salida (que no
%sea 'nada'), entonces
if(numeroParticion3 ~= 0)
%armamos la nueva regla
nuevaRegla = [numeroParticion1 numeroParticion2 numeroParticion3];
%aadimos la nueva regla al sistema de inferencia fuzzy
numeroReglas = numeroReglas + 1;
fis{4}{numeroReglas} = nuevaRegla;
%llamada a la funcion que actualiza la lista de reglas de la ventana
actualizarListaReglas(handles);
%deshabilitamos todos los botones cargar
for i = 1:1:3
botonCargar = eval(strcat('handles.botonCargar', num2str(i)));
set(botonCargar, 'Enable', 'off');
end;
end;

Funcin botonEliminarRegla_Callback
% --- Executes on button press in botonEliminarRegla.
function botonEliminarRegla_Callback(hObject, eventdata, handles)
%trabajamos con la variable global fis
global fis;
%trabajamos con la variable global numero de reglas
global numeroReglas;
%obtenemos la regla seleccionada en la lista de la ventana
numeroRegla = get(handles.listaReglas, 'Value');

%borramos la regla seleccionada del sistema de inferencia fuzzy


numeroReglas = numeroReglas - 1;
for i = numeroRegla:1:(size(fis{4}, 2) - 1)
fis{4}(i) = fis{4}(i + 1);
end;
%borramos el ultimo elemento de la cela donde se encuentran las reglas
fis{4}(size(fis{4}, 2)) = [];
%llamada a la funcion que actualiza la lista de reglas de la ventana
actualizarListaReglas(handles);

Funcin botonCalcular_Callback
% --- Executes on button press in botonCalcular.
function botonCalcular_Callback(hObject, eventdata, handles)
%llamada a la funcion que calcula el sistema de inferencia fuzzy
calcularInferencia(handles);

Funcin botonGraficar_Callback
% --- Executes on button press in botonGraficar.
function botonGraficar_Callback(hObject, eventdata, handles)
%llamada a la funcion que grafica el resultado
graficarParticiones(3, get(handles.campoResultado, 'String'));

Funcin botonLimpiar_Callback
% --- Executes on button press in botonLimpiar.
function botonLimpiar_Callback(hObject, eventdata, handles)
%trabajamos con la variable global fis
global fis;
%limpiamos todos los campos de la ventana
for i = 1:1:2
campoNombreEntrada = eval(strcat('handles.campoNombreEntrada', num2str(i)));
campoRangoEntrada = eval(strcat('handles.campoRangoEntrada', num2str(i)));
campoValorEntrada = eval(strcat('handles.campoValorEntrada', num2str(i)));
set(campoNombreEntrada, 'String', '');
set(campoRangoEntrada, 'String', '');
set(campoValorEntrada, 'String', '');
end;
for i = 1:1:3
botonCargar = eval(strcat('handles.botonCargar', num2str(i)));
texto = eval(strcat('handles.texto', num2str(i)));
listaParticiones = eval(strcat('handles.listaParticiones', num2str(i)));
checkNot = eval(strcat('handles.checkNot', num2str(i)));
set(botonCargar, 'Enable', 'on');
set(texto, 'Visible', 'off');

set(listaParticiones, 'String', '');


set(checkNot, 'Value', 0);
end;
for i = 1:1:3
for j = 1:1:7
campoNombreParticion = eval(strcat('handles.campoNombreParticion', num2str(i),
num2str(j)));
campoParametrosParticion = eval(strcat('handles.campoParametrosParticion',
num2str(i), num2str(j)));
set(campoNombreParticion, 'String', '');
set(campoParametrosParticion, 'String', '');
end;
end;
set(handles.campoNombreSalida, 'String', '');
set(handles.campoRangoSalida, 'String', '');
set(handles.listaReglas, 'String', '');
set(handles.campoResultado, 'String', '');
%reseteamos el sistema de inferencia fuzzy
inicializarSistemaInferencia();

Archivo grafica.m:
Funcin graficarParticiones
%funcion que grafica las particiones de la variable que se este tratando
function graficarParticiones(rango, particiones, resultado)
%trabajamos con la variable global grado de precision
global gradoPrecision;
%habilitamos la superposicion de graficos
hold on;
%definimos los colores de trazo para las graficas
coloresTrazo = {[0 0 1], [0 1 0], [0 1 1], [0.5 0 0], [0.5 0 1], [1 0 1], [1 1 0]};
%recorremos todas las particiones de la variable
for i = 1:1:size(particiones, 2)
%obtenemos los parametros de la grafica
parametrosGrafica = particiones{i}{2};
%definimos los valores de x
x = rango(1):gradoPrecision:rango(2);
%definimos los valores de y
y = max(min((x - parametrosGrafica(1)) / (parametrosGrafica(2) parametrosGrafica(1)), (parametrosGrafica(3) - x) / (parametrosGrafica(3) parametrosGrafica(2))), 0);
%graficamos la particion
plot(x, y, 'Color', coloresTrazo{i});
%colocamos un texto sobre la grafica
text((parametrosGrafica(2) - length(particiones{i}{1}) / (2 *
length(particiones{i}{1}))), (1 + 0.05), particiones{i}{1});

end;
%si la variable resultado no esta vacia, entonces
if(~isempty(resultado))
%definimos los valores de y
y = 0:gradoPrecision:1;
%graficamos el resultado
plot(str2num(resultado), y, 'r');
end;
%definimos los limites del eje y
ylim([-0.1 1.1]);

Funcin figure1_CreateFcn
% --- Executes during object creation, after setting all properties.
function figure1_CreateFcn(hObject, eventdata, handles)
%declaramos la variable grado de precision como global
global gradoPrecision;
%inicializamos el grado de precision
gradoPrecision = 0.001;
%configuramos lo necesario para habilitar la comunicacion entre la ventana
%ejercicio1.fig y grafica.fig
manejadorVentanaPrincipal = getappdata(0, 'manejadorVentanaPrincipal');
%obtenemos la variable rango
rango = getappdata(manejadorVentanaPrincipal, 'rango');
%obtenemos la variable particiones
particiones = getappdata(manejadorVentanaPrincipal, 'particiones');
%obtenemos la variable resultado
resultado = getappdata(manejadorVentanaPrincipal, 'resultado');
%llamada a la funcion que grafica las particiones
graficarParticiones(rango, particiones, resultado);

Problema 2 Sistema FIS genrico (3 ptos.)

Disear un script que configure un sistema de inferencia fuzzy para un problema genrico que
contiene tres variables, dos de entrada (x, y) y una de salida (z). Las variables (x, y, z) toman
valores en el intervalo [0,10]. El script debe utilizar las funciones del toolbox fuzzy y responder a
los requerimientos que se indican:

Debe solicitar el tipo de funcin de pertenencia a utilizar, la misma para todas las
variables. Se recomienda trabajar con tringulos y gaussianas.

Debe solicitar la cantidad de particiones, entre tres, cinco y siete.

Debe solicitar el porcentaje de solapamiento (ej. 20%, 50% y 80%).

Las funciones se dispondrn igualmente espaciadas sobre el universo de cada variable,


solapadas segn el porcentaje indicado. Los vrtices de la primera y ltima funcin deben
coincidir con los extremos del universo de cada variable.

Utilizar como base de reglas, las mostradas en el paper DERIVACIN DE REGLAS DE


CONTROL MIMO PARA UN CONTROLADOR FUZZY SIN CONOCIMIENTO
EXPERTO, para tres, cinco y siete particiones.

Debe graficarse la funcin de transferencia z = f(x,y).

A partir de la funcin de transferencia z = f(x,y) establecer conclusiones de cmo afecta el grado


de solapamiento, la cantidad de particiones y el tipo de funcin de pertenencia sobre la salida del
sistema.
FUNCIONAMIENTO DEL SCRIPT.
Como caso de uso, para mostrar el funcionamiento del script, se seleccion el problema del hotel.
El problema utiliza dos variables de entrada y una nica variable de salida.
Dado un nmero entre 0 y 10 que representa la comodidad de la cama del hotel (donde 10 es
excelente), y otro nmero entre 0 y 10 que representa la calidad del desayuno (donde de nuevo
10 es excelente), Cmo es el servicio del hotel?
Antes de nada escribimos las reglas de inferencia del problema:
1. Si la cama es incomoda o el desayuno es horrible, entonces el servicio es malo.
2. Si la cama es normal, entonces el servicio es normal.
3. Si la cama es cmoda o el desayuno es delicioso, entonces el servicio es bueno.
Aclaradas y definidas las reglas de inferencia (y otras cuestiones) se procede a utilizar el
programa.

Escribimos en la ventana de comandos de MatLab el comando ejercicio2.

Y vemos la siguiente salida.

Ahora, escribimos el nombre de la primera variable de entrada y un valor para la misma. En


nuestro problema el nombre de la primera variable de entrada es cama y un valor puede ser 7
por ejemplo.
Entonces tenemos.

Presionamos la tecla ENTER y hacemos lo mismo para la segunda variable de entrada,


considerando que el nombre de la segunda variable de entrada es desayuno y el valor es 8 (por
ejemplo).
Entonces tenemos.

Presionamos la tecla ENTER y escribimos el nombre de la variable de salida, el nombre de la


misma es servicio.
Entonces tenemos.

Presionamos la tecla ENTER y vemos la siguiente salida.

Ahora, elegimos alguna funcin de pertenencia de las dos que muestra el programa. Si queremos
utilizar la funcin triangular escribimos 1 sino escribimos 2. En nuestro caso utilizaremos una
funcin triangular.

Presionamos la tecla ENTER y vemos la siguiente salida.

Ahora, elegimos el nmero de particiones que tendrn todas las variables del sistema. Escribimos
1 si queremos 3 (tres) particiones, 2 si queremos 5 (cinco), 3 si queremos 7 (siete). Para
nuestro ejemplo elegiremos solamente 3 (tres) particiones.

Presionamos la tecla ENTER y obtenemos la siguiente salida.

Ahora, escribimos el porcentaje de solapamiento, tomaremos un solapamiento del 20%.

Presionamos la tecla ENTER y vemos la siguiente salida.

Ahora, escribimos el nombre de cada una de las 3 (tres) particiones que forman parte de la
primera variable de entrada (la variable cama). Para nuestro problema, el nombre de la particin
1 es incomoda, de la particin 2 es normal y de la particin 3 es cmoda.
Entonces tenemos.

Presionamos la tecla ENTER y hacemos lo mismo para la segunda variable de entrada (la
variable desayuno), considerando que el nombre de la particin 1 es horrible, de la particin 2 es
normal y de la particin 3 es delicioso.
Entonces tenemos.

Presionamos la tecla ENTER y lo mismo para la variable de salida (la variable servicio), el
nombre de la particin 1 es malo, de la particin 2 es normal y de la particin 3 es bueno.
Entonces tenemos.

Presionamos la tecla ENTER y vemos la siguiente salida.

Luego, introducimos las reglas de nuestro sistema de inferencia. Las reglas deben tener el
siguiente
formato:
[particionVarEntrada1,
particionVarEntrada2,
particionVarSalida,
operacionLogica] donde,

particionVarEntrada1 es el nmero de particin correspondiente a la primera variable de


entrada. Si se quiere negar ste antecedente, operacin lgica NOT, se coloca el signo -
(menos) acompaado del nmero de particin. Tambin se puede excluir el antecedente
colocando un nmero 0 (cero).

particionVarEntrada2 es el nmero de particin correspondiente a la segunda variable de


entrada. Si se quiere negar ste antecedente, operacin lgica NOT, se coloca el signo -
(menos) acompaado del nmero de particin. Tambin se puede excluir el antecedente
colocando un nmero 0 (cero).

particionVarSalida es el nmero de particin correspondiente a la variable de salida. Si se


quiere negar ste consecuente, operacin lgica NOT, se coloca el signo - (menos)
acompaado del nmero de particin. Es importante recalcar que no se puede excluir el
consecuente.

operacionLogica es el nmero correspondiente al tipo de operacin lgica a realizar con


los antecedentes. 1 si trata de una operacin lgica AND o 2 si se trata de una
operacin lgica OR.

Entonces, las reglas mencionadas al principio quedaran expresadas en la consola de la siguiente


manera.

Finalmente, presionamos la tecla ENTER y el programa nos muestra el valor de la variable de


salida en relacin a los valores asignados a la primera y segunda variable de entrada.

Adems, el programa nos muestra la siguiente grfica de superficie.

Si abrimos el archivo generado por el script podemos observar como las particiones de cada
variable estn solapadas un 20%. Las siguientes figuras describen tal situacin.

La siguiente captura visualiza las reglas de nuestro sistema de inferencia, las cuales coinciden
con las enunciadas en nuestro problema de ejemplo.

CDIGO FUENTE DEL SCRIPT.


Archivo ejercicio2.m:
%cerramos todas las ventanas, borramos todas las variables y limpiamos la
%consola
close all; clear; clc;
%definimos un nombre para el archivos fis
nombreArchivo = 'ejercicio2';
%creamos un nuevo sistema de inferencia fuzzy
fis = newfis(nombreArchivo);
%el metodo de defuzzificacion es el del centroide
fis = setfis(fis, 'defuzzmethod', 'centroid');
%definimos el rango de valores de las variables involucradas
rangoValores = [0 10];
%definimos un vector que contendra los tipos de funciones de pertenencia
funcionesPertenencia = {'trimf', 'gaussmf'};
%definimos un vector que contendra los numeros de particiones
numerosParticiones = [3, 5, 7];
%definimos un objeto tipo celda para almacenar los nombres de las variables
nombreVariables = cell(1, 3);
%salida en consola
fprintf('Primera variable de entrada:\n');
fprintf('\tNombre: ');
%pedimos al usuario el nombre de la primera variable de entrada
nombreVariables{1} = input('', 's');
%salida en consola
fprintf('\tValor: ');
%pedimos al usuario el valor de la primera variable de entrada
valorVariableEntrada1 = input('');
%salida en consola
fprintf('\nSegunda variable de entrada:\n');
fprintf('\tNombre: ');
%pedimos al usuario el nombre de la segunda variable de entrada
nombreVariables{2} = input('', 's');
%salida en consola
fprintf('\tValor: ');
%pedimos al usuario el valor de la segunda variable de entrada
valorVariableEntrada2 = input('');
%salida en consola
fprintf('\nVariable de salida:\n');
fprintf('\tNombre: ');
%pedimos al usuario el nombre de la variable de salida
nombreVariables{3} = input('', 's');
%recorremos todas las variables
for i = 1:1:size(nombreVariables, 2)
%si es una variable de entrada, entonces
if(i < size(nombreVariables, 2))
%agregamos una variable de entrada al sistema de inferencia
fis = addvar(fis, 'input', nombreVariables{i}, rangoValores);
%sino
else
%agregamos una variable de salida al sistema de inferencia
fis = addvar(fis, 'output', nombreVariables{i}, rangoValores);
end;

end;
%salida en consola
fprintf('\nFuncion de pertenencia:');
fprintf('\n\t(1) Triangular');
fprintf('\n\t(2) Gaussiana');
fprintf('\nOpcion: ');
%pedimos al usuario que ingrese la funcion de pertenencia a utilizar
tipoFuncionPertenencia = input('');
%salida en consola
fprintf('\nCantidad de particiones:');
fprintf('\n\t(1) Tres');
fprintf('\n\t(2) Cinco');
fprintf('\n\t(3) Siete');
fprintf('\nOpcion: ');
%pedimos al usuario que ingrese la cantidad de particiones
cantidadParticiones = input('');
%salida en consola
fprintf('\nPorcentaje de solapamiento: ');
%pedimos al usuario que ingrese el porcentaje de solapamiento
porcentajeSolapamiento = input('');
%llamamos a la funcion obtenerParticiones para obtener las particiones con
%sus respectivos parametros (solapados con el porcentaje indicado)
particionesSistema = obtenerParticiones(numerosParticiones(cantidadParticiones),
porcentajeSolapamiento, funcionesPertenencia{tipoFuncionPertenencia});
%recorremos todas las variables
for i = 1:1:size(nombreVariables, 2)
%salida en consola
fprintf('\nParticiones de la variable %s:\n', nombreVariables{i});
%recorremos todas las particiones de la variable
for j = 1:1:numerosParticiones(cantidadParticiones)
%salida en consola
fprintf('\tNombre de la particion %d: ', j);
%pedimos al usuario el nombre de la particion
nombreParticion = input('', 's');
%si es una variable de entrada, entonces
if(i < size(nombreVariables, 2))
%agregamos una particion de entrada al sistema de inferencia
fis = addmf(fis, 'input', i, nombreParticion,
funcionesPertenencia{tipoFuncionPertenencia}, particionesSistema{j});
%sino
else
%agregamos una particion de salida al sistema de inferencia
fis = addmf(fis, 'output', 1, nombreParticion,
funcionesPertenencia{tipoFuncionPertenencia}, particionesSistema{j});
end;
end;
end;
%salida en consola
fprintf('\nReglas:');
fprintf('\n\tForma de la regla: [particionVarEntrada1, particionVarEntrada2,
particionVarSalida, operacionLogica]\n');

%definimos una bandera para el bucle while


banderaBucle = true;
while banderaBucle
%salida en consola
fprintf('\t\tRegla: ');
%pedimos al usuario una regla
reglaSistema = input('');
%si la regla no esta vacia, entonces
if(~isempty(reglaSistema))
%agregamos una nueva regla al sistema de inferencia
fis = addrule(fis, [reglaSistema(1), reglaSistema(2), reglaSistema(3), 1,
reglaSistema(4)]);
%sino
else
%salimos del bucle, el usuario ya no quiere ingresar mas reglas
banderaBucle = false;
end;
end;
%calculamos el sistema de inferencia fuzzy
resultadoFinal = evalfis([valorVariableEntrada1, valorVariableEntrada2], fis);
%salida en consola
fprintf('\nResultado: %d\n', resultadoFinal);
%guardamos el fis como un archivo
writefis(fis, nombreArchivo);
%mostramos la grafica de superficie
gensurf(fis);
%abrimos el fuzzy logic toolbox con nuestro ejemplo
fuzzy(strcat(nombreArchivo, '.fis'));

Archivo obtenerParticiones.m:
Funcin obtenerParticiones
%funcion que obtiene las particiones
function particiones = obtenerParticiones(numeroParticiones, porcentajeSolapamiento,
tipoFuncion)
%definimos el tamao para la base de un triangulo
tamanoBase = 10;
%calculamos la mitad de la base
mitadTamanoBase = tamanoBase * 0.5;
%definimos los parametros del triangulo ubicado mas a la izquierda
trianguloIzquierdo = [-mitadTamanoBase 0 mitadTamanoBase];
%definimos los parametros del triangulo ubicado despues del triangulo
%izquierdo
trianguloSiguiente = [mitadTamanoBase tamanoBase (mitadTamanoBase * 3)];
%calculamos el area del triangulo ubicado mas a la izquierda
areaTrianguloIzquierdo = mitadTamanoBase * 0.5 * (porcentajeSolapamiento * 0.01);
%definimos un diferencial de aumento
diferencialDelta = 0.0;
%definimos un limite inferior de busqueda
limiteInferiorBusqueda = 0;
%definimos un limite superior de busqueda
limiteSuperiorBusqueda = 0;

%definimos la precision de busqueda del resultado


precisionBusqueda = 0.0000001;
%definimos un nuevo tamao para la base del triangulo
nuevoTamanoBase = 0;
%definimos un objeto tipo celda para almacenar los parametros de cada
%particion triangulo
particionesTriangulo = cell(1, numeroParticiones);
%buscamos la solucion aumentando el valor de x de 0.1 en 0.1
%(hasta tamanoBase)
for i = 1:1:tamanoBase
%aumentamos el diferencial en 0.1
diferencialDelta = diferencialDelta + 0.1;
%calculamos el area del triangulo actual
areaTrianguloActual = (trianguloIzquierdo(3) - (trianguloSiguiente(1) - i)) *
0.5 * diferencialDelta;
%si el area del triangulo actual es mayor o igual al area del
%triangulo izquierdo, entonces
if(areaTrianguloActual >= areaTrianguloIzquierdo)
%restringimos los limites de busqueda
limiteInferiorBusqueda = trianguloIzquierdo(3) - (trianguloSiguiente(1) (i - 1));
limiteSuperiorBusqueda = trianguloIzquierdo(3) - (trianguloSiguiente(1) i);
break;
end;
end;
%seguimos buscando la solucion pero aumentando el valor de x en un
%valor mucho mas pequeo
for i = limiteInferiorBusqueda:precisionBusqueda:limiteSuperiorBusqueda
%calculamos el area del triangulo actual
areaTrianguloActual = (trianguloIzquierdo(3) - (trianguloSiguiente(1) - i)) *
0.5 * (i * 0.1);
%si el area del triangulo actual es mayor o igual al area del
%triangulo izquierdo, entonces
if(areaTrianguloActual >= areaTrianguloIzquierdo)
%encontramos la solucion, el nuevo tamao de la base del
%triangulo es:
nuevoTamanoBase = i;
break;
end;
end;
%la primera particion es el triangulo izquierdo
particionesTriangulo{1} = trianguloIzquierdo;
%movemos todas las particiones triangulo
for i = 2:1:numeroParticiones
%obtenemos los parametros de la particion anterior
particionAnterior = cell2mat(particionesTriangulo(i - 1));
%calculamos el primer parametro de la particion
extremoIzquierdo = particionAnterior(3) - nuevoTamanoBase;
%calculamos el tercer parametro de la particion
extremoDerecho = tamanoBase - nuevoTamanoBase + particionAnterior(3);

%calculamos el segundo parametro de la particion


extremoMedio = extremoIzquierdo + mitadTamanoBase;
%aadimos una nueva partcion con los parametros calculados
particionesTriangulo{i} = [extremoIzquierdo extremoMedio extremoDerecho];
end;
%obtenemos los parametros de la ultima particion
ultimaParticion = cell2mat(particionesTriangulo(size(particionesTriangulo, 2)));
%redimensionamos todos las particiones triangulos
for i = 1:1:size(particionesTriangulo, 2)
%redimensionamos el triangulo
particionesTriangulo{i} = cell2mat(particionesTriangulo(i)) * tamanoBase /
ultimaParticion(2);
%convertimos las particiones triangulo a algun tipo
switch(tipoFuncion)
%si el tipo de funcion a convertir es gaussmf, entonces
case 'gaussmf'
%la nueva particion es del tipo gaussmf
particionesTriangulo{i} = mf2mf(cell2mat(particionesTriangulo(i))
, 'trimf', tipoFuncion);
end;
end;
%devolvemos las particiones
particiones = particionesTriangulo;
end

PORCENTAJE DE SOLAPAMIENTO VS. FUNCIN DE PERTENENCIA.

Comparativa de resultados
%

20

50

80

Triangulo

Gauss

Comparativa de graficas de superficie


%

Triangulo

Gauss

20

50

80

Conclusin: comparando los resultados y las grficas de superficie, se puede observar


claramente como al aumentar el porcentaje de solapamiento disminuye el resultado de la salida al
defuzzificar. Esto sucede tanto para la funcin triangulo como para la funcin gaussiana.

Problema 3 Modelo Simulink (4 ptos.)


El motor de un molino de trigo requiere, para un funcionamiento normal, el ingreso de los granos de trigo
con una humedad relativa entre el 15.7 y 16.2 %. Si la humedad es baja el molino se esfuerza ms y por
lo tanto el consumo de corriente del motor principal se incrementa a 22.6 Amperes, provocando un dao
permanente en el sistema, si se mantiene en esta condicin durante demasiado tiempo. Por otro lado, si la
humedad del trigo es alta, el consumo del motor es bajo, alrededor de los 18 Amperes. Un consumo ideal
del motor oscila entre 19.2 a 21.1 Amperes.
Para incrementar la humedad se emplean rociadores de agua de tipo ON-OFF. Para reducir la humedad
se utiliza aire impulsado a gran velocidad por un ventilador, que es activado o desactivado segn se
requiera.
Disear mediante el Fuzzy Logic Toolbox, la interfaz grfica fuzzy y simular en el entorno de
Simulink el modelo fuzzy del molino asociado a un FLC (sistema de control fuzzy), que muestre la
operacin del sistema completo.
Debe decidir el tipo apropiado de controlador: P, PI, PD o PID. Mostrar las curvas de control
segn el modelo seleccionado. Ntese que se trata de un sistema con medicin indirecta; no se
cuenta con un medidor de humedad, pero s con un ampermetro que indica el consumo de
corriente del motor.
Desarrollo:
Lo primero que hemos hecho es realizar la interfaz grfica fuzzy de nuestro sistema en el Fuzzy
Logic Toolbox, para ello:
1. Hemos creado un FIS al que hemos llamado Molino.fis (El archivo se encuentra dentro de
la carpeta que contiene a este documento). En este caso, nuestro FIS recibe como entrada
el consumo de corriente del motor principal y como salida tenemos el estado en el que se
encuentran los rociadores o el ventilador ante dicho consumo.

2. La variable de entrada Consumo, la hemos definido en un rango que va desde los 16


Amperes hasta los 25 Amperes, ya que consideramos a este intervalo como el ms
significante para la operacin de nuestro sistema. Hemos identificado tres conjuntos, los
conjuntos Bajo y Alto son conjuntos Fuzzy con forma trapezoidal, mientras que el conjunto
Ideal, es un conjunto Crisp. Se utiliz esta representacin de los conjuntos para poder
indicar que cuando el consumo sea mayor a 21.1 amperes entonces automticamente se
prendan los rociadores y si el consumo es menor a 19.2 amperes entonces
automticamente se prenda el ventilador.
Nota: Si vamos View -> Rules (o apretamos Ctrl+5) Podemos ver cmo cambia
automticamente el estado de los rociadores o del ventilador si nos desviamos un poco del
lmite dado en el intervalo Ideal.

3. Las variables de Salida a las que llamamos Rociadores y Ventilador, tienen dos conjuntos
Crisp, a los que llamamos Encendido y Apagado. Utilizamos esa representacin para
indicar que nicamente nos interesan los valores cero (para indicar que esta pagado) y
uno (para indicar que esta encendido) para definir el estado de los Rociadores y del
Ventilador.

4. La Base de Reglas que hemos definido para nuestro FIS es la siguiente:

Ya creado nuestro FIS nos dirigimos a Simulink para poder simular como opera nuestro Sistema.
En este caso estamos hablando de un Sistema con Servo Control, el consumo ingresa, pero no
hay ninguna realimentacin que me permita corregir el consumo en el caso de que este sea muy
elevado. Nuestro Sistema implementado en Simulink y guardado como Molino_Simulink.mdl (El
archivo se encuentra dentro de la carpeta que contiene a este documento), es el siguiente:

Tenemos como entrada una seal sinusoidal con una amplitud de 4.5 amperes y un bias de 20.5
amperes dndonos el intervalo necesario para el FIS, es decir de 16 a 25 amperes. Presionamos
Start Simulation y obtenemos los siguientes resultados:

Hemos definido el tiempo de Simulacin en 10 segundos. Como dijimos la entrada es una seal
sinusoidal definida entre 16 y 25 Amperes, como salidas tenemos seales que pueden tomar el
valor 0 para indicar el estado apagado o 1 para indicar el estado encendido de los rociadores y del
ventilador. Como podemos ver el sistema funciona de manera correcta pero no nos avisa en el
caso de que el sistema sobrepase los 22.6 amperes, por lo que no es aconsejable esta
implementacin.

Para ello recurrimos a la implementacin de un sistema con realimentacin capaz de corregirme


este consumo elevado que puede llegar a daarme el sistema. Hemos optado por utilizar un
controlador P, el error ingresado es proporcional a la accin de control. La justificacin de esto es
clara en este caso, ya que a medida que el consumo vaya ms lejos de los 22.6 amperes, la
accin de control necesaria para corregir dicho consumo elevado debe tambin ser ms grande.
La recomendacin era utilizar un PD, pero creemos que la respuesta que nos da este controlador
es muy buena.

Como no disponemos de los conceptos necesarios para el desarrollo de la funcin de


transferencia hemos utilizado dos FIS, al primero lo llamamos MolinoP.fis y al segundo lo
llamamos Corrector.fis

MolinoP.fis tiene una nica variable de entrada que me representa el error entre un valor de
referencia o Set Point al que hemos definido como 20.15 amperes (rango medio del conjunto de
valores que forman parte del consumo ideal) y el consumo que va desde los 16 hasta los 25
amperes. Adems dispone de tres variables de salida, una de ellas me representa el estado de los
rociadores, la otra el estado del ventilador y la otra me representa si el sistema se encuentra o no
en peligro por haber superado el lmite de 22.6 amperes.

La variable de entrada Error tiene cuatro conjuntos, dos de ellos son Crisp (Peligroso e Ideal) y
dos son Fuzzy (Bajo y Alto) con forma triangular. Hemos utilizado esta representacin para indicar
que cuando el sistema me indique un error menor o igual a
-2.45 (Consumo superior a 22.6
amperes) entonces deberemos dar una seal de peligro y si es mayor a -2.45 entonces el sistema
deje de estar en peligro. Adems me permite indicar que mientras el error este definido entre -0.95
y 0.95 entonces nos encontremos en el estado ideal del sistema y no ser necesario realizar
ningn tipo de correccin sobre el mismo.

Las variables de Salida a las que llamamos Peligro, Rociadores y Ventilador, tienen dos conjuntos
Crisp, a los que llamamos Encendido y Apagado para las ltimas y para la primera S y No.
Utilizamos esa representacin para indicar que nicamente nos interesan los valores cero y uno
para definir el estado de los Rociadores, del Ventilador y del Sistema, para poder saber si est o
no, en Peligro.

La base de reglas es la siguiente:

Corrector.fis tiene una nica variable de entrada que me representa el error entre un valor de
referencia o Set Point al que hemos definido como 20.15 amperes y el consumo que va desde los

16 hasta los 25 amperes. Adems dispone de una variable de salida que me indica la correccin a
realizar sobre el consumo que ha ingresado al sistema, si el consumo supera los 22.6 amperes.

La variable de entrada dispone de tres conjuntos fuzzy con forma triangular que me indican un
Error Bajo, un Error Alto y un Error Medio. Lamentablemente no disponemos de la informacin
suficiente para definir una forma particular para las funciones de pertenencia as que hemos
optado por la forma estndar que es la triangular.

La variable de salida tambin dispone de tres conjuntos fuzzy con forma triangular que me indican
si la accin de control o la correccin sobre el consumo es Baja, Alta o Intermedia, dependiendo
por supuesto del error ingresado al FIS. Lamentablemente no disponemos de la informacin
suficiente para definir una forma particular para las funciones de pertenencia as que hemos
optado por la forma estndar que es la triangular.

La base de reglas es la siguiente:

Ya creados nuestros FIS nos dirigimos a Simulink para poder simular como opera nuestro
Sistema. En este caso estamos hablando de un Sistema con Realimentacin, el consumo ingresa,

y dicha realimentacin me permite corregir el consumo en el caso de que este sea muy elevado,
es decir superior a los 22.6 amperes. Nuestro Sistema implementado en Simulink y guardado
como MolinoP_Simulink.mdl (El archivo se encuentra dentro de la carpeta que contiene a este
documento), es el siguiente:

El tiempo de Simulacin se estableci en 30 segundos con un paso fijo de 0.1 segundos, pero,
Cmo opera nuestro Sistema? Primeramente generamos un error tomando el Set Point y un
valor de Consumo que se genera a partir de una funcin sinusoidal. Se coloca posteriormente un
Transport Delay para que este error salga del bloque a los 0.2 segundos dndome como salida
hasta ese entonces el valor 0 que es el que tomaremos como error inicial. En base a ese error, mi
sistema opera y me devuelve una salida realimentada (es decir, la accin de control) que corregir
el error que tenamos inicialmente, el sistema entonces operara nuevamente dndome una salida
igual a cero, indicndome que se ha corregido el error.
Despus de ese lapso de tiempo de 0,2 segundos y el Transport Delay deja salir el error calculado
y procederemos a corregir dicho error si es necesario. El sistema seguir operando hasta alcanzar
los 30 segundos.
La grafica de Control, donde ponemos el error, expresado en amarillo y la accin de control en
violeta, es la siguiente:

El resultado expresado es bastante consistente. Cuando el error es mayor o igual a -2.45


entonces, que es la diferencia entre el valor de referencia y el consumo que ha ingresado al
sistema, entonces nuestro controlador tratara de corregir dicho error aplicando la accin de control
correspondiente, de esta forma evitaremos que el sistema quede inoperativo.

You might also like