-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFuzzyAirconController.java
391 lines (326 loc) · 15.7 KB
/
FuzzyAirconController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
//import java.util.*;
//import javax.swing.*;
import processing.core.*;
import com.fuzzylite.*;
import com.fuzzylite.defuzzifier.*;
import com.fuzzylite.norm.s.*;
import com.fuzzylite.norm.t.*;
import com.fuzzylite.rule.*;
import com.fuzzylite.term.*;
import com.fuzzylite.variable.*;
import controlP5.*;
// Listener class to handle events on the dial control
class TargetTempListener implements ControlListener {
private int targetTemp;
TargetTempListener(){this.targetTemp = 18;}
public void controlEvent(ControlEvent theEvent) {
targetTemp = (int)theEvent.getController().getValue();
}
public int getTargetTemp(){return targetTemp;}
}
// Listener class to handle events on the checkbox control
class CheckboxListener implements ControlListener {
private int active;
CheckboxListener(){this.active = 0;}
public void controlEvent(ControlEvent theEvent) {
active = (int)theEvent.getController().getValue();
}
public boolean isActive(){return active == 1;}
}
public class FuzzyAirconController extends PApplet{
private final int INITIAL_TEMP = 18;
// Step vars to control perlin noise
private float t1 = (float) 3;
// Current room temperature
private float roomTemp;
private float targetTemp;
// AC action (-/+)
private float acCommand;
// Setup some colours
private int blue = color(0,174,253);
private int red = color(255,0,0);
private int black = color(0,0,0);
private int grey = color(240,240,240);
//private int white = color(255,255,255);
private int green = color(0,204,102);
// Fuzzy Logic objects
private Engine engine;
private InputVariable inputVariable1;
private InputVariable inputVariable2;
private OutputVariable outputVariable;
private RuleBlock ruleBlock;
private ControlP5 cp5;
private TargetTempListener targetTempListener;
private CheckboxListener acPowerListener;
private Chart tempChart;
public void settings(){
size(800, 360);
}
public void createFuzzyEngine(){
// Create the engine
engine = new Engine();
engine.setName("FuzzyAirconController");
inputVariable1 = new InputVariable();
inputVariable1.setEnabled(true);
inputVariable1.setName("temperature");
inputVariable1.setRange(0, 40.00);//added adam
// TODO
// Set the range and terms for the room temperature input
//added adam
inputVariable1.addTerm(new Triangle("toocold",0, 0, 10));
inputVariable1.addTerm(new Triangle("cold",5, 10, 18));
inputVariable1.addTerm(new Triangle("warm",15, 20, 25 ));
inputVariable1.addTerm(new Triangle("hot", 20, 30, 35));
inputVariable1.addTerm(new Triangle("toohot", 30, 40,40));
engine.addInputVariable(inputVariable1);
inputVariable2 = new InputVariable();
inputVariable2.setEnabled(true);
inputVariable2.setName("target");
inputVariable2.setRange(15, 35);
// TODO
// Set the range and terms for the target temperature input
inputVariable2.setRange(0, 40);
// Add each term for the Linguistic variable
inputVariable2.addTerm(new Triangle("vlow", 0 , 5, 10));
inputVariable2.addTerm(new Trapezoid("low", 5 ,10 , 12.5, 17.5));//i want colder
inputVariable2.addTerm(new Trapezoid("normal",12.5, 17.5 ,22.5,25 ));//i want normal
inputVariable2.addTerm(new Trapezoid("high", 22.5, 25, 30,35));
inputVariable2.addTerm(new Trapezoid("vhigh", 30 , 35, 37.5,40));//i want hot
// Add the variable to the fuzzy engine
engine.addInputVariable(inputVariable2);
//engine.addInputVariable(inputVariable2);
outputVariable = new OutputVariable();
outputVariable.setEnabled(true);
outputVariable.setName("command");
outputVariable.setRange(-10, 10);
// How should the rules be accumulated
outputVariable.fuzzyOutput().setAccumulation(new Maximum());
// How will the output be Defuzzified?
outputVariable.setDefuzzifier(new Centroid(200));
outputVariable.setDefaultValue(0.000);
outputVariable.setLockValidOutput(false);
outputVariable.setLockOutputRange(false);
//what should the ac do
outputVariable.addTerm(new Trapezoid("vlow",-10, -8.5,-6.5, -4.5));
outputVariable.addTerm(new Trapezoid("low",-6.5, -4.5, -2,0));
outputVariable.addTerm(new Triangle("normal",-1 , 0 , 1));
outputVariable.addTerm(new Trapezoid("high", 0 , 2 , 4.5, 6.5));
outputVariable.addTerm(new Trapezoid("vhigh",4.5, 6.5, 8.5, 10));
// Add the variable to the fuzzy engine
engine.addOutputVariable(outputVariable);
// TODO
// Set the range and terms for the command output
engine.addOutputVariable(outputVariable);
// Setup the inference rules
ruleBlock = new RuleBlock();
ruleBlock.setEnabled(true);
ruleBlock.setName("Rule Block");
// Set up fuzzy functions for AND, OR and NOT
ruleBlock.setConjunction(new Minimum());
ruleBlock.setDisjunction(new Maximum());
ruleBlock.setActivation(new Minimum());
// Add the rules as follows
//low end ( 0 to 18)
ruleBlock.addRule(Rule.parse("if (temperature is warm) and (target is low) then command is low", engine));
ruleBlock.addRule(Rule.parse("if (temperature is warm) and (target is normal) then command is normal", engine));
ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is normal) then command is vhigh", engine));
ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is low) then command is normal", engine));
ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is vlow) then command is vlow", engine));
ruleBlock.addRule(Rule.parse("if (temperature is toocold) and (target is vlow) then command is normal", engine));
ruleBlock.addRule(Rule.parse("if (temperature is toocold) and (target is low) then command is high", engine));
//high end (19 to 40)#
ruleBlock.addRule(Rule.parse("if (temperature is warm) and (target is high) then command is high", engine));
ruleBlock.addRule(Rule.parse("if (temperature is hot) and (target is normal) then command is vlow", engine));
ruleBlock.addRule(Rule.parse("if (temperature is hot) and (target is high) then command is normal", engine));
ruleBlock.addRule(Rule.parse("if (temperature is hot) and (target is vhigh) then command is vhigh", engine));
ruleBlock.addRule(Rule.parse("if (temperature is toohot) and (target is high) then command is low", engine));
ruleBlock.addRule(Rule.parse("if (temperature is toohot) and (target is normal) then command is low", engine));
ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is vhigh) then command is vhigh", engine));
ruleBlock.addRule(Rule.parse("if (temperature is toohot) and (target is low) then command is vlow", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is toocold) and (target is high) then command is high", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is toocold) and (target is normal) then command is high", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is toocold) and (target is low) then command is normal", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is low) then command is low", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is normal) then command is high", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is cold) and (target is high) then command is high", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is warm) and (target is low) then command is low", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is warm) and (target is normal) then command is normal", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is warm) and (target is high) then command is high", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is hot) and (target is low) then command is low", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is hot) and (target is normal) then command is normal", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is hot) and (target is high) then command is high", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is toohot) and (target is low) then command is low", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is toohot) and (target is normal) then command is low", engine));
// ruleBlock.addRule(Rule.parse("if (temperature is toohot) and (target is high) then command is normal", engine));
// TODO - Add the rest of the rules - see lab sheet
// Add the rule block to the fuzzy engine
engine.addRuleBlock(ruleBlock);
}
public void setup(){
roomTemp = INITIAL_TEMP;
acCommand = 0f;
// Set the fuzzy logic engine including inputs, outputs and rules
createFuzzyEngine();
// Create a ControlP5 object for the user interface
cp5 = new ControlP5(this);
// Create the target temperature dial
cp5.addKnob("Target Temperature")
.setRange(5,35) // Most room thermostats have this range - don't change
.setValue(INITIAL_TEMP)
.setPosition(180,180)
.setRadius(65)
.setColorCaptionLabel(black)
.setDragDirection(Knob.VERTICAL)
;
// Create a new listener for the target temperature slider
targetTempListener = new TargetTempListener();
// Add a listener so we can receive slider events
cp5.getController("Target Temperature").addListener(targetTempListener);
cp5.addCheckBox("AC Checkbox")
.setPosition(210, 150)
.setColorForeground(color(0))
.setColorActive(blue)
.setColorLabel(color(0))
.setSize(20, 20)
.addItem("AC On/Off", 0)
;
acPowerListener = new CheckboxListener();
// Add a listener so we can receive slider events
cp5.getController("AC On/Off").addListener(acPowerListener);
tempChart = cp5.addChart("Temperature")
.setPosition(350, 160)
.setColorCaptionLabel(black)
.setSize(400, 150)
.setRange(-15, 45)
.setColorBackground(grey)
.setLabelVisible(true)
.setView(Chart.LINE) // use Chart.LINE, Chart.PIE, Chart.AREA, Chart.BAR_CENTERED
;
// Setup the dataset for outside temperature
tempChart.addDataSet("Outside");
tempChart.setData("Outside", new float[2000]);
// Setup the dataset for room temperature
tempChart.addDataSet("Room");
tempChart.setData("Room", new float[2000]);
tempChart.setColors("Room", red);
// Setup the dataset for target temperature
tempChart.addDataSet("Target");
tempChart.setData("Target", new float[2000]);
tempChart.setColors("Target", green);
}
private void drawThermometer(){
// Draw the thermometer
stroke(0);
line(100,300,100,150); // Left side
line(105,300,105,150); // Right side
line(100,300,105,300); // Bottom
fill(red);
ellipse(103,310,19,19);
// Draw the tick marks and labels
fill(black);
line(90, 300, 100, 300); // Zero tick
text("0",80,305);
line(95, (int)(300-18.75), 100, (int)(300-18.75)); // 5 tick
line(90, (int)(300-37.5), 100, (int)(300-37.5)); // 10 tick
text("10",73,(int)(300-37.5+5));
line(95,(int)(300-56.25), 100, (int)(300-56.25)); // 15 tick
line(90, 300-75, 100, 300-75); // 20 tick
line(95, (int)(300-93.75), 100, (int)(300-93.75)); // 25 tick
text("20",73,(int)(300-75+5));
line(90, (int)(300-112.5), 100, (int)(300-112.5)); // 30 tick
line(95, (int)(300-131.25), 100, (int)(300-131.25)); // 35 tick
text("30",73,(int)(300-112.5+5));
line(90, 300-150, 100, 300-150); // 40 tick
text("40",73,(int)(300-150+5));
}
private void drawTempLevel(float lev){
// No outline for the water
noStroke();
// Set the fill color
fill(red);
// Draw the rect for the temp level
double ratio = 150*(lev / 40);
rect(101,(int)(300-ratio),4,(int)(ratio+1));
}
private void drawInfo(float ot, float rt, float tt, float ac){
// Output the room temp and target temp
fill(black);
text("Outside Temp: " + ot,50,35);
text("Room Temp: " + rt,50,50);
text("Target Temp: " + tt,50,65);
text("AC Command: " + ac,50,80);
// Chart legend
fill(blue);
rect(350,145, 10,10);
fill(black);
text("Outside", 365, 155);
// Chart legend
fill(red);
rect(420,145, 10,10);
fill(black);
text("Room", 435, 155);
// Chart legend
fill(green);
rect(480,145, 10,10);
fill(black);
text("Target", 495, 155);
}
private float fuzzyACEvaluate(float rt, float tt){
//System.out.println(rt);
// Load the input variables
inputVariable1.setInputValue(rt); // room temp
inputVariable2.setInputValue(tt); // target temp
// Run the engine
engine.process();
// Get the output
return (float)(outputVariable.defuzzify());
}
// Run the system
public void drawSystem(){
// Clear the background
background(255);
// Draw all the static visual components
drawThermometer();
// Constant change
float outsideTemp = noise(t1);
// Map the demand to a value between -1 and 1.5
outsideTemp = map(outsideTemp,0f,1f,-10.0f,40f);
// Calculate the difference between the outside temp and room temp
// We will use a scaling factor to make the change in temp gradual
float tempDelta = (roomTemp - outsideTemp) * 0.001f;
// Get the target temperature
targetTemp = targetTempListener.getTargetTemp();
// Run the fuzzy engine with inputs and get controller output
if (acPowerListener.isActive()){
// TODO: uncomment the call to fuzzyACEvaluate below
// Run the fuzzy controller on our inputs and get an output
acCommand = fuzzyACEvaluate(roomTemp, targetTemp);
// Apply the pump action to the current level
// new roomTemp will be affected by the delta (room - outside) and the AC fuzzy output
roomTemp = (roomTemp - tempDelta + (acCommand * 0.01f));
}
else if (!acPowerListener.isActive()){
// If the AC is not active then the room temp will
// only be affected the outside temp
roomTemp = roomTemp - tempDelta;
}
// Update the temperature level on screen
drawTempLevel(roomTemp);
// Draw the instrumentation panel
drawInfo(outsideTemp, roomTemp, targetTemp, acCommand);
// Increment time step for Perlin noise
t1 += 0.001;
// Push the data from this time step on to the live graph
tempChart.push("Outside", outsideTemp);
tempChart.push("Room", roomTemp);
tempChart.push("Target", targetTemp);
}
// Draw each frame of animation
public void draw(){
drawSystem();
}
// Main method
public static void main(String[] args) {
PApplet.main("FuzzyAirconController");
}
}