AM中波放送用SDR.CICフィルタのみを使用.CQ出版社「トランジスタ技術」誌,2021年5月号に掲載

Dependencies:   mbed

main.cpp

Committer:
MikamiUitOpen
Date:
2021-02-04
Revision:
1:2b596eab04de
Parent:
0:4037028ba61a
Child:
2:fa94a6a917dd

File content as of revision 1:2b596eab04de:

//-------------------------------------------------------------
//  FM 用 SDR
//      入力信号:SDR_FM_Tx で発生した信号
//      入力ピン: A1
//      出力ピン: A2
//  ダウンサンプリングで CIC フィルタを使用
//
//  Tera Term から選局可能,0 と 1
//
//  2021/02/04, Copyright (c) 2021 MIKAMI, Naoki
//-------------------------------------------------------------

#include "F446_ADC_Intr.hpp"
#include "F446_DAC.hpp"
#include "QuadOscIir.hpp"
#include "Cic3Stage.hpp"
#include "FastATan.hpp"
#include "IirDcCut.hpp"
#include "InitialMessage.hpp"   // 最初のメーッセージ
using namespace Mikami;
#pragma diag_suppress 870   // マルチバイト文字使用の警告抑制のため

const float FS_ = 900.0f;       // 標本化周波数,単位: kHz
const float T0_ = 1000/FS_;     // 標本化間隔,単位:μs
const float A0_ = 8192;         // 直交信号発生器の出力の振幅

const float F_C_[] = { 70.0e3f, 130.0e3f};  // 搬送波周波数

AdcF446_Intr adc_(FS_, A1);
DacF446 dac_;
Serial pc_(USBTX, USBRX);           // ターミナルに対する受信割込み用

// 直流分除去用フィルタ
// 高域通過フィルタ
// バタワース特性
// 次数    : 1 次
// 標本化周波数: 36.00 kHz
// 遮断周波数 :  0.05 kHz
IirDcCut dcCut_(9.913112E-01f, 9.956556E-01f);  // 入力の直流成分除去用フィルタ

QuadOscIir nco_(F_C_[0], T0_, A0_); // NCO (numerically controlled oscillator)

const int DS_RATE_ = 25;    // 1/25 にダウンサンプリング
Cic3Stage cic3I_(DS_RATE_, A0_);
Cic3Stage cic3Q_(DS_RATE_, A0_);

// AD 変換終了割り込みに対する割り込みサービス・ルーチン
void AdcIsr()
{
    static int count = 0;

    float xn = adc_.Read();     // ADC の読込み
    float sinX, cosX;
    nco_.Generate(sinX, cosX);  // sin, cos 発生

    cic3I_.Integrate((int16_t)(xn*cosX));   // I 信号
    cic3Q_.Integrate((int16_t)(xn*sinX));   // Q 信号
    
    if (++count >= DS_RATE_)
    {
        count = 0;
        NVIC->STIR |= EXTI4_IRQn;   // ソフトウェア割り込み発生
    }
}

// ダウンサンプラより後の処理に対する割り込みサービス・ルーチン
void SwiIsr()
{
    static const float PI  = 3.141592654;
    static const float PI2 = 2.0f*PI;
    static float phi_nM1 = 0;           // 一つ前の位相の値

    float yI_n = cic3I_.CombFilter();   // くし形フィルタ処理で I 信号を生成
    float yQ_n = cic3Q_.CombFilter();   // くし形フィルタ処理で Q 信号を生成

    float phi_n = FastATan(yQ_n, yI_n); // 位相成分を求める
    float dif = phi_n - phi_nM1;        // 位相の差分
    if (dif > PI) dif -= PI2;           // 差分処理の補正
    if (dif < -PI) dif += PI2;          // 差分処理の補正
    
    float yn = dcCut_.Execute(dif);     // 直流分除去
    dac_.Write(yn);
    phi_nM1 = phi_n;
}

// シリアル・ポートの受信割込みに対する処理
void RxIsr()
{
    unsigned char chr = pc_.getc();
    // 受信した文字が '0', '1' の場合のみ NCO の周波数を変える
    if (('0' <= chr) && (chr <= '1'))
    {
        nco_.Set(F_C_[chr & 0x01]);
        pc_.putc(chr);   // エコーバック
    }
    if (chr == '\r') pc_.printf("\r\n");
}

int main()
{
    InitialMessage("ダウンサンプリングに CIC フィルタ使用.", FM, pc_);

    NVIC_SetPriority(ADC_IRQn,    0);   // 最優先
    NVIC_SetPriority(EXTI4_IRQn,  1);   // 2番目に優先
    NVIC_SetPriority(USART2_IRQn, 2);   // 3番目に優先

    adc_.SetIntrVec(&AdcIsr);   // ADC の割り込みサービス・ルーチンの設定

    // EXTI4 によるソフトウェア割り込みに対応する設定
    NVIC_SetVector(EXTI4_IRQn, (uint32_t)SwiIsr);
    NVIC_EnableIRQ(EXTI4_IRQn);

    // シリアル・ポートの受信割込みの設定
    pc_.format();    // default: 8 bits, nonparity, 1 stop bit
    pc_.attach(&RxIsr);

    while (true) {}
}