Proyecto Estación Meteorológica 5: Análisis y Tratamiento de Datos Mediante Matlab
Análisis y Tratamiento de Datos Mediante Matlab
Para terminar de forma adecuada el proyecto, se ha decidido darles una razón de ser a los datos recogidos. Con la ayuda del software Matlab se hace el control de la temperatura y la humedad de la habitación utilizando un controlador fuzzy. La habitación en cuestión tendrá un climatizador que se ocupará de calentar, enfriar, humidificar o deshumidificar el aire de la sala. El climatizador estará formado por los siguientes elementos:
- Un intercambiador de calor para enfriar el aire.
- Un contenedor para retirar el agua condensada.
- Una resistencia para calentar el aire.
- Un humidificador.
Pasando al código de Matlab, este cuenta con 3 partes principales: la obtención de datos de ThingSpeak, el controlador fuzzy y el Simulink en el cual se conseguirán las acciones de control.
Tal y como se ha mencionado, primero hay que obtener los datos de entrada, los cuales están almacenados en los servidores de ThingSpeak. Teniendo en cuenta que la temperatura y la humedad no varían mucho en un minuto, se ha decidido que como datos de entrada se usarán todos los datos del último minuto, con las cuales se calculan los datos medios de ese intervalo. Además, al ser un sistema no crítico (ya que, al ser una habitación normal y los actuadores no ser demasiado potentes, los cambios en las condiciones no son muy drásticos) el periodo entre obtención de datos es de unos 15 segundos, aunque no cumple requisitos de tiempo real.
close all; clear all; clc; | |
%% Parámetros | |
Channel_1_ID = 702692; | |
Channel_2_ID = 702693; | |
CantDatos = 3; | |
%% Variables | |
contador = 1; | |
%% Programa cíclico | |
while true | |
%% Importar datos del último minuto | |
% https://es.mathworks.com/help/thingspeak/thingspeakread.html#bvio0ym | |
[canal1, timestamps1] = thingSpeakRead(Channel_1_ID, 'Fields', [1,2],... | |
'NumPoints', CantDatos); | |
[canal2, timestamps2] = thingSpeakRead(Channel_2_ID, 'Fields', [1,2],... | |
'NumPoints', CantDatos); | |
[x1 y1] = size(canal1); | |
[x2 y2] = size(canal2); | |
if x1 > x2 | |
varAux = x1; | |
else | |
varAux = x2; | |
end | |
% Se juntan todos los datos en una sola matriz. Además, se crea otra matriz | |
% para unificar todos los timestamps | |
for j = 1:varAux | |
r = (j * 2) - 1; | |
s = j * 2; | |
% Se ordenan los datos teniendo en cuenta el momento en el que han sido | |
% recividos en ThingSpeak (en las variables timestamps). Además, | |
% primero se asegura de que el dato existe. | |
if j <= x1 | |
if j <= x2 | |
if timestamps1(j) < timestamps2(j) | |
data(r, :) = canal1(j, :); | |
data(s, :) = canal2(j, :); | |
timestamps(r, :) = timestamps1(j, :); | |
timestamps(s, :) = timestamps2(j, :); | |
else | |
data(r, :) = canal2(j, :); | |
data(s, :) = canal1(j, :); | |
timestamps(r, :) = timestamps2(j, :); | |
timestamps(s, :) = timestamps1(j, :); | |
end | |
else | |
data(r, :) = canal1(j, :); | |
timestamps(r, :) = timestamps1(j, :); | |
end | |
elseif j <= x2 | |
data(r, :) = canal2(j, :); | |
timestamps(r, :) = timestamps2(j, :); | |
end | |
end | |
% Se borran las variables innecesarias por claridad y ahorrar espacio | |
clear canal1 canal2 timestamps1 timestamps2 x1 x2 y1 y2 varAux j r s; | |
%% Graficar los datos obtenidos | |
figure(1); | |
subplot(2, 1, 1); | |
plot(timestamps, data(:, 1), 'r-o', 'LineWidth', 2); | |
grid on; | |
title('Temperatura (ºC)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
tempMax = max(data(:, 1)); | |
tempMin = min(data(:, 1)); | |
ylim([tempMin-5 tempMax+5]); | |
subplot(2, 1, 2); | |
plot(timestamps, data(:, 2), '-o', 'LineWidth', 2); | |
grid on; | |
title('Humedad (%)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
humMax = max(data(:, 2)); | |
humMin = min(data(:, 2)); | |
ylim([humMin-5 humMax+5]); |
Una vez se han obtenido los datos y se han preparado para poder ser utilizados, se diseña el controlador. Este está formado por dos entradas (media de la humedad y la temperatura) y tres salidas (calentar, humidificar y enfriar). Las entradas y salidas han sido relacionadas mediante 34 reglas, una regla para cada combinación de entradas posibles. Las señales de control (las salidas) se han programado para un climatizador con los niveles de actuación definidos a continuación:
- Calentar: CalentarN1, CalentarN2 y CalentarN3.
- Enfriar: FrioN1, FrioN2 y FrioN3.
- Humidificar: HumedecerN1 y HumedecerN2.
*A tener en cuenta: para deshumidificar el aire, primero se enfriará el aire con el fin de condensar la humedad del aire. El agua condensada se retirará mediante un contenedor, y por último, se volverá a calentar el aire (en caso de querer mantener o aumentar la temperatura).
[System] | |
Name='climatizador' | |
Type='mamdani' | |
Version=2.0 | |
NumInputs=2 | |
NumOutputs=3 | |
NumRules=34 | |
AndMethod='min' | |
OrMethod='max' | |
ImpMethod='min' | |
AggMethod='max' | |
DefuzzMethod='centroid' | |
[Input1] | |
Name='Temperatura' | |
Range=[-2 52] | |
NumMFs=7 | |
MF1='MuyBaja':'trapmf',[-20.87 -3.589 3.4 11.5] | |
MF2='Baja':'trimf',[0.00016 11.5 20] | |
MF3='muyAlta':'trapmf',[35.2 43.3 52 68.2] | |
MF4='Adecuada':'trimf',[16.7428571428572 22.1428571428571 27.5428571428571] | |
MF5='Alta':'trimf',[27.6857142857143 35.7857142857143 43.8857142857143] | |
MF6='ModeradaBaja':'trimf',[9.64285714285715 17.7428571428571 25.8428571428571] | |
MF7='ModeradaAlta':'trimf',[20.1571428571429 28.2571428571429 36.3571428571429] | |
[Input2] | |
Name='Humedad' | |
Range=[15 95] | |
NumMFs=5 | |
MF1='Baja':'trimf',[19.021164021164 39.021164021164 59.021164021164] | |
MF2='Adecuada':'trimf',[40 55 70] | |
MF3='Alta':'trimf',[50.7671957671958 70.7671957671958 90.7671957671958] | |
MF4='muyBaja':'trapmf',[-60.4237566137566 -29.0837566137566 26.3862433862434 38.3862433862434] | |
MF5='muyAlta':'trapmf',[69.7089947089947 81.7089947089947 96.1089947089947 160.108994708995] | |
[Output1] | |
Name='Calefactor' | |
Range=[0 100] | |
NumMFs=3 | |
MF1='CalentarN1':'trimf',[-0 25 50] | |
MF2='CalentarN2':'trimf',[29.7380952380952 55.2380952380952 79.7380952380952] | |
MF3='CalentarN3':'trapmf',[65.4761904761905 90.4761904761905 110.27619047619 120.27619047619] | |
[Output2] | |
Name='Humidificador' | |
Range=[0 100] | |
NumMFs=2 | |
MF1='HumedecerN1':'trimf',[0 35 70] | |
MF2='HumedecerN2':'trapmf',[35 70 100 109] | |
[Output3] | |
Name='IntercambiadorDeCalor' | |
Range=[0 100] | |
NumMFs=3 | |
MF1='FrioN1':'trimf',[0 25 50] | |
MF2='FrioN2':'trimf',[34 60 84] | |
MF3='FrioN3':'trapmf',[63.0952380952381 88.0952380952381 108.095238095238 109.095238095238] | |
[Rules] | |
4 1, 0 1 0 (1) : 1 | |
4 4, 0 2 0 (1) : 1 | |
4 3, 1 2 1 (1) : 1 | |
4 5, 2 2 2 (1) : 1 | |
7 2, 0 0 1 (1) : 1 | |
7 1, 0 1 2 (1) : 1 | |
7 4, 0 2 1 (1) : 1 | |
7 3, 1 0 2 (1) : 1 | |
7 5, 2 0 3 (1) : 1 | |
5 2, 0 0 2 (1) : 1 | |
5 1, 0 1 2 (1) : 1 | |
5 4, 0 2 2 (1) : 1 | |
5 3, 1 0 3 (1) : 1 | |
5 5, 1 0 3 (1) : 1 | |
3 2, 0 0 3 (1) : 1 | |
3 1, 0 1 3 (1) : 1 | |
3 4, 0 2 3 (1) : 1 | |
3 3, 0 0 3 (1) : 1 | |
3 5, 0 0 3 (1) : 1 | |
6 2, 1 0 0 (1) : 1 | |
6 1, 1 1 0 (1) : 1 | |
6 4, 1 2 0 (1) : 1 | |
6 3, 2 0 1 (1) : 1 | |
6 5, 3 0 2 (1) : 1 | |
2 2, 2 0 0 (1) : 1 | |
2 1, 2 1 0 (1) : 1 | |
2 4, 2 2 0 (1) : 1 | |
2 3, 2 0 0 (1) : 1 | |
2 5, 3 0 1 (1) : 1 | |
1 2, 3 0 0 (1) : 1 | |
1 1, 3 1 0 (1) : 1 | |
1 4, 3 2 0 (1) : 1 | |
1 3, 3 0 0 (1) : 1 | |
1 5, 3 0 0 (1) : 1 |
Además de diseñar el controlador, el cual se implementará en Simulink más adelante, se grafican tanto las entradas como las salidas para que el usuario tenga mayor conocimiento sobre lo que está pasando.
%% Climatizador | |
tiempo = contador; | |
mediaTemp = mean(data(:, 1)); | |
mediaHum = mean(data(:, 2)); | |
TempHum = [tiempo mediaTemp mediaHum]; | |
% Tabla de variables de las entradas | |
Tiempo(contador) = TempHum(1); | |
Temp(contador) = TempHum(2); | |
Hum(contador) = TempHum(3); | |
% Ejecutar el archivo Simulink del controlador fuzzy | |
sim('ControlClimatizador.slx'); | |
% Guardar las variables de salida en tablas | |
Calefactor(contador) = salida.Data(1,1); | |
Humidificador(contador) = salida.Data(1,2); | |
Intercambiador(contador) = salida.Data(1,3); | |
% Graficar los resultados y las entradas | |
figure(2); | |
subplot(3, 1, 1); | |
plot(Tiempo, Temp, 'r-o', 'LineWidth', 2); | |
grid on; | |
title('Temperatura (ºC)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
tempMax = max(data(:, 1)); | |
tempMin = min(data(:, 1)); | |
ylim([tempMin-5 tempMax+5]); | |
subplot(3, 1, 2); | |
plot(Tiempo, Hum, '-o', 'LineWidth', 2); | |
grid on; | |
title('Humedad (%)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
humMax = max(data(:, 2)); | |
humMin = min(data(:, 2)); | |
ylim([humMin-5 humMax+5]); | |
subplot(3, 1, 3); | |
% stairs(Tiempo, Calefactor, Tiempo, Humidificador, Tiempo, Intercambiador); | |
hold on; | |
stairs(Tiempo, Calefactor, 'LineWidth', 2) | |
stairs(Tiempo, Humidificador, 'LineWidth', 2) | |
stairs(Tiempo, Intercambiador, 'LineWidth', 2) | |
grid on; | |
title('Señal de Control (%)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
legend('Calefactor', 'Humidificador', 'Intercambiador de Calor'); | |
ylim([0 100]); | |
contador = contador + 1; | |
pause(10); | |
end |
Por último, se diseña el Simulink en el cual se ejecutará el controlador fuzzy, el cual calculará las salidas correspondientes de acuerdo a las entradas. Además, todos estos datos van a poder ser observados tanto en el Simulink como en Matlab.
Al final, juntando todas las partes, el código de Matlab tiene el siguiente aspecto:
close all; clear all; clc; | |
%% Parámetros | |
Channel_1_ID = 702692; | |
Channel_2_ID = 702693; | |
CantDatos = 3; | |
%% Variables | |
contador = 1; | |
%% Programa cíclico | |
while true | |
%% Importar datos del último minuto | |
% https://es.mathworks.com/help/thingspeak/thingspeakread.html#bvio0ym | |
[canal1, timestamps1] = thingSpeakRead(Channel_1_ID, 'Fields', [1,2],... | |
'NumPoints', CantDatos); | |
[canal2, timestamps2] = thingSpeakRead(Channel_2_ID, 'Fields', [1,2],... | |
'NumPoints', CantDatos); | |
[x1 y1] = size(canal1); | |
[x2 y2] = size(canal2); | |
if x1 > x2 | |
varAux = x1; | |
else | |
varAux = x2; | |
end | |
% Se juntan todos los datos en una sola matriz. Además, se crea otra matriz | |
% para unificar todos los timestamps | |
for j = 1:varAux | |
r = (j * 2) - 1; | |
s = j * 2; | |
% Se ordenan los datos teniendo en cuenta el momento en el que han sido | |
% recividos en ThingSpeak (en las variables timestamps). Además, | |
% primero se asegura de que el dato existe. | |
if j <= x1 | |
if j <= x2 | |
if timestamps1(j) < timestamps2(j) | |
data(r, :) = canal1(j, :); | |
data(s, :) = canal2(j, :); | |
timestamps(r, :) = timestamps1(j, :); | |
timestamps(s, :) = timestamps2(j, :); | |
else | |
data(r, :) = canal2(j, :); | |
data(s, :) = canal1(j, :); | |
timestamps(r, :) = timestamps2(j, :); | |
timestamps(s, :) = timestamps1(j, :); | |
end | |
else | |
data(r, :) = canal1(j, :); | |
timestamps(r, :) = timestamps1(j, :); | |
end | |
elseif j <= x2 | |
data(r, :) = canal2(j, :); | |
timestamps(r, :) = timestamps2(j, :); | |
end | |
end | |
% Se borran las variables innecesarias por claridad y ahorrar espacio | |
clear canal1 canal2 timestamps1 timestamps2 x1 x2 y1 y2 varAux j r s; | |
%% Graficar los datos obtenidos | |
figure(1); | |
subplot(2, 1, 1); | |
plot(timestamps, data(:, 1), 'r-o', 'LineWidth', 2); | |
grid on; | |
title('Temperatura (ºC)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
tempMax = max(data(:, 1)); | |
tempMin = min(data(:, 1)); | |
ylim([tempMin-5 tempMax+5]); | |
subplot(2, 1, 2); | |
plot(timestamps, data(:, 2), '-o', 'LineWidth', 2); | |
grid on; | |
title('Humedad (%)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
humMax = max(data(:, 2)); | |
humMin = min(data(:, 2)); | |
ylim([humMin-5 humMax+5]); | |
%% Climatizador | |
tiempo = contador; | |
mediaTemp = mean(data(:, 1)); | |
mediaHum = mean(data(:, 2)); | |
TempHum = [tiempo mediaTemp mediaHum]; | |
% Tabla de variables de las entradas | |
Tiempo(contador) = TempHum(1); | |
Temp(contador) = TempHum(2); | |
Hum(contador) = TempHum(3); | |
% Ejecutar el archivo Simulink del controlador fuzzy | |
sim('ControlClimatizador.slx'); | |
% Guardar las variables de salida en tablas | |
Calefactor(contador) = salida.Data(1,1); | |
Humidificador(contador) = salida.Data(1,2); | |
Intercambiador(contador) = salida.Data(1,3); | |
% Graficar los resultados y las entradas | |
figure(2); | |
subplot(3, 1, 1); | |
plot(Tiempo, Temp, 'r-o', 'LineWidth', 2); | |
grid on; | |
title('Temperatura (ºC)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
tempMax = max(data(:, 1)); | |
tempMin = min(data(:, 1)); | |
ylim([tempMin-5 tempMax+5]); | |
subplot(3, 1, 2); | |
plot(Tiempo, Hum, '-o', 'LineWidth', 2); | |
grid on; | |
title('Humedad (%)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
humMax = max(data(:, 2)); | |
humMin = min(data(:, 2)); | |
ylim([humMin-5 humMax+5]); | |
subplot(3, 1, 3); | |
% stairs(Tiempo, Calefactor, Tiempo, Humidificador, Tiempo, Intercambiador); | |
hold on; | |
stairs(Tiempo, Calefactor, 'LineWidth', 2) | |
stairs(Tiempo, Humidificador, 'LineWidth', 2) | |
stairs(Tiempo, Intercambiador, 'LineWidth', 2) | |
grid on; | |
title('Señal de Control (%)', 'FontSize', 12, 'FontWeight', 'Bold'); | |
xlabel('Fecha', 'FontWeight', 'Bold'); | |
legend('Calefactor', 'Humidificador', 'Intercambiador de Calor'); | |
ylim([0 100]); | |
contador = contador + 1; | |
pause(10); | |
end |
Comentarios
Publicar un comentario