dsPIC33AKシリーズ⑯ DSPの使い方1(デジタルフィルタ)

dsPIC33Aシリーズ

概要

以前の記事にも有りますように、dsPICシリーズは「dsP」と頭文字がつくように、DSPが内蔵されています。今回は、dsPIC33AKシリーズのDSPの使い方をご紹介します。

関連記事

記事リンク
第1回dsPIC33AKシリーズについてdsPIC33Aシリーズに関して – ぴくおの電子工作的な何かWP (electricpico.com)
第2回開発ボード、コンフィグレーション設定、クロック設定についてdsPIC33AKシリーズ②開発ボード,コンフィグレーション設定,クロック設定について – ぴくおの電子工作的な何かWP (electricpico.com)
第3回CPU性能についてdsPIC33AKシリーズ③CPU性能について – ぴくおの電子工作的な何かWP (electricpico.com)
第4回FPU性能についてdsPIC33AKシリーズ④FPU性能について – ぴくおの電子工作的な何かWP (electricpico.com)
第5回DSPについてdsPIC33AKシリーズ⑤DSPについて – ぴくおの電子工作的な何かWP (electricpico.com)
第6回タイマー1割り込みの使い方dsPIC33AKシリーズ⑥Timer1割り込みの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第7回PMUの使い方dsPIC33AKシリーズ⑦PMUの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第8回高速ADCの使い方dsPIC33AKシリーズ⑧高速ADCの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第9回高速OPAMPの使い方dsPIC33AKシリーズ⑨高速OPAMPの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第10回DMAモジュールの使い方dsPIC33AKシリーズ⑩DMAモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第11回WDTモジュールの使い方dsPIC33AKシリーズ⑪WDTモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第12回DMTモジュールの使い方dsPIC33AKシリーズ⑫DMTモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第13回I/Oインテグリティモニタモジュールの使い方dsPIC33AKシリーズ⑬I/Oインテグリティモニターモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第14回QEIモジュールの使い方dsPIC33AKシリーズ⑭QEIモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第15回UARTモジュールの使い方dsPIC33AKシリーズ⑮UARTモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第16回(本記事)DSPの使い方1 デジタルフィルタ
(fig.1-1)各関連記事リンク
関連記事リンク
DSPライブラリの使い方1(デジタルフィルタ)DSPライブラリの使い方1(デジタルフィルタ) – ぴくおの電子工作的な何かWP (electricpico.com)
DSPライブラリの使い方2(FFT)DSPライブラリの使い方2(FFT) – ぴくおの電子工作的な何かWP (electricpico.com)

開発環境

開発環境を以下に示します。
今回はCPUボード(EV02G02A)で動作確認を行います。

項目リンク
ベースボードdsPIC33A CURIOSITY PLATFORM
DEVELOPMENT BOARD
dsPIC33A Curiosity Platform Development Board User’s Guide (microchip.com)
CPUボード(EV68M17A)EV68M17A – dsPIC33AK128MC106 Motor Control DIMdsPIC33AK128MC106 Motor Control Dual In-Line Module (DIM) Information Sheet (microchip.com)
CPUボード(EV02G02A)dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM)dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM) | Microchip Technology
統合開発環境MPLAB X IDE v6.20MPLAB® X IDE | Microchip Technology
コンパイラMPLAB XC DSC v3.10MPLAB® XC DSC Compiler | Microchip Technology
(fig.2-1)本記事の動作確認環境
(fig.2-2)動作環境

フィルタ特性について

今回はサンプリング周波数を48kHzに設定し、LPF/BPF/HPFの3種類のフィルタを試してみます。フィルタ設計については、以前の記事を参考にしてください。

タイプカットオフ周波数[Hz]ゲイン・フェーズ特性
LPF5k
BPF7k – 10k
HPF10k

ただし、今回は下表のとおり分解能は16ビットではなく32ビットに設定します

dsPIC33F/E/CdsPIC33A
説明文⑥Quantize Coefficients ウィンドウが開きますので、Quantize by に16bit / Format to save coeffsを Dec に設定し「OK」をクリック。⑥Quantize Coefficients ウィンドウが開きますので、Quantize by に32bit / Format to save coeffsを Dec に設定し「OK」をクリック。
イメージ

ソースコード

インクルードファイル

コンフィグレーションファイル、クロック設定ファイルは以下のファイルをインクルードしてください。

■コンフィグレーションファイル (config.h)

■クロック設定ソースファイル(Clock_Driver.c)

