dsPICでボコーダ2009/08/17 12:08

以前PC用につくったボコーダプログラムをdsPIC用に書き直してみました。
固定小数点のプログラミングがなかなかうまくいかず非常に苦労しました。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; i0; 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の入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://gijishinpo.asablo.jp/blog/2009/08/17/4520955/tb