FIRフィルタのフレーム処理
信号処理ではそのアルゴリズムによってフレーム単位で処理している場合が多いです。 フーリエ変換を行う場合は、そのサイズ(点数)でフレーム化されたりします。 このようなケースを考えたとき、フィルタもそのフレームサイズに適した形が都合が良く、高速化(最適化)に関しても利点が多いです。
FIRのフレーム処理
「適応フィルタを作ってみる」と、
「FIRフィルタを作って周波数特性を検証」
で、FIRのサンプルコードを紹介しましたが、1サンプルに対してフィルタ処理を行うサンプル処理でした。
今回は、フレーム単位で処理を行うFIRフィルタを作ってみます。
サンプルコード 【C言語】
#define FIR_TAP 15 // 目的に合わせて調整する (今回は15で試してみます)
// clip static short double_saturate(double in) { if (in > 32767.0) in = 32767.0; if (in < -32768.0) in = -32768.0; return (short)in; } // FIRフィルタフレーム処理 void fir_frame(float* coef, short *mem, int n, short *in, short *out) { int flen; double sum; short *buff; float *p_coef; short *p_buff; // buff update memcpy(mem, &mem[n], sizeof(short)*(FIR_TAP - 1)); memcpy(&mem[FIR_TAP - 1], in, sizeof(short)*n); // convolution buff = &mem[FIR_TAP - 1]; while (n--) { sum = 0.; p_coef = coef; p_buff = buff++; flen = FIR_TAP; while (flen--) { sum += *p_coef++ * (double)*p_buff--; } *out++ = double_saturate(sum); } }
検証用のコード
PCMにWAVヘッダを付けるで紹介した検証用コードをフレームサイズで処理するように変更してみました。今回は、フレームサイズを128サンプルとしています。サンプリング周波数16kHzの場合で8msです。
サンプルコード 【C言語】
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "fir.h" #include "wav_header.h" #define FRAME_SIZE 128 // 16kHz 8ms (128サンプル) #define WAV_FORMAT 1 // 1: WAVヘッダを追加, 0:PCM void fir_frame(float* coef, short *mem, int n, short *in, short *out); extern float g_filter_coef[FIR_TAP]; //フィルタ係数 short mem[FRAME_SIZE + FIR_TAP - 1]; //フィルタメモリ long get_file_size(const char *FileName); char* get_wav_header_16kHz(long wav_data_size); int main(int argc, char **argv) { FILE *fp_in; FILE *fp_out; int pcm_bytes = get_file_size(argv[1]); // サイズを取得 #if WAV_FORMAT ///////////// WAVヘッダ ////////////////// int wav_bytes = pcm_bytes / (FRAME_SIZE * 2); wav_bytes *= FRAME_SIZE * 2; char* wav_header = get_wav_header_16kHz(wav_bytes); // WAVヘッダを取得 #endif if ((fp_in = fopen(argv[1], "rb")) == NULL) { // PCM入力ファイル printf("can not open %s\n", argv[1]); exit(EXIT_FAILURE); } if ((fp_out = fopen(argv[2], "wb")) == NULL) { // PCM出力ファイル printf("can not open %s\n", argv[2]); exit(EXIT_FAILURE); } for (int i = 0; i < FIR_TAP; i++) mem[i] = 0; // フィルタメモリ初期化 #if WAV_FORMAT ///////////// WAVヘッダ ////////////////// fwrite(wav_header, WAV_HEADER_SIZE, 1, fp_out); // WAVヘッダ部分をファイル出力 #endif for (int i = 0; i < pcm_bytes; i += FRAME_SIZE * 2) { short in[FRAME_SIZE]; short out[FRAME_SIZE]; fread(in, sizeof(short), FRAME_SIZE, fp_in); fir_frame(g_filter_coef, mem, FRAME_SIZE, in, out); // FIRフレーム処理 fwrite(out, sizeof(short), FRAME_SIZE, fp_out); } fclose(fp_in); fclose(fp_out); return EXIT_SUCCESS; }
WAVヘッダのコード(get_wav_header_16kHz, get_file_size)は、こちら PCMにWAVヘッダを付ける
フィルタ係数(g_filter_coef)は、こちら FIRフィルタを作って周波数特性を検証