/*
* IMPLEMENTASI FUZZY INFERENCE SYSTEM (MAMDANI)
* Input: 3 Potensiometer (mewakili N, P, K)
* Output: PWM LED (mewakili intensitas penyiraman)
*
* Fungsi Keanggotaan: Segitiga dan Trapesium
* Metode Defuzzifikasi: Centroid
*
* By: ptti
*/
// Pin Definitions
const int potN = A0; // Potensiometer Nitrogen
const int potP = A1; // Potensiometer Fosfor
const int potK = A2; // Potensiometer Kalium
const int ledPWM = 9; // Output PWM ke LED
// Variabel untuk nilai input
float N, P, K;
// Variabel untuk nilai output
float penyiraman;
// ==============================================
// FUZZY SET PARAMETERS
// ==============================================
// Input Ranges
const float N_MIN = 0;
const float N_MAX = 100;
const float P_MIN = 0;
const float P_MAX = 100;
const float K_MIN = 0;
const float K_MAX = 100;
// Output Range
const float OUT_MIN = 0;
const float OUT_MAX = 100;
// Linguistic Variables
enum { RENDAH, SEDANG, TINGGI };
// Membership functions for N, P, K (rendah, sedang, tinggi)
struct FuzzySet {
float rendah[3]; // [a, b, c] untuk segitiga
float sedang[3]; // [a, b, c] untuk segitiga
float tinggi[3]; // [a, b, c] untuk segitiga
};
// Parameter fungsi keanggotaan (disesuaikan dengan penelitian)
FuzzySet N_set = {{0, 0, 40}, {20, 50, 80}, {60, 100, 100}};
FuzzySet P_set = {{0, 0, 40}, {20, 50, 80}, {60, 100, 100}};
FuzzySet K_set = {{0, 0, 40}, {20, 50, 80}, {60, 100, 100}};
// Output membership functions
FuzzySet out_set = {{0, 0, 40}, {20, 50, 80}, {60, 100, 100}};
// ==============================================
// FUZZIFICATION FUNCTIONS
// ==============================================
float triangleMF(float x, float a, float b, float c) {
if (x <= a || x >= c) return 0;
if (x == b) return 1;
if (x > a && x < b) return (x - a) / (b - a);
return (c - x) / (c - b);
}
float trapezoidMF(float x, float a, float b, float c, float d) {
if (x <= a || x >= d) return 0;
if (x >= b && x <= c) return 1;
if (x > a && x < b) return (x - a) / (b - a);
return (d - x) / (d - c);
}
// Fuzzify input
void fuzzify(float value, FuzzySet set, float mf[3]) {
mf[RENDAH] = trapezoidMF(value, set.rendah[0], set.rendah[1], set.rendah[1], set.rendah[2]);
mf[SEDANG] = triangleMF(value, set.sedang[0], set.sedang[1], set.sedang[2]);
mf[TINGGI] = trapezoidMF(value, set.tinggi[0], set.tinggi[1], set.tinggi[1], set.tinggi[2]);
}
// ==============================================
// RULE BASE (27 Rules sesuai penelitian)
// ==============================================
const int numRules = 27;
struct Rule {
int N; // 0: rendah, 1: sedang, 2: tinggi
int P; // 0: rendah, 1: sedang, 2: tinggi
int K; // 0: rendah, 1: sedang, 2: tinggi
int out; // 0: sedikit, 1: sedang, 2: banyak
};
Rule ruleBase[numRules] = {
// Format: {N, P, K, output}
// Aturan untuk N rendah
{RENDAH, RENDAH, RENDAH, TINGGI}, // Rule 1: Jika N rendah DAN P rendah DAN K rendah MAKA penyiraman banyak
{RENDAH, RENDAH, SEDANG, TINGGI}, // Rule 2
{RENDAH, RENDAH, TINGGI, SEDANG}, // Rule 3
{RENDAH, SEDANG, RENDAH, TINGGI}, // Rule 4
{RENDAH, SEDANG, SEDANG, SEDANG}, // Rule 5
{RENDAH, SEDANG, TINGGI, SEDANG}, // Rule 6
{RENDAH, TINGGI, RENDAH, SEDANG}, // Rule 7
{RENDAH, TINGGI, SEDANG, SEDANG}, // Rule 8
{RENDAH, TINGGI, TINGGI, RENDAH}, // Rule 9
// Aturan untuk N sedang
{SEDANG, RENDAH, RENDAH, TINGGI}, // Rule 10
{SEDANG, RENDAH, SEDANG, SEDANG}, // Rule 11
{SEDANG, RENDAH, TINGGI, SEDANG}, // Rule 12
{SEDANG, SEDANG, RENDAH, SEDANG}, // Rule 13
{SEDANG, SEDANG, SEDANG, SEDANG}, // Rule 14
{SEDANG, SEDANG, TINGGI, SEDANG}, // Rule 15
{SEDANG, TINGGI, RENDAH, SEDANG}, // Rule 16
{SEDANG, TINGGI, SEDANG, RENDAH}, // Rule 17
{SEDANG, TINGGI, TINGGI, RENDAH}, // Rule 18
// Aturan untuk N tinggi
{TINGGI, RENDAH, RENDAH, SEDANG}, // Rule 19
{TINGGI, RENDAH, SEDANG, SEDANG}, // Rule 20
{TINGGI, RENDAH, TINGGI, RENDAH}, // Rule 21
{TINGGI, SEDANG, RENDAH, SEDANG}, // Rule 22
{TINGGI, SEDANG, SEDANG, RENDAH}, // Rule 23
{TINGGI, SEDANG, TINGGI, RENDAH}, // Rule 24
{TINGGI, TINGGI, RENDAH, RENDAH}, // Rule 25
{TINGGI, TINGGI, SEDANG, RENDAH}, // Rule 26
{TINGGI, TINGGI, TINGGI, RENDAH} // Rule 27
};
// ==============================================
// INFERENCE AND DEFUZZIFICATION
// ==============================================
float fuzzyMin(float a, float b) {
return (a < b) ? a : b;
}
float fuzzyMax(float a, float b) {
return (a > b) ? a : b;
}
float inference(float N_mf[3], float P_mf[3], float K_mf[3]) {
float fireStrength[numRules];
float outputMF[3] = {0, 0, 0}; // Untuk menyimpan aggregated output MF
// Hitung fire strength untuk setiap rule
for (int i = 0; i < numRules; i++) {
Rule r = ruleBase[i];
float strength = fuzzyMin(fuzzyMin(N_mf[r.N], P_mf[r.P]), K_mf[r.K]);
fireStrength[i] = strength;
// Aggregate menggunakan MAX
outputMF[r.out] = fuzzyMax(outputMF[r.out], strength);
}
// Defuzzifikasi menggunakan metode Centroid (membagi area menjadi 100 titik)
const int samples = 100;
float numerator = 0;
float denominator = 0;
for (int i = 0; i <= samples; i++) {
float x = map(i, 0, samples, OUT_MIN, OUT_MAX);
// Hitung nilai keanggotaan pada titik x
float mfValue = 0;
// Untuk output "sedikit"
mfValue = fuzzyMax(mfValue, fuzzyMin(outputMF[RENDAH],
triangleMF(x, out_set.rendah[0], out_set.rendah[1], out_set.rendah[2])));
// Untuk output "sedang"
mfValue = fuzzyMax(mfValue, fuzzyMin(outputMF[SEDANG],
triangleMF(x, out_set.sedang[0], out_set.sedang[1], out_set.sedang[2])));
// Untuk output "banyak"
mfValue = fuzzyMax(mfValue, fuzzyMin(outputMF[TINGGI],
trapezoidMF(x, out_set.tinggi[0], out_set.tinggi[1],
out_set.tinggi[1], out_set.tinggi[2])));
numerator += x * mfValue;
denominator += mfValue;
}
if (denominator == 0) return 50; // Default value
return numerator / denominator;
}
// ==============================================
// ARDUINO SETUP
// ==============================================
void setup() {
Serial.begin(9600);
pinMode(potN, INPUT);
pinMode(potP, INPUT);
pinMode(potK, INPUT);
pinMode(ledPWM, OUTPUT);
Serial.println("Sistem Fuzzy Penyiraman Otomatis");
Serial.println("=================================");
Serial.println("Rentang Input: 0-100%");
Serial.println("Output: 0-100% (PWM 0-255)");
Serial.println();
}
// ==============================================
// ARDUINO MAIN LOOP
// ==============================================
void loop() {
// 1. Baca input dari potensiometer
N = map(analogRead(potN), 0, 1023, N_MIN, N_MAX);
P = map(analogRead(potP), 0, 1023, P_MIN, P_MAX);
K = map(analogRead(potK), 0, 1023, K_MIN, K_MAX);
// 2. Fuzzyfikasi
float N_mf[3], P_mf[3], K_mf[3];
fuzzify(N, N_set, N_mf);
fuzzify(P, P_set, P_mf);
fuzzify(K, K_set, K_mf);
// 3. Inferensi dan Defuzzifikasi
penyiraman = inference(N_mf, P_mf, K_mf);
// 4. Map output ke PWM (0-255)
int pwmValue = map(penyiraman, OUT_MIN, OUT_MAX, 0, 255);
analogWrite(ledPWM, pwmValue);
// 5. Tampilkan hasil ke Serial Monitor
Serial.println("=================================");
Serial.print("N: "); Serial.print(N, 1); Serial.print("%");
Serial.print(" | P: "); Serial.print(P, 1); Serial.print("%");
Serial.print(" | K: "); Serial.print(K, 1); Serial.println("%");
Serial.print("Keanggotaan N: ");
Serial.print("R="); Serial.print(N_mf[RENDAH], 3);
Serial.print(", S="); Serial.print(N_mf[SEDANG], 3);
Serial.print(", T="); Serial.println(N_mf[TINGGI], 3);
Serial.print("Keanggotaan P: ");
Serial.print("R="); Serial.print(P_mf[RENDAH], 3);
Serial.print(", S="); Serial.print(P_mf[SEDANG], 3);
Serial.print(", T="); Serial.println(P_mf[TINGGI], 3);
Serial.print("Keanggotaan K: ");
Serial.print("R="); Serial.print(K_mf[RENDAH], 3);
Serial.print(", S="); Serial.print(K_mf[SEDANG], 3);
Serial.print(", T="); Serial.println(K_mf[TINGGI], 3);
Serial.print("Intensitas Penyiraman: ");
Serial.print(penyiraman, 2);
Serial.print("% | PWM: ");
Serial.println(pwmValue);
Serial.println();
delay(2000); // Delay untuk stabilitas pembacaan
}K
P
N