■クロックヘッダーファイル(clock_driver.h)

ライブラリインポート

DSPを使用する場合、dsp.hのインクルードとlibdsp-elf.aのインポートが必須です。

ソースコード全体

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include "clock_driver.h"
#include <dsp.h>

#define FIR_TAP		  100                //FIRタップ数
#define FIR_SFREQ	  48000              //FIRサンプリング周波数
#define FIR_DUMMY_A_FREQ    2000.0
#define FIR_DUMMY_B_FREQ    8500.0
#define FIR_DUMMY_C_FREQ    12000.0
#define FIR_DUMMY_A_GAIN    0.9
#define FIR_DUMMY_B_GAIN    0.5
#define FIR_DUMMY_C_GAIN    0.2

#define FIR_SPL_NUM         256

//入力ダミーデータ
float fl_FIRDummyData[FIR_SPL_NUM];
fractional fir_FIRDummyData[FIR_SPL_NUM];

//フィルタ構造
FIRStruct firFilterLPF;
FIRStruct firFilterBPF;
FIRStruct firFilterHPF;
//フィルタ出力
fractional fir_OutputLPF[FIR_SPL_NUM];
fractional fir_OutputBPF[FIR_SPL_NUM];
fractional fir_OutputHPF[FIR_SPL_NUM];
/*
U_0
Remez Algorithm LPF
Sampling Frequency =    48000.0
cutoff1 = 5000.0000000
cutoff2 = 6000.0000000
Tap Count = 100
attenuate =   -40.00
ripple factor =    0.1000000
*/
fractional LPF_SF48k_CF5k_100T[FIR_TAP] __attribute__((space(xmemory), far))= 		
{
-11345875	,
-1348086	,
2101441	,
3038787	,
5320409	,
2845042	,
747979	,
-4361683	,
-5804455	,
-6403468	,
-1598913	,
2916012	,
8395421	,
8350743	,
5483385	,
-2429496	,
-8614922	,
-12542608	,
-8780894	,
-1148515	,
9536639	,
15288686	,
14825745	,
5135436	,
-7568629	,
-19050243	,
-20872508	,
-12669195	,
4491020	,
20858908	,
29241529	,
22277659	,
2901321	,
-21887197	,
-38217748	,
-37139217	,
-14921886	,
19215710	,
50152787	,
59427382	,
37944823	,
-10987720	,
-67344991	,
-103091528	,
-90561247	,
-16586082	,
111645541	,
265039300	,
402334708	,
483213741	,
483213741	,
402334708	,
265039300	,
111645541	,
-16586082	,
-90561247	,
-103091528	,
-67344991	,
-10987720	,
37944823	,
59427382	,
50152787	,
19215710	,
-14921886	,
-37139217	,
-38217748	,
-21887197	,
2901321	,
22277659	,
29241529	,
20858908	,
4491020	,
-12669195	,
-20872508	,
-19050243	,
-7568629	,
5135436	,
14825745	,
15288686	,
9536639	,
-1148515	,
-8780894	,
-12542608	,
-8614922	,
-2429496	,
5483385	,
8350743	,
8395421	,
2916012	,
-1598913	,
-6403468	,
-5804455	,
-4361683	,
747979	,
2845042	,
5320409	,
3038787	,
2101441	,
-1348086	,
-11345875	

};

