수면 해킹: Whisper와 FFT를 활용한 로컬 수면 무호흡 및 코골이 모니터 만들기 🌙💤
Source: Dev.to
소개
8시간을 잤음에도 불구하고 트럭에 치인 듯한 기분으로 깨어본 적 있나요? 당신은 수백만 명의 수면 무호흡증 또는 만성 코골이 환자 중 한 명일지도 모릅니다. 이 튜토리얼에서는 FFT 스펙트럼 분석과 Faster‑Whisper를 결합한 프라이버시‑우선, 로컬 수면 무호흡 감지 시스템을 구축합니다. 모든 처리는 장치 내에서 이루어지므로 오디오가 기기를 떠나지 않습니다.
파이프라인 개요
graph TD
A[Nightly Audio Input] --> B[Librosa Pre‑processing]
B --> C{FFT Energy Check}
C -- Below Threshold --> A
C -- Event Detected --> D[Faster‑Whisper Classification]
D --> E[Breathing Pattern Tagging]
E --> F[(SQLite Storage)]
F --> G[Health Report Generation]
사전 요구 사항
- Python 3.9+
- Faster‑Whisper – 로컬 전사/분류
- Librosa – 오디오 분석
- SQLite – 로컬 저장소
설치
pip install faster-whisper librosa numpy sounddevice
Librosa와 FFT를 이용한 오디오 분석
import numpy as np
import librosa
def is_meaningful_audio(audio_data, sr=16000):
"""Return True if the audio segment is louder than a background threshold."""
# Short‑Time Fourier Transform (STFT)
stft = np.abs(librosa.stft(audio_data))
# Convert amplitude to decibels
db = librosa.amplitude_to_db(stft, ref=np.max)
mean_db = np.mean(db)
# -30 dB is a reasonable starting point for “significant” noise
return mean_db > -30
def extract_features(audio_path):
"""Extract a simple spectral feature (centroid) from an audio file."""
y, sr = librosa.load(audio_path, sr=16000)
centroid = librosa.feature.spectral_centroid(y=y, sr=sr)
return np.mean(centroid)
FFT 에너지 검사는 시스템이 실제 소리 이벤트(코골이, 헐떡임 등)가 포함된 구간만 처리하도록 보장합니다. 코골이는 보통 저주파 영역(≈ 60–500 Hz)을 차지하고, 무호흡 관련 소리는 뚜렷한 스펙트럼 특성을 가집니다.
Faster‑Whisper를 이용한 호흡 분류
from faster_whisper import WhisperModel
# Choose a small model for speed on CPUs
model_size = "base"
model = WhisperModel(model_size, device="cpu", compute_type="int8")
def classify_breathing(audio_segment_path):
"""Run Faster‑Whisper on a short audio segment and return detected tokens."""
segments, info = model.transcribe(audio_segment_path, beam_size=5)
findings = [segment.text.lower() for segment in segments]
return " ".join(findings)
음성을 전사하는 대신 Whisper의 출력을 [snoring], [gasping], [heavy breathing]와 같은 비음성 소리를 분류하는 데 사용합니다.
SQLite로 이벤트 기록하기
import sqlite3
from datetime import datetime
def log_event(event_type, confidence):
"""Store a detected event with a timestamp in a local SQLite database."""
conn = sqlite3.connect('sleep_health.db')
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS events (
timestamp TEXT,
type TEXT,
confidence REAL
)
''')
c.execute(
"INSERT INTO events VALUES (?, ?, ?)",
(datetime.now().isoformat(), event_type, confidence)
)
conn.commit()
conn.close()
이벤트를 로컬에 저장하면 “등받이에서 잘 때 코골이가 더 심한가?”와 같은 주간 패턴을 분석할 수 있습니다.
다음 단계
- Matplotlib 대시보드를 추가해 코골이 “핫존”을 시각화합니다.
- 심박수 모니터를 통합해 맥박 급증과 무호흡 이벤트를 연관시킵니다.
- Raspberry Pi에 스크립트를 배포해 전용 침대 옆 모니터를 구축합니다.
이러한 확장은 프로토타입을 모든 데이터를 장치 내에 보관하면서도 강력한 개인 건강 대시보드로 전환할 수 있게 해줍니다.