# Created: 2026-03-07
# Purpose: Radar chart for 7-channel forensic features
# Dependencies: plotly, numpy
"""Radar chart visualization for 7 forensic audio features."""
import numpy as np
import plotly.graph_objects as go
def plot_forensic_radar(feature_stats: dict) -> go.Figure:
"""7개 포렌식 피처를 레이더 차트로 시각화.
Args:
feature_stats: Dict with feature names as keys and normalized values (0-1)
Returns:
plotly Figure (radar/polar chart)
"""
# 7개 포렌식 피처 정의
features = [
("Residual Energy", "잔차 에너지 (AI 코덱 흔적)"),
("Harmonic Strength", "하모닉 강도 (음악 구조)"),
("Percussive Strength", "타악기 강도 (리듬 요소)"),
("Temporal Delta", "시간 변화율 (다이나믹스)"),
("Temporal Accel", "시간 가속도 (변화 일관성)"),
("H/P Ratio", "하모닉/타악기 비율"),
("Spectral Flux", "스펙트럼 변화량 (질감)"),
]
# 기본값 (feature_stats가 없으면 중간값)
if not feature_stats:
values = [0.5] * 7
else:
values = [
feature_stats.get("residual_energy", 0.5),
feature_stats.get("harmonic_strength", 0.5),
feature_stats.get("percussive_strength", 0.5),
feature_stats.get("temporal_delta", 0.5),
feature_stats.get("temporal_accel", 0.5),
feature_stats.get("hp_ratio", 0.5),
feature_stats.get("spectral_flux", 0.5),
]
# 레이더 차트용 데이터 (첫 값을 마지막에 반복해서 폐곡선 생성)
categories = [f[0] for f in features]
values_closed = values + [values[0]]
categories_closed = categories + [categories[0]]
fig = go.Figure()
# 현재 오디오 패턴
fig.add_trace(go.Scatterpolar(
r=values_closed,
theta=categories_closed,
fill='toself',
fillcolor='rgba(255, 71, 87, 0.3)',
line=dict(color='#ff4757', width=2),
name='Audio Pattern',
hovertemplate="%{theta}
Score: %{r:.2f}
AI 뉴럴 코덱이 남기는 미세한 코덱 흔적. AI 음악은 인간이 만든 음악과 다른 양자화 패턴을 보입니다.
음악을 멜로디 성분과 리듬 성분으로 분리. AI는 두 요소의 에너지 비율이 부자연스럽게 일정합니다.
스펙트럼의 시간축 변화 패턴. AI 음악은 변화가 너무 부드럽고 규칙적입니다 (생성 과정의 smoothing 효과).
멜로디와 리듬의 균형. AI는 장르와 무관하게 특정 비율로 수렴하는 경향을 보입니다.
주파수 성분의 프레임간 변화 절댓값. AI는 변화가 일관적이고 예측 가능합니다 (확률적 생성의 특성).
💡 핵심 원리: AI 생성 모델은 물리적 악기의 불규칙성을 완벽히 재현하지 못합니다. 이 7개 피처는 그러한 미세한 차이를 정량화하여 AI 시그니처를 탐지합니다.