dsPICでボコーダ ― 2009/08/17 12:08
以前PC用につくったボコーダプログラムをdsPIC用に書き直してみました。
固定小数点のプログラミングがなかなかうまくいかず非常に苦労しました。dsPIC(C30コンパイラ)にはfractionalという固定小数点型があって、これを利用すると積和演算などが高速に行えるということなのですが、計算途中でオーバフローを起こしているらしく、うまく使えませんでした。結局long int型を使ってなんとか動かすことができました。
計算速度の関係でサンプリング周波数は4kHz、フィルタのタップ数は4としています。そのためボコーダとしては最低の性能になっていると思います。何と発音しているかは識別できません。タップ数を増やせないのが致命的です。
固定小数点のプログラミングがなかなかうまくいかず非常に苦労しました。dsPIC(C30コンパイラ)にはfractionalという固定小数点型があって、これを利用すると積和演算などが高速に行えるということなのですが、計算途中でオーバフローを起こしているらしく、うまく使えませんでした。結局long int型を使ってなんとか動かすことができました。
計算速度の関係でサンプリング周波数は4kHz、フィルタのタップ数は4としています。そのためボコーダとしては最低の性能になっていると思います。何と発音しているかは識別できません。タップ数を増やせないのが致命的です。
#include#include "adc10.h" #include "timer.h" #include "dsp.h" // Configuration bits-------------------------------------------------------- _FOSC(CSW_FSCM_OFF & FRC_PLL16); //FRC with 16xPLL oscillator, Failsafe clock off _FWDT(WDT_OFF); //Watchdog timer disabled _FBORPOR(PBOR_OFF & MCLR_EN); //Brown-out reset disabled, MCLR reset enabled _FGS(CODE_PROT_OFF); //Code protect disabled //// Setup Data for 10bits A/D Converter //// AN0のみサンプル Tad=200nsec@40MHz //// タイマ3で自動スタート, 自動スキャン無し unsigned int ValueADCON1 = ADC_MODULE_ON & ADC_IDLE_STOP & ADC_FORMAT_INTG & ADC_CLK_TMR & ADC_AUTO_SAMPLING_ON & ADC_SAMPLE_INDIVIDUAL & ADC_SAMP_OFF; unsigned int ValueADCON2 = ADC_VREF_AVDD_AVSS & ADC_SCAN_OFF & ADC_CONVERT_CH0 & ADC_SAMPLES_PER_INT_1 & ADC_ALT_BUF_OFF & ADC_ALT_INPUT_OFF; unsigned int ValueADCON3 = ADC_SAMPLE_TIME_1 & ADC_CONV_CLK_SYSTEM & ADC_CONV_CLK_2Tcy; unsigned int ValueADPCFG = ENABLE_AN0_ANA & ENABLE_AN1_ANA & ENABLE_AN2_ANA & ENABLE_AN3_ANA; unsigned int ValueADCSSL = 0; unsigned int Channel0 = ADC_CH0_POS_SAMPLEA_AN0 & ADC_CH0_NEG_SAMPLEA_NVREF; // Definitions--------------------------------------------------------------- #define BUF_LEN 256 #define LPC_ORDER 4 //グローバル変数----------------------------------------------------------------- long int lpc[LPC_ORDER+1]; long int in_buf[BUF_LEN]; long int out_buf[LPC_ORDER+1]; int ix_buf = 0; int ix_read = 0; int ix_write = 0; int ratio = 0; int s_cnt = 0; //音程用 int zero_cnt = 0; unsigned char sound = 0; //// タイマ1割り込み処理(16k/256/2Hz) void _ISR _T1Interrupt(void) { int n,m,k; int i,j; long int r[LPC_ORDER+1]; long int a[LPC_ORDER+1]; long int b[LPC_ORDER+1]; long int alfa; long int km,alfam,t; IFS0bits.T1IF = 0; //AutoCorrelation for(i=0; i<=LPC_ORDER; i++){ r[i] = 0; for(j=0; j<(BUF_LEN-i); j++){ r[i] += ((in_buf[j] * in_buf[j+i])>>8); } } //Levinson-Durbin a[0] = 1<<8; alfam = r[0]; for(m=1; m<=LPC_ORDER; m++){ t = r[m]; for(k=1; k<=m-1; k++){ t = t + ((r[m-k]*a[k])>>8); } if(alfam==0)alfam=1; km = -((t<<8)/alfam); for(k=1; k<=m-1; k++){ b[k] = a[m-k]; } for(k=1; k<=m-1; k++){ a[k] = a[k] + ((km*b[k])>>8); } a[m] = km; alfam = (alfam*((1<<8) - ((a[m]*a[m])>>8)))>>8; } alfa = alfam; for(i=0; i 0; i--){ out_buf[i-1] = 0; } } //// ADC割り込み処理(約16kHz) void _ISRFAST _ADCInterrupt(void) { long int tone; fractional SigIn; long int out; int d_out; int i; int on; IFS0bits.ADIF = 0; //音程生成 s_cnt++; if(s_cnt==16){ s_cnt = 0; tone=1<<7; }else{ tone=0; } //AD input in_buf[ix_buf] = (long int)(ReadADC10(0)>>2)-128; if(in_buf[ix_buf]<32 && in_buf[ix_buf]>-32){ in_buf[ix_buf]=0; zero_cnt++; //sound = 0; }else{ sound = 1; zero_cnt = 0; } if(zero_cnt>10){sound = 0;} if(sound==0){tone = 0;} ix_buf++; if(ix_buf>=BUF_LEN){ ix_buf = 0; } //合成フィルタ out = -( ((lpc[0] * out_buf[0])>>8) + ((lpc[1] * out_buf[1])>>8) + ((lpc[2] * out_buf[2])>>8) + ((lpc[3] * out_buf[3])>>8) ) + tone; for(i=LPC_ORDER; i>0; i--){ out_buf[i] = out_buf[i-1]; } out_buf[0] = out; //出力処理 d_out = 0x7000 | ((0x8000 + (out<<7))>>4); LATEbits.LATE0 = 0; //CS=0 for(i=0; i<16; i++){ if(((d_out << i) & 0x8000) != 0){ LATEbits.LATE2 = 1; //SDI=1 }else{ LATEbits.LATE2 = 0; //SDI=0 } LATEbits.LATE1 = 1; //SCK=1 LATEbits.LATE1 = 0; //SCK=0 } LATEbits.LATE0 = 1; //CS=1 LATEbits.LATE3 = 0; //LDAC=0 LATEbits.LATE3 = 1; //LDAC=0 } //main----------------------------------------------------------------------- int main(void) { int i,j; int data; //Initialize LATE = 0x0000; // // Setup Port TRISB = 0x01; //AN0 input TRISE = 0x00; //all output SRbits.IPL=4; //Set CPU priority Set core priority level to 4 // Setup ADC10 OpenADC10(ValueADCON1, ValueADCON2, ValueADCON3, ValueADPCFG, ValueADCSSL); SetChanADC10(Channel0); ConfigIntADC10(ADC_INT_PRI_7 & ADC_INT_ENABLE); // タイマ1設定 サンプリング周期 4/256/2kHz = (7.37MHz*16/4)/256/3684 OpenTimer1(T1_ON & T1_GATE_OFF & T1_PS_1_256 & T1_SOURCE_INT,3684*2-1); IPC0bits.T1IP = 5; IFS0bits.T1IF = 0; IEC0bits.T1IE = 1; // タイマ3設定 サンプリング周期 4kHz = (7.37MHz*16/4)/1842 OpenTimer3(T3_ON & T3_GATE_OFF & T3_PS_1_1 & T3_SOURCE_INT,1842*4-1); // init mcp4922 LATEbits.LATE0 = 1; //CS LATEbits.LATE1 = 0; //SCK LATEbits.LATE2 = 0; //SDI LATEbits.LATE3 = 1; //LDAC //Idle Loop while (1){}; }
コメント
トラックバック
このエントリのトラックバックURL: http://gijishinpo.asablo.jp/blog/2009/08/17/4520955/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。