본문 바로가기
Audio Processing

오디오 필터(16)-IIR 필터 실행, 오디오 볼륨 처리

by gigasound 2021. 10. 29.


IIR 필터 다루기

이전의 글에서 디지털 필터의 전달 함수를 위한 계수들을 구하는 방법을 알아봤습니다. 이때 디지털 필터 전달 함수의 형태에 따라 IIR 또는 FIR가 있으며 형태가 조금 다릅니다. 이에 관한 내용은 다른 글에서 다루겠습니다.

이글에서는 GNU Octave에서 오디오를 다루는 방법, 그리고 이를 이용해서 오디오의 볼륨을 조정하는 방법, 마지막으로 디지털 필터를 적용해서 오디오 신호를 처리하고 출력하는 방법을 알아보겠습니다. 

유투브를 보시면 오디오 파일을 6초 정도로 짧게 만들어 실험에 사용하는 방법과 GNU Octave로 오디오 파일을 출력 하는 방법 까지 설명해 놨습니다. 


IIR 필터 실행 방법

 IIR 필터는 다음과 같이 처리됩니다. 입력 신호를 받아서 필터 계수를 적용한 IIR 필터에 실행한 후에 출력합니다. 그런데 IIR 필터는 과거에 연산한 필터 결과를 기록해서 이를 다시 사용합니다. 이를 History Buffer라고 부르겠습니다. IIR 필터는 History Buffer를 이용한 입력 신호와의 컨볼루션(covolution) 연산입니다. 


GNU Octave의 오디오 파일 다루기

octave에는 오디오를 위한 함수가 기본적으로 포함되어 있습니다. audioread()는 오디오 파일을 읽어서 원시 데이터로 출력해 줍니다. 이 글에서는 audioread()를 이용해서 원시 데이터를 추출해 보겠습니다. 

그리고 sound() 함수로 신호 처리된 결과를 오디오로 재생할 수 있습니다. 

오디오 파일 열고 볼륨 처리

추출된 원시 데이터는 실수형 값이며 [-1,1]로 정규화된 값으로 직접 신호처리에 적용해도 됩니다. 먼저 오디오 파일을 열고 신호의 크기를 절반 (0.5)로 줄여 보겠습니다. 그리고 신호를 출력해보겠습니다.

 

아래 코드는 Octave의 스크립 파일로 추출 원시 데이터는 adata, 샘플링 주파수는 fs로 기록됩니다. 그런 다음 윈시 데이터를 0.5배 한 후에 출력합니다. 

clear all;
file_name = 'test.wav';

[adata,fs]=audioread(file_name);
adata = adata * 0.5;
sound(adata,fs);

Peaking 필터 계수를 구하고 IIR 필터 수행

아래 스크립 파일은 다른 글에서 다루었던 Peaking filter의 계수를 구하는 내용을 포함하고 IIR 필터를 수행하는 부분을 추가한 내용입니다. 그리고 오디오 파일의 볼륨을 절반으로 줄인 다음에 Peaking filter가 적용된 내용을 출력합니다. 

그리고 원래 오디오 파일과 IIR 필터 처리 후의 결과를 연속으로 듣도록 작성했던 것입니다.

이 스크립 파일을 수행하는 데는 시간이 좀 걸립니다. Octave는 실시간 오디오 처리가 고려된 프로그램이 아니기 때문에 곧바로 출력되지는 않습니다. 

#pkg load signal;
clear all
file_name = 'test.wav';

function [b, a] = PEAKING(f0,fs,g,q)
  coef_b=zeros(3,1);
  coef_a=zeros(3,1);
  A=10^(g/40.0);
  w0=2.0*pi*f0/fs;
  s0=sin(w0);
  c0=cos(w0);
  h=sin(w0)/(2.0*q);
  b(1,1) = 1.0+h*A;
  b(2,1) = -(2.0*c0);
  b(3,1) = (1.0-h*A);
  a(1,1) = 1.0+h/A;
  a(2,1) = -2.0*c0;
  a(3,1) = 1- h/A;
  b(1,1) /= a(1,1);
  b(2,1) /= a(1,1);
  b(3,1) /= a(1,1);
  a(2,1) /= a(1,1);
  a(3,1) /= a(1,1);
  a(1,1) = 1; 
endfunction

function output = IIR(input,b,a)
  order = size(b,1);
  output = zeros(size(input,1),size(input,2));
  x = zeros(3,size(input,2));
  y = zeros(3,size(input,2));
  accu =zeros(1,size(input,2));
  for i =1:size(input,1)
    x(1,:) = input(i,:);
    accu(1,:) = x(1,:) * b(1);
    for k = 2:order
      accu(1,:) += x(k,:) * b(k);
      accu(1,:) -= y(k,:) * a(k);
    endfor
    y(1,:) = accu(1,:);
    output(i,:)= accu(1,:);
    for k = 0:(order-2)
      x((order-k),:) = x((order-k-1),:);
      y((order-k),:) = y((order-k-1),:); 
    endfor
  endfor
endfunction

[adata,fs]=audioread(file_name);
adata = adata * 0.5;
[b,a] = PEAKING(3000,44100,-30,1);
output = IIR(adata,b,a);
sound(adata,fs);
sound(output,fs);

실험을 위해서 음성 오디오 파일을 이용했습니다. 이유는 필터가 잘 적용되었는지 알아듣기 편리하기 때문입니다. 그리고 음성 정보에 민감한 주파수 부분인 3kHz의 이득을 조정해서 검토했습니다.

아래의 두 개의 그래프는 입력과 출력 오디오 신호의 내용입니다. 그래프로는 구분하기 신호처리 결과를 구분하기 어렵습니다. 그러니 청취해서 비교하는 것이 좋습니다.  


광고좀 꾹 눌러주시면 고맙겠습니다. 


위의 내용을 참조용으로만 사용해주세요. 무단 도용이나 무단 복제는 불허합니다.

기타 문의 사항은 gigasound@naver.com에 남겨 주시면 고맙겠습니다.