Obtain Plant’s Health Conditions with Fuzzy Logic Algorithm

Andrew Yong Zheng Dao
8 min readJul 11, 2020

--

What is fuzzy logic?

Fuzzy logic is a way of reasoning that simulates human reasoning. The logic imitates how human makes decisions that involve all intermediate possibilities between the answer of YES and NO. The reasoning process involves the use of a mathematical formula which is known as the membership function.

Membership Function

The membership function is a mathematical function that use in fuzzy logic to calculate the interval value and determine the possible outcomes accordingly. The interval value will modify the consequences, THEN part after evaluating the antecedents, IF part.

Fuzzification and defuzzification

Fuzzification is a process that converts the input value into linguistic qualifiers and the input will then map and generate output based on fuzzy rules. Moreover, the defuzzification process is to obtain an average result from all the fuzzification results.

Fuzzy Logic and Plant Condition

Fuzzy Logic is designed to determine the plant’s condition. The algorithm represents a plant to illustrate or simulate the speaking style of humans to express its conditions based on measurable data. The data include temperature value, light intensity value, soil moisture value, and ambient humidity value. These data are passed as input and being processed by the algorithm to obtain the current level of each measurement in terms of linguistic variables respectively. The linguistic variables are set as the antecedents (in the IF clause) and the plant’s health condition is set as the consequences (in the ELSE clause).

This application helps to specify the plant’s condition and clarify the requirements of the plant in detail in order to improve the current health status of the plant.

The input data that are required from a plant

  1. Light Intensity (lux)
  2. Temperature (%)
  3. Soil Moisture (%)
  4. Ambient Humidity (%)

Triangular Membership Function

The triangular membership function is used to characterize the input data and the linguistic variable used for fuzzy reasoning. The mathematical function of the triangular membership function is shown below:

The suggested properties of each measurement variable

The suggested properties of the overall plant’s health condition

Some suggested fuzzy rules

The defuzzification

The weighted average method is applied in the defuzzification process. The formula of the weighted average method is shown below:

Fuzzy Logic Algorithm (In Javascript)

Step 1: Initialise a fuzzy set

//Initialize each fuzzy set with input variable name, the name of //membership function, and the range of each membership function.
let fuzzyset = {
variables_input:[
// Fuzzify light intensity level
{
name: 'LightIntensity',
setsName: ['Dark', 'Normal', 'Bright'],
sets:[[0,5000,10000],[9000,17000,25000],[24000,67500,111000],]
},
//Fuzzify temperature level
{
name: 'Temperature',
setsName: ['Cool', 'Normal', 'Hot'],
sets:[[0,23,46],[44,60,76],[74,87,100],]
},
// Fuzzify Soil Moisture level
{
name: 'SoilMoisture',
setsName: ['Dry', 'Normal', 'Wet'],
sets:[[0,20,40],[30,50,70],[60,80,100],]
},
//Fuzzify ambient humidity level
{
name: 'AmbientHumidity',
setsName: ['Low', 'Normal', 'High'],
sets: [[0,20,40],[30,50,70],[60,80,100],]
}
],
};
//fuzzify tips output
let tips_output=
{
name: 'Plant Condition',
setsName: ['Unhealthy', 'Healthy', 'Very Healthy'],
sets:[[0,20,40],[30,50,70],[60,80,100],]
};

Step 2: Initialize the Fuzzy Rules