/*
U_0
Remez Algorithm BPF
Sampling Frequency =    48000.0
cutoff1 = 7000.0000000
cutoff2 = 8000.0000000
cutoff3 = 9000.0000000
cutoff4 = 10000.0000000
Tap Count = 100
attenuate =  -100.00
ripple factor =    0.1000000
*/
fractional BPF_SF48k_CF7k10k__100T[FIR_TAP] __attribute__((space(xmemory), far))= 	
{
-137284	,
383693	,
50904	,
55042	,
336813	,
429783	,
-265282	,
-1314330	,
-1083485	,
1197710	,
3332260	,
1767570	,
-3449184	,
-6574309	,
-1874078	,
7746838	,
10915680	,
459622	,
-14686346	,
-15734882	,
3640738	,
24458855	,
19853859	,
-11550546	,
-36596100	,
-21646933	,
23990460	,
49829102	,
19335100	,
-40914960	,
-62152223	,
-11427647	,
61265420	,
71118683	,
-2805381	,
-82951371	,
-74335670	,
22953832	,
103105517	,
70049274	,
-47328536	,
-118598930	,
-57653816	,
73130196	,
126696283	,
37981890	,
-96925144	,
-125687009	,
-13262466	,
115322660	,
115322660	,
-13262466	,
-125687009	,
-96925144	,
37981890	,
126696283	,
73130196	,
-57653816	,
-118598930	,
-47328536	,
70049274	,
103105517	,
22953832	,
-74335670	,
-82951371	,
-2805381	,
71118683	,
61265420	,
-11427647	,
-62152223	,
-40914960	,
19335100	,
49829102	,
23990460	,
-21646933	,
-36596100	,
-11550546	,
19853859	,
24458855	,
3640738	,
-15734882	,
-14686346	,
459622	,
10915680	,
7746838	,
-1874078	,
-6574309	,
-3449184	,
1767570	,
3332260	,
1197710	,
-1083485	,
-1314330	,
-265282	,
429783	,
336813	,
55042	,
50904	,
383693	,
-137284	
};
/*
U_0
Remez Algorithm HPF
Sampling Frequency =    48000.0
cutoff1 = 10000.0000000
cutoff2 = 11000.0000000
Tap Count = 100
attenuate =  -100.00
ripple factor =    0.1000000
Quantized by 32 [bits]
      631042
*/
fractional HPF_SF48k_CF10k_100T[FIR_TAP] __attribute__((space(xmemory), far))= 		
{
631042	,
7886162	,
-36828284	,
66598643	,
-52523460	,
-3268292	,
32315499	,
-2502069	,
-23918555	,
794611	,
20056737	,
2622472	,
-17538827	,
-6674920	,
15044598	,
10841364	,
-11787302	,
-14803700	,
7493018	,
17986285	,
-1920700	,
-19990284	,
-4689383	,
20145758	,
12119433	,
-18091418	,
-19649860	,
13301775	,
26603126	,
-5607716	,
-32075079	,
-4838361	,
34793249	,
17998637	,
-33875157	,
-33081339	,
27957117	,
49302389	,
-15581318	,
-65755972	,
-5098258	,
81319072	,
37580014	,
-94803461	,
-90977124	,
105253372	,
199264175	,
-111926424	,
-673824800	,
1187934027	,
-673824800	,
-111926424	,
199264175	,
105253372	,
-90977124	,
-94803461	,
37580014	,
81319072	,
-5098258	,
-65755972	,
-15581318	,
49302389	,
27957117	,
-33081339	,
-33875157	,
17998637	,
34793249	,
-4838361	,
-32075079	,
-5607716	,
26603126	,
13301775	,
-19649860	,
-18091418	,
12119433	,
20145758	,
-4689383	,
-19990284	,
-1920700	,
17986285	,
7493018	,
-14803700	,
-11787302	,
10841364	,
15044598	,
-6674920	,
-17538827	,
2622472	,
20056737	,
794611	,
-23918555	,
-2502069	,
32315499	,
-3268292	,
-52523460	,
66598643	,
-36828284	,
7886162	,
631042	,
0	

};
fractional Delays[FIR_TAP] __attribute__((space(ymemory), far));

int32_t i4g_Time[16];

/*----------------------------------------------------------------------------*/
/**
* @fn          main(int argc, char** argv) 
* @brief       PROJECT_4_1_1_DSP_FIR
* @param[in]   argc argument count
* @param[in]   argv argument vector
* @retval      EXIT_SUCCESS 成功
* @retval      EXIT_FAILURE 失敗
* @detail      DSPによるFFT
* @note        
 */
