Acoustic Anomaly Detection: หูของบ้านที่ไม่เคยหลับ
กล้อง CCTV ตรวจจับการบุกรุกได้เมื่อเห็นคน แต่เสียง แตกกระจก เกิดก่อนที่บุคคลจะปรากฏในกล้อง และเสียง ร้องขอความช่วยเหลือ เกิดในมุมที่กล้องมองไม่เห็น Acoustic Detection ปิดช่องว่างนี้ด้วยการฟังตลอด 24 ชั่วโมง
YAMNet: Google Audio Classification Model
YAMNet (Yet Another Mobile Network) เป็น audio classification model ของ Google ที่ฝึกด้วย AudioSet dataset (2 ล้าน video, 521 classes) รองรับการตรวจจับ: - Glass breaking (เสียงแตกกระจก) - Screaming (เสียงร้อง) - Smoke alarm / CO alarm - Gunshot - Dog barking - Siren รัน YAMNet TFLite บน Raspberry Pi 5 ด้วย ~180MB RAM, ~15% CPU
Hardware Setup
Microphone Array แนะนำ: - ReSpeaker 4-Mic Array สำหรับ Raspberry Pi (~1,200 บาท): 4 microphones พร้อม DOA (Direction of Arrival) estimation - หรือ USB omnidirectional mic ราคา ~300–600 บาท สำหรับ single-room monitoring การวาง microphone: - ห้องนั่งเล่น: ติดเพดาน ตรงกลางห้อง - หน้าประตูทางเข้า: ตรวจจับเสียงทุบประตูหรือแกะกุญแจ - ห้องนอนผู้สูงอายุ: ตรวจจับ fall sound + scream
Implementation: YAMNet บน Raspberry Pi
python import numpy as np import sounddevice as sd import tensorflow as tf # Load YAMNet TFLite model interpreter = tf.lite.Interpreter('yamnet.tflite') interpreter.allocate_tensors() input_details = interpreter.get_input_details() output_details = interpreter.get_output_details() TARGET_CLASSES = { 9: ('glass_break', 0.7), # Glass, shatter 40: ('scream', 0.65), # Screaming 312: ('smoke_alarm', 0.8), # Smoke detector 427: ('gunshot', 0.85), # Gunshot } def classify_audio(audio_chunk): waveform = audio_chunk.flatten().astype(np.float32) waveform = waveform / np.max(np.abs(waveform) + 1e-6) interpreter.set_tensor(input_details[0]['index'], [waveform]) interpreter.invoke() scores = interpreter.get_tensor(output_details[0]['index'])[0] for class_id, (class_name, threshold) in TARGET_CLASSES.items(): if scores[class_id] > threshold: return class_name, scores[class_id] return None, 0 def audio_callback(indata, frames, time, status): audio_chunk = indata[:, 0] event, confidence = classify_audio(audio_chunk) if event: publish_to_mqtt(event, confidence) with sd.InputStream(samplerate=16000, channels=1, blocksize=15600, callback=audio_callback): sd.sleep(int(1e9)) # run forever
False Positive Reduction
YAMNet มี false positive สูงกับเสียงบางชนิด ใช้กลยุทธ์:
- Confirmation Window: event ต้องเกิดขึ้น 2 ครั้งใน 3 วินาที 2. Context Suppression: ถ้า TV เปิดอยู่ (ดูจาก media player state ใน HA) ลด threshold ลงหรือ ignore เสียงบางชนิด 3. Direction Estimation (ถ้าใช้ 4-mic array): เสียงจากทิศที่มีกำแพงนอก (ไม่ใช่ทิศห้องน้ำ) ให้ priority สูงกว่า 4. Nighttime Sensitivity Boost: ระหว่าง 22:00–07:00 ลด confirmation threshold เป็น 1 ครั้ง
Home Assistant Integration
yaml automation: - alias: "Glass Break Alert" trigger: - platform: mqtt topic: "acoustic/event" payload: "glass_break" action: - service: alarm_control_panel.alarm_trigger target: entity_id: alarm_control_panel.home_alarm - service: notify.line_family data: message: "🔔 ตรวจพบเสียงแตกกระจก! กรุณาตรวจสอบทันที" data: photo: "/api/frigate/notifications/front_door/thumbnail.jpg"
Privacy: ไม่บันทึกเสียง
ระบบประมวลผล audio stream แบบ real-time ไม่บันทึกเสียงพูดหรือ audio file ใดๆ ลงดิสก์ บันทึกเฉพาะ event label, timestamp, confidence score เท่านั้น ทำให้ไม่มีความเสี่ยงด้าน privacy จาก audio recording
ต้นทุนรวม
| รายการ | ราคา (THB) | |--------|------------| | Raspberry Pi 5 4GB | 2,200 | | ReSpeaker 4-Mic Array | 1,200 | | USB power + enclosure | 400 | | YAMNet TFLite model | ฟรี (Apache 2.0) | | รวม | 3,800 |