-
정확도 개선 2 - 1차 IIR 필터JDTuner/개발기록 2026. 3. 11. 20:51
문제점
마이크를 사용하는 앱이므로 어지간하면 조용한곳에서 사용하겠지만
마이크로 들어가는 소리는 단순히 기타 줄의 소리만 들어가는게 아니다.
1. 배음
기타 줄에서 나오는 파형은 여러개의 파형의 합쳐져 있다.
6번 줄(82.4Hz)을 예로 들면,
정배수인 164.8Hz(2배음), 247.2Hz(3배음), 329.6Hz(4배음) 등의
고음역대 소리가 동시에, 치는 순간에는 원래 음보다 더 강하게 튀어나온다.
2. 피킹음
피킹시 피크(Pick)가 줄을 긁는 고음역대의 쇳소리도 들어갈 수 있다.
3. 주변 소음
TV를 틀어 놓거나 하는 주변 소음도 어느정도 있을 수 있다.
해결방식 - 1차 IIR 필터
이런 여러소리가 같이 들어가는 상황에서 최대한 기타 줄의 음역대의 영역으로 가져오기 위해
필터가 필요하고 이럴때 간단한 로우패스 필터를 사용하면 도움이 된다.
이론

현재의 결과값을 현재의 입력값 x[n]과 바로 직전의 결과값 y[n-1]을 가중치 알파를 통해 더한다.

모든 샘플을 돌면서 계산하게 되므로 결국 y[n]은 위와 같은 식으로 나오고 이전 값이 지수적으로 영향을 미쳐
지수 이동 평균이라고도 한다.

알파 값을 0.2라고 가정하면
- 새로운 소리의 반영 비율이 20%밖에 안돼서 갑자기 날카로운 고주파 소리(빠르게 진동하는 파형)가 확 들어와도, 80%의 과거 데이터가 끌어내린다.
- 결과적으로 빠르게 변하는 고주파(배음, 잡음)는 억제되고, 천천히 변하는 저주파(기타의 기본음)만 살아남는다.
- 기존 음의 영향력은 샘플이 진행될수록 점점 약해져 완만하게 필터링이 가능하다.
코드 적용
// JDTunerEngine.h private: // ... // 로우패스 필터용 변수 float prevLpfOut = 0.0f; // 필터의 이전 출력값을 기억 float lpfAlpha = 0.2f; // 필터 강도 (0.0~1.0, 작을수록 고음을 더 강하게 깎음) // JDTunerEngine.cpp // ... void JDTunerEngine::collectData(const float* datas, int numSamples) { for (int i = 0; i < numSamples; ++i) { // 로우패스 필터 적용 float filteredSample = lpfAlpha * datas[i] + (1.0f - lpfAlpha) * prevLpfOut; prevLpfOut = filteredSample; collector.push_back(filteredSample); } } // ...- 헤더쪽에 private으로 필터 관련 값을 정의한다.
- 이전값을 저장하는 프로퍼티를 만들어서 줄바꿈시 기존 줄값을 저장하는거에 대한 걱정이 있었으나
위의 예시를 봤을때 10칸의 데이터만해도 2%만 영향을 주므로
4000개 이상의 버퍼 단위로 다루는 현재 상황에선 줄바꿈시 기존 줄의 값이 남아있어도
큰 영향이 없고 심지어 아예 영향이 없는 수준이어서 연속성을 위해 프로퍼티를 사용하는 방법으로 했다.
결과
불필요한 고음역대와 잡음을 최대한 필터링하는 방식을 적용해정확도를 더 개선했고 DSP에서 자주 사용되는 1차 필터를 학습했다.
지수 이동 평균 방식은 합연산을 이용해 메모리 관리에 용이한 알고리즘으로
플러그인 만들때도 사용해본적이 있었던 만큼 다시 학습하고 사용해봐서 좋았다.
'JDTuner > 개발기록' 카테고리의 다른 글
프로젝트 구조 변경 - 튜너를 외부로 분리 (0) 2026.04.03 UI 수정 (0) 2026.03.15 정확도 개선 1 - Parabolic Interpolation (0) 2026.03.11 구조 개선 2 - 비동기스트림 (0) 2026.03.10 구조 개선 1 - 데이터 관리 + 테스트 영상 (0) 2026.03.09