/*Define some IF-ELSE rules set whereby condition array store the variable names for 
light intensity, temperature, soil moisture and ambient humidity respectively and associated with
message which displayed later*/
let fuzzysetRulesBase = [{condition :['Dark', 'Cool', 'Dry','High'],
message: "I am in extremely unhealthy condition. Rest in Peace~"
},
{condition :['Normal', 'Cool', 'Dry', 'Normal'],
message: "I am in fairly healthy condition because the soil is dry! I need water!"
},
{condition :['Normal', 'Normal', 'Dry', 'Normal'],
message: "I need water to recover to normal condition."
},
{condition :['Dark', 'Normal', 'Dry', 'Normal'],
message: "The condition is not suitable for me. I need sunlight and water!"
},
{condition :['Dark', 'Normal', 'Normal', 'Normal'],
message: "The condition is not suitable for me. I need sunlight to produce foods!"
},
{condition :['Dark', 'Cool', 'Normal', 'High'],
message: "I am not in an ideal condition! The surrounding is too cool and my transpiration rate is low!"
},
{condition :['Dark', 'Cool', 'Wet', 'High'],
message: "I am not in an ideal condition! The surrounding is too cool and my transpiration rate is low!"
},
{condition :['Bright','Normal','Wet','High'],
message: "I am healthy but the surrounding humidity is too wet."
},
{condition :['Bright', 'Hot', 'Dry', 'Low'],
message: "I feel extremely hot and my soil is very dry! This is not the good condition although the water is provided"
},
{condition :['Normal', 'Normal', 'Normal', 'Normal'],
message: "I am healthy. Thanks for your concern~"
},
{condition :['Bright', 'Normal', 'Wet', 'Low'],
message: "I am very healthy right now. I growth smoothly."
},
{condition :['Normal', 'Cool', 'Wet', 'High'],
message: "It is too wet in here, I can't get rid of the excess water!"
},
{condition :['Normal', 'Hot', 'Dry', 'Normal'],
message: "It is too hot and dry, I am dehydrated!"
}
];

Step 3: Array for factors and the trigger’s values

/*Initiallise the factor array to store the linguistic variable from light intensity, temperature, 
soil moisture and humidity level factor to check the plants' health condition*/
let factor = ['undefine','undefine','undefine','undefine'];
/*Initiallise the trigger to compare the input for each factor if the range overlapping. 0 will store the calculated value from membership function and 'unknown' will store the linguistic
variable
*/
let trigger = [0,'unknown',0,'unknown'];

Step 4: Declare Membership Function

/* Triangular membership function*/
function mf_triangle(input, left, max, right)
{
if (input < left || input > right) return 0;
if (left <= input && input <= max) return (input - left) / (max - left);

return (right - input) / (right - max);
}

Step 5: Declare Inference Function

/*Inference Function for calculate input membership*/
function inference(){
if(trigger[0] > trigger[2]){
return trigger[1];
}if(trigger[0] == trigger[2]){
return trigger[1];
}else{
return trigger[3];
}}

Step 6: Declare Fuzzification Function

//Passing the value to membership function
function fuzzification(index, input_value){
var left, max,right,linguistic, output, counter = 0;
//loop to pass the range of each fuzzified factor to the membership function
for(let i = 0; i<3; i++){
//if index is not equal four then calculate input variable respectively
if(index !== 4){
left = fuzzyset.variables_input[index].sets[i][0];
max = fuzzyset.variables_input[index].sets[i][1];
right = fuzzyset.variables_input[index].sets[i][2];
linguistic = fuzzyset.variables_input[index].setsName[i];
output = mf_triangle(input_value,left,max,right);
}else{// else calculate the output variable
left = tips_output.sets[i][0];
max = tips_output.sets[i][1];
right = tips_output.sets[i][2];
linguistic = tips_output.setsName[i];
output = mf_triangle(input_value,left,max,right);
}
if(output !== 0){ // if the condition is triggered save it to trigger array
if(counter == 0){
trigger[0] = output;
trigger[1] = linguistic;
counter++;//increase counter by one
}else{
trigger[2] = output;
trigger[3] = linguistic;}
}
}
counter = 0;//reset counter to zero
}

Step 7: Declare Defuzzification Function

