220 lines
6.9 KiB
Python
220 lines
6.9 KiB
Python
import sounddevice as sd
|
|
import numpy as np
|
|
import librosa
|
|
import joblib
|
|
import firebase_admin
|
|
import time
|
|
|
|
from firebase_admin import credentials, db
|
|
|
|
# =====================================================
|
|
# FIREBASE SETUP
|
|
# =====================================================
|
|
cred = credentials.Certificate("serviceAccountKey.json")
|
|
|
|
firebase_admin.initialize_app(cred, {
|
|
'databaseURL': 'https://tugas-akhir-9947b-default-rtdb.asia-southeast1.firebasedatabase.app/'
|
|
})
|
|
|
|
ref = db.reference("/Kebun")
|
|
|
|
# =====================================================
|
|
# LOAD MODEL & LABEL
|
|
# =====================================================
|
|
model = joblib.load("model_burung.pkl")
|
|
|
|
label_map = {
|
|
10: "manusia",
|
|
20: "burung"
|
|
}
|
|
|
|
# =====================================================
|
|
# PARAMETER
|
|
# =====================================================
|
|
duration = 2.0
|
|
fs = 22050
|
|
|
|
MIN_VOLUME = 0.06
|
|
MIN_CONFIDENCE = 0.75
|
|
MAX_DISTANCE = 300
|
|
|
|
# =====================================================
|
|
# HOLD DETEKSI & TIMER
|
|
# =====================================================
|
|
DETECTION_HOLD = 5
|
|
last_detection_time = 0
|
|
last_result = "tidak dikenal"
|
|
|
|
last_firebase_update = 0
|
|
firebase_interval = 2
|
|
|
|
print("===================================")
|
|
print("AI KNN BURUNG AKTIF")
|
|
print("Listening...")
|
|
print("===================================")
|
|
|
|
# =====================================================
|
|
# LOOP
|
|
# =====================================================
|
|
while True:
|
|
try:
|
|
# =============================================
|
|
# AMBIL SENSOR FIREBASE
|
|
# =============================================
|
|
jarak = 0
|
|
suara_sensor = 0
|
|
|
|
try:
|
|
sensor_data = ref.child("Sensor").get()
|
|
if sensor_data:
|
|
if "Jarak" in sensor_data:
|
|
jarak = int(sensor_data["Jarak"])
|
|
if "Suara_dB" in sensor_data:
|
|
suara_sensor = float(sensor_data["Suara_dB"])
|
|
except Exception as e:
|
|
print("Gagal baca sensor:", e)
|
|
|
|
# =============================================
|
|
# RECORD AUDIO
|
|
# =============================================
|
|
audio = sd.rec(
|
|
int(duration * fs),
|
|
samplerate=fs,
|
|
channels=1,
|
|
device=1,
|
|
dtype='float32'
|
|
)
|
|
sd.wait()
|
|
audio = audio.flatten()
|
|
|
|
# =============================================
|
|
# HITUNG VOLUME & KONVERSI dB
|
|
# =============================================
|
|
volume = np.max(np.abs(audio))
|
|
db_value = int(volume * 85)
|
|
|
|
if db_value < 30:
|
|
db_value = 30
|
|
if db_value > 85:
|
|
db_value = 85
|
|
|
|
print("Volume:", round(volume, 4))
|
|
print("dB:", db_value)
|
|
|
|
# =============================================
|
|
# DEFAULT
|
|
# =============================================
|
|
hasil = "tidak dikenal"
|
|
confidence = 0.0
|
|
|
|
# =============================================
|
|
# DEBUG FILTER
|
|
# =============================================
|
|
print("========== FILTER ==========")
|
|
print("Volume :", round(volume, 4))
|
|
print("Min Volume :", MIN_VOLUME)
|
|
print("Jarak :", jarak)
|
|
print("Max Jarak :", MAX_DISTANCE)
|
|
|
|
if volume < MIN_VOLUME:
|
|
print("SKIP -> Volume terlalu kecil")
|
|
if suara_sensor < 60:
|
|
print("SKIP -> Suara sensor ESP32 kurang dari 60 dB")
|
|
if jarak <= 2:
|
|
print("SKIP -> Jarak terlalu dekat")
|
|
if jarak > MAX_DISTANCE:
|
|
print("SKIP -> Jarak terlalu jauh")
|
|
|
|
# =============================================
|
|
# FILTER NOISE & PREDIKSI
|
|
# =============================================
|
|
if (volume >= MIN_VOLUME and suara_sensor >= 60 and jarak > 2 and jarak <= MAX_DISTANCE):
|
|
|
|
# NORMALISASI & MFCC
|
|
audio = librosa.util.normalize(audio)
|
|
mfcc = librosa.feature.mfcc(y=audio, sr=fs, n_mfcc=13)
|
|
mfcc_scaled = np.mean(mfcc.T, axis=0).reshape(1, -1)
|
|
|
|
# PREDIKSI
|
|
proba = model.predict_proba(mfcc_scaled)[0]
|
|
prediksi = model.predict(mfcc_scaled)[0]
|
|
|
|
print("Probabilitas :", proba)
|
|
confidence = float(np.max(proba))
|
|
predicted_label = label_map.get(prediksi, "tidak dikenal")
|
|
|
|
print("Raw Prediksi :", prediksi)
|
|
print("Label :", predicted_label)
|
|
print("Confidence :", round(confidence, 2))
|
|
|
|
# =========================================
|
|
# VALIDASI HASIL AI (Sudah di dalam posisi Indentasi yang Benar)
|
|
# =========================================
|
|
sorted_proba = np.sort(proba)
|
|
highest = sorted_proba[-1]
|
|
second = sorted_proba[-2]
|
|
selisih = highest - second
|
|
|
|
print("Selisih Proba :", round(selisih, 2))
|
|
|
|
if (confidence >= 0.75 and selisih >= 0.20 and predicted_label in ["manusia", "burung"]):
|
|
hasil = predicted_label
|
|
else:
|
|
hasil = "tidak dikenal"
|
|
|
|
# =============================================
|
|
# HOLD HASIL DETEKSI
|
|
# =============================================
|
|
current_time = time.time()
|
|
|
|
if hasil in ["manusia", "burung"]:
|
|
last_result = hasil
|
|
last_detection_time = current_time
|
|
|
|
# TAHAN HASIL
|
|
if (current_time - last_detection_time) < DETECTION_HOLD:
|
|
hasil_tampil = last_result
|
|
else:
|
|
hasil_tampil = "tidak dikenal"
|
|
|
|
# =============================================
|
|
# DEBUG TAMPILAN
|
|
# =============================================
|
|
print("Confidence:", round(confidence, 2))
|
|
print("Hasil AI:", hasil)
|
|
print("Tampil:", hasil_tampil)
|
|
print("Jarak Firebase:", jarak)
|
|
print("Suara Sensor:", suara_sensor)
|
|
print("----------------")
|
|
|
|
# =============================================
|
|
# UPDATE FIREBASE
|
|
# =============================================
|
|
if (current_time - last_firebase_update) >= firebase_interval:
|
|
last_firebase_update = current_time
|
|
ref.update({
|
|
"AI": {
|
|
"Klasifikasi": hasil_tampil,
|
|
"Confidence": round(confidence, 2),
|
|
"Volume": round(float(volume), 4)
|
|
}
|
|
})
|
|
|
|
# =============================================
|
|
# DELAY
|
|
# =============================================
|
|
time.sleep(0.3)
|
|
|
|
except Exception as e:
|
|
print("ERROR:", e)
|
|
try:
|
|
ref.update({
|
|
"AI": {
|
|
"Klasifikasi": "error",
|
|
"Confidence": 0,
|
|
"Volume": 0
|
|
}
|
|
})
|
|
except:
|
|
pass
|
|
time.sleep(1) |