/*----------------------------------------------------------------------------*/
int main(int argc, char** argv) 
{
    unsigned int u2l_Loop;
    unsigned int u2lCnt;
    float f4_Time;
    float f4_DummyA;
    float f4_DummyB;
    float f4_DummyC; 
	
  CORCON = 0x00;
	
    /*------------------------------------------------------------------------*/
    /* クロック初期化*/
    /*------------------------------------------------------------------------*/
        vdg_Clock_Set_Register();    /* クロック初期化 */

    /*-----------------------------------------------------------------------*/
    /* Timerレジスタ */
    /*-----------------------------------------------------------------------*/
       PR1 = 1000000;
       T1CONbits.ON = 1;
       T1CONbits.TCKPS = 0;
       IFS1bits.T1IF = 0;
       IEC1bits.T1IE = 0;
       IPC6bits.T1IP = 3;
		
       INTCON1bits.GIE = 0;
		
    /*------------------------------------------------------------------------*/
    /* フィルタ係数初期化*/
    /*------------------------------------------------------------------------*/
        FIRStructInit( &firFilterLPF,          // フィルター構造体
                        FIR_TAP,               // フィルター係数タップ数
                        LPF_SF48k_CF5k_100T,   // フィルタ係数ポインタ
                        0,		       // フィルタ係数PSVページ
                        Delays );             // ディレイバッファ
        FIRStructInit( &firFilterBPF,         // フィルター構造体
                        FIR_TAP,              // フィルター係数タップ数
                        BPF_SF48k_CF7k10k__100T,  // フィルタ係数ポインタ
                        0,			  // フィルタ係数PSVページ
                        Delays );           // ディレイバッファ
        FIRStructInit( &firFilterHPF,       // フィルター構造体
                        FIR_TAP,            // フィルター係数タップ数
                        HPF_SF48k_CF10k_100T,	 // フィルタ係数ポインタ
                        0,			// フィルタ係数PSVページ
                        Delays );           // ディレイバッファ
    /*------------------------------------------------------------------------*/
    /* ディレイバッファクリア*/
    /*------------------------------------------------------------------------*/
        FIRDelayInit( &firFilterLPF ); // フィルター構造体
        FIRDelayInit( &firFilterBPF ); // フィルター構造体
        FIRDelayInit( &firFilterHPF ); // フィルター構造体
    /*------------------------------------------------------------------------*/
    /* ダミーデータ生成*/
    /*------------------------------------------------------------------------*/
        for (u2l_Loop = 0;u2l_Loop < FIR_SPL_NUM ;u2l_Loop ++)
        {
            f4_Time = (float)u2l_Loop/(FIR_SFREQ);
            f4_DummyA = sin(f4_Time * FIR_DUMMY_A_FREQ * 2 * PI) * FIR_DUMMY_A_GAIN  ;
            f4_DummyB = sin(f4_Time * FIR_DUMMY_B_FREQ * 2 * PI) * FIR_DUMMY_B_GAIN  ;
	    f4_DummyC = sin(f4_Time * FIR_DUMMY_C_FREQ * 2 * PI) * FIR_DUMMY_C_GAIN  ;
			fl_FIRDummyData[u2l_Loop] = (f4_DummyA + f4_DummyB + f4_DummyC);
            fir_FIRDummyData[u2l_Loop] = fl_FIRDummyData[u2l_Loop] * 1073741823;
        }
    /*------------------------------------------------------------------------*/
    /* フィルタ演算*/
    /*------------------------------------------------------------------------*/
	i4g_Time[0] = TMR1;
        for (u2lCnt = 0;u2lCnt < FIR_SPL_NUM;u2lCnt ++)
        {
            FIR( 1,                                 // 入力信号個数
                &fir_OutputLPF[u2lCnt],                // 出力サンプル変数ポインタ
                &fir_FIRDummyData[u2lCnt],      // 入力サンプル変数ポインタ
                &firFilterLPF );                       // フィルター構造体
        }

	i4g_Time[1] = TMR1;
        for (u2lCnt = 0;u2lCnt < FIR_SPL_NUM;u2lCnt ++)
        {
            FIR( 1,                                 // 入力信号個数
                &fir_OutputBPF[u2lCnt],                // 出力サンプル変数ポインタ
                &fir_FIRDummyData[u2lCnt],      // 入力サンプル変数ポインタ
                &firFilterBPF );                       // フィルター構造体
        }

	i4g_Time[2] = TMR1;
        for (u2lCnt = 0;u2lCnt < FIR_SPL_NUM;u2lCnt ++)
        {
            FIR( 1,                                 // 入力信号個数
                &fir_OutputHPF[u2lCnt],                // 出力サンプル変数ポインタ
                &fir_FIRDummyData[u2lCnt],      // 入力サンプル変数ポインタ
                &firFilterHPF );                       // フィルター構造体
        }
	i4g_Time[3] = TMR1;

    /*------------------------------------------------------------------------*/
    /* メインループ*/
    /*------------------------------------------------------------------------*/
        while(1)
        {

        }    
    return EXIT_SUCCESS
}

結果

生信号に対してそれぞれLPF/BPF/HPF処理を行った結果、目的の周波数の信号と振幅を得られることが確認できました。

今回の256サンプルを実行する処理では、約238μsecで演算を完了しました。
1サンプルの場合、処理は約0.9μsecで完了するため、48kHzのサンプリングごとに実行しても、0.9μsec/20.83μsecで十分な余裕があることが確認できました。

記事についての注意点

本記事は慎重に内容を検討し正確さに努めておりますが、内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。

コメント

タイトルとURLをコピーしました