//Defuzzification by appling weight-average method 
function defuzzification(light_input,temperature_input,soilMoisture_input,ambientHumidity_input){
var left, max, right, output, sumOfmidpointMultiplyoutput = 0, sumOfoutput = 0, counter = 0;
do{
for(let i = 0; i<3; i++){
//counter is zero calculate light intensity input
if(counter === 0){
left = ((fuzzyset.variables_input[counter].sets[i][0] / 111000) *100);//normalized the left boundary over 111000 lux
max = ((fuzzyset.variables_input[counter].sets[i][1] / 111000)*100);//normalized the maximum over 111000 lux
right = ((fuzzyset.variables_input[counter].sets[i][2] / 111000)*100);//normalized the right boundary over 111000 lux
var convertLightToPercentage = ((light_input / 111000) * 100);//normalized the light intensity input over 111000 lux
output = mf_triangle(convertLightToPercentage,left,max,right);
}
//if counter is one calculate temperature input
else if(counter === 1){
left = fuzzyset.variables_input[counter].sets[i][0];
max = fuzzyset.variables_input[counter].sets[i][1];
right = fuzzyset.variables_input[counter].sets[i][2];
output = mf_triangle(temperature_input,left,max,right);
}
//if counter is two calculate soil moisture input
else if(counter === 2){
left = fuzzyset.variables_input[counter].sets[i][0];
max = fuzzyset.variables_input[counter].sets[i][1];
right = fuzzyset.variables_input[counter].sets[i][2];
output = mf_triangle(soilMoisture_input,left,max,right);
}
// if counter is three calculate ambient humidity input
else if(counter === 3){
left = fuzzyset.variables_input[counter].sets[i][0];
max = fuzzyset.variables_input[counter].sets[i][1];
right = fuzzyset.variables_input[counter].sets[i][2];
output = mf_triangle(ambientHumidity_input,left,max,right);
}
if(output !== 0){//if return 1
/*sum the multiplication between output and the midpoint of the range*/
sumOfmidpointMultiplyoutput = sumOfmidpointMultiplyoutput + (output*((left + right) / 2));
//sum up the output
sumOfoutput = sumOfoutput + output;
}
}
counter++;//increase counter by one
}while(counter < 4);//repeat when counter smaller that four
/*return the defuzzification value*/
return (sumOfmidpointMultiplyoutput / sumOfoutput);
}

Step 8: Declare function to obtain the plant’s health condition

//Appriopriate plant condition reply
function condition(light_input, temperature_input, soilMoisture_input, ambientHumidity_input){
//normalized the temperature over 40 celcius
var convertTempToPercentage = ((temperature_input / 40) * 100);
let defuzzify,match;
//fuzzification function call to pass light intensity input
//and save the linguistic variable to factor[0]
fuzzification(0, light_input);
factor[0] = inference();
//fuzzification function call to pass temperature input
//and save the linguistic variable to factor[1]
fuzzification(1, convertTempToPercentage);
factor[1] = inference();
//fuzzification function call to pass soil moisture input
//and save the linguistic variable to factor[2]
fuzzification(2, soilMoisture_input);
factor[2] = inference();
//fuzzification function call to pass humidity input
//save the linguistic variable to factor[3]
fuzzification(3, ambientHumidity_input);
factor[3] = inference();
//defuzzify the input varibles
defuzzify = defuzzification(light_input,convertTempToPercentage,soilMoisture_input,ambientHumidity_input);
trigger = [0,'unknown',0,'unknown'];//reset trigger to default
fuzzification(4, defuzzify); //fuzzification the centroid to get the health condition of plant
//loop to match with the rules base in fuzzysetRules
for(let i = 0; i < fuzzysetRulesBase.length; i++){
//IF the rules batch match
if(JSON.stringify(fuzzysetRulesBase[i].condition) == JSON.stringify(factor)){
console.log(fuzzysetRulesBase[i].message);
match = true; break;
}else{
match = false;
}
}
if(!match)//If not match the rules base
{
if(trigger[1] === 'Unhealthy'){
if(trigger[2] >= trigger[0]){
console.log("I feel better now as I am recovery from aging.");
}else{
console.log("I feel very sad and unenergized. My leaves are lost and perhaps in permature aging condition.");}
}
else if(trigger[1] === 'Healthy'){
if(trigger[2] >= trigger[0]){
if(factor[2] == "Dry"){
console.log("I feel better and getting healthier, and I need some water");
}else{
console.log("I feel better as all my photosynthesis and transpiration processes run smoothly and I am getting healthier");
}
}else{
console.log("I am healthy and feel comfortable with current condition.");
}
}
else if(trigger[1] === 'Very Healthy' || trigger[3] === 'Very Healthy'){
if(trigger[1] === 'High'){
console.log("I feel extremely delightful as all my features look gorgeous.");
}else if(trigger[2] >= trigger[0]){
console.log("I growth smoothly and getting stronger.");
}else{
console.log("I am in a healthy condition and will grow better than now.");
}
}
}
console.log("My healthy level is about" + defuzzify + "%.");
//reset trigger array to default
trigger = [0,'unknown',0,'unknown'];
}

--

--