//Copyright+LGPL //----------------------------------------------------------------------------------------------------------------------------------------------- // Copyright 2000-2013 Makoto Mori, Nobuyuki Oba //----------------------------------------------------------------------------------------------------------------------------------------------- // This file is part of MMSSTV. // MMSSTV is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. // MMSSTV is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public License along with MMTTY. If not, see // . //----------------------------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include //ja7ude 0521 #pragma hdrstop #include #include "fir.h" //------------------------------------------------- // FIRフィルタのたたき込み演算 double __fastcall DoFIR(double *hp, double *zp, double d, int tap) { memcpy(zp, &zp[1], sizeof(double)*tap); zp[tap] = d; d = 0.0; for( int i = 0; i <= tap; i++, hp++, zp++ ){ d += (*zp) * (*hp); } return d; } //--------------------------------------------------------------------------- CIIRTANK::CIIRTANK() { b1 = b2 = a0 = z1 = z2 = 0; SetFreq(2000.0, SampFreq, 50.0); } //--------------------------------------------------------------------------- void CIIRTANK::SetFreq(double f, double smp, double bw) { double lb1, lb2, la0; lb1 = 2 * exp(-PI * bw/smp) * cos(2 * PI * f / smp); lb2 = -exp(-2*PI*bw/smp); if( bw ){ #if 0 const double _gt[]={18.0, 26.0, 20.0, 20.0}; la0 = sin(2 * PI * f/smp) / (_gt[SampType] * 50 / bw); #else la0 = sin(2 * PI * f/smp) / ((smp/6.0) / bw); #endif } else { la0 = sin(2 * PI * f/smp); } b1 = lb1; b2 = lb2; a0 = la0; } //--------------------------------------------------------------------------- double CIIRTANK::Do(double d) { d *= a0; d += (z1 * b1); d += (z2 * b2); z2 = z1; if( fabs(d) < 1e-37 ) d = 0.0; z1 = d; return d; } //--------------------------------------------------------------------------- CLMS::CLMS() { Z = new double[LMSTAP+1]; H = new double[LMSTAP+1]; D = new double[LMSTAP+1]; memset(Z, 0, sizeof(double[LMSTAP+1])); memset(H, 0, sizeof(double[LMSTAP+1])); memset(D, 0, sizeof(double[LMSTAP+1])); m_D = 0; m_lmsADJSC = 1.0 / double(32768 * 32768); // スケール調整値 m_lmsErr = m_lmsMErr = 0; m_Tap = int((4 * SampBase/11025) + 0.5); // m_Tap = int((8 * SampBase/11025) + 0.5); if( m_Tap > LMSTAP ) m_Tap = LMSTAP; m_lmsMU2 = 0.003; // LMS 2μ m_lmsGM = 0.9999; // LMS γ m_Tap_N = int((48 * SampBase/11025) + 0.5); if( m_Tap_N > LMSTAP ) m_Tap_N = LMSTAP; // m_lmsMU2_N = 0.00018; // LMS 2μ // m_lmsGM_N = 0.999999; // LMS γ m_lmsMU2_N = 0.00018; // LMS 2μ m_lmsGM_N = 0.999999; // LMS γ m_lmsDelay_N = int((12 * SampBase/11025) + 0.5); if( m_lmsDelay_N > LMSTAP ) m_lmsDelay_N = LMSTAP; } CLMS::~CLMS() { delete D; delete H; delete Z; } //------------------------------------------------- // 適応フィルタの演算 double CLMS::Do(double d) { double a = 0.0; int i; double *zp = Z; double *hp = H; // トランスバーサルフィルタ memcpy(Z, &Z[1], sizeof(double)*m_Tap); #if 0 Z[m_Tap] = D[0]; #else Z[m_Tap] = m_D; #endif for( i = 0; i <= m_Tap; i++, zp++, hp++ ){ a += (*zp) * (*hp); } // 誤差計算 m_lmsErr = d - a; m_lmsMErr = m_lmsErr * m_lmsMU2 * m_lmsADJSC; // lmsADJSC = 1/(32768 * 32768) スケーリング調整値 // 遅延器の移動 #if 0 if( m_lmsDelay ) memcpy(D, &D[1], sizeof(double)*m_lmsDelay); D[m_lmsDelay] = d; #else m_D = d; #endif // 係数更新 zp = Z; hp = H; double sum = 0; for( i = 0; i <= m_Tap; i++, zp++, hp++ ){ *hp = (m_lmsMErr * (*zp)) + (*hp * m_lmsGM); if( *hp >= 0 ){ sum += *hp; } else { sum -= *hp; } } if( sum > 0 ) a /= sum; return a; } //------------------------------------------------- // 適応フィルタの演算 double CLMS::DoN(double d) { double a = 0.0; int i; double *zp = Z; double *hp = H; // トランスバーサルフィルタ memcpy(Z, &Z[1], sizeof(double)*m_Tap_N); Z[m_Tap_N] = D[0]; for( i = 0; i <= m_Tap_N; i++, zp++, hp++ ){ a += (*zp) * (*hp); } // 誤差計算 m_lmsErr = d - a; m_lmsMErr = m_lmsErr * m_lmsMU2_N * m_lmsADJSC; // lmsADJSC = 1/(32768 * 32768) スケーリング調整値 // 遅延器の移動 memcpy(D, &D[1], sizeof(double)*m_lmsDelay_N); D[m_lmsDelay_N] = d; // 係数更新 zp = Z; hp = H; for( i = 0; i <= m_Tap_N; i++, zp++, hp++ ){ *hp = (m_lmsMErr * (*zp)) + (*hp * m_lmsGM_N); } return m_lmsErr; } //------------------------------------------------- // 適応フィルタの演算 void CLMS::SetAN(int sw) { m_Tap_N = int((48 * SampBase/11025) + 0.5); if( m_Tap_N > LMSTAP ) m_Tap_N = LMSTAP; m_lmsDelay_N = int((12 * SampBase/11025) + 0.5); if( m_lmsDelay_N > LMSTAP ) m_lmsDelay_N = LMSTAP; memset(Z, 0, sizeof(double[LMSTAP+1])); memset(H, 0, sizeof(double[LMSTAP+1])); memset(D, 0, sizeof(double[LMSTAP+1])); switch(sw){ case 1: m_lmsMU2_N = 0.00018; // LMS 2μ m_lmsGM_N = 0.999998; // LMS γ break; default: m_lmsMU2_N = 0.00005; // LMS 2μ m_lmsGM_N = 0.9999985; // LMS γ break; } } //------------------------------------------------- // 相関計算の演算 int CLMS::Sig(double d) { double a = 0.0; int i; double *zp = Z; double *hp = H; // トランスバーサルフィルタ memcpy(Z, &Z[1], sizeof(double)*m_Tap); #if 0 Z[m_Tap] = D[0]; #else Z[m_Tap] = m_D; #endif for( i = 0; i <= m_Tap; i++, zp++, hp++ ){ a += (*zp) * (*hp); } // 誤差計算 m_lmsErr = d - a; m_lmsMErr = m_lmsErr * m_lmsMU2 * m_lmsADJSC; // lmsADJSC = 1/(32768 * 32768) スケーリング調整値 // 遅延器の移動 #if 0 if( m_lmsDelay ) memcpy(D, &D[1], sizeof(double)*m_lmsDelay); D[m_lmsDelay] = d; #else m_D = d; #endif // 係数更新 zp = Z; hp = H; double sum = 0; for( i = 0; i <= m_Tap; i++, zp++, hp++ ){ *hp = (m_lmsMErr * (*zp)) + (*hp * m_lmsGM); if( *hp >= 0 ){ sum += *hp; } else { sum -= *hp; } } return sum * 32768.0; } //--------------------------------------------------------------------------- // ノッチフィルタ __fastcall CNotch::CNotch() { // m_pZ = new double[NOTCHTAPMAX+1]; // m_pH = new double[NOTCHTAPMAX+1]; // memset(m_pZ, 0, sizeof(double)*NOTCHTAPMAX+1); m_tap = 96 * SampBase / 11025.0; if( m_tap & 1 ) m_tap++; if( m_tap >= NOTCHTAPMAX ) m_tap = NOTCHTAPMAX; SetNotchFreq(2400); } __fastcall CNotch::~CNotch() { // delete m_pZ; // delete m_pH; } void __fastcall CNotch::SetNotchFreq(double fq) { m_freq = fq; double fl, fh; if( (fq < 1050.0) || (fq > 2350) ){ fl = fq - 30; fh = fq + 30; } else { fl = fq - 15; fh = fq + 15; } m_Notch.Create(m_tap, ffBEF, SampFreq, fl, fh, 10, 1.0); // MakeFilter(m_pH, m_tap, ffBEF, SampFreq, fl, fh, 10, 1.0); } double __fastcall CNotch::Do(double d) { return m_Notch.Do(d); // return DoFIR( m_pH, m_pZ, d, m_tap); } /********************************************************************** FIRフィルタ設計関数 **********************************************************************/ /* ==================================================== ベッセル関数 ==================================================== */ static double I0(double x) { double sum, xj; int j; sum = 1.0; xj = 1.0; j = 1; while(1){ xj *= ((0.5 * x) / (double)j); sum += (xj*xj); j++; if( ((0.00000001 * sum) - (xj*xj)) > 0 ) break; } return(sum); } /* ==================================================== FIRフィルタの設計 ==================================================== */ void MakeFilter(double *HP, int tap, int type, double fs, double fcl, double fch, double att, double gain) { FIR fir; fir.typ = type; fir.n = tap; fir.fs = fs; fir.fcl = fcl; fir.fch = fch; fir.att = att; fir.gain = gain; MakeFilter(HP, &fir); } void MakeFilter(double *HP, FIR *fp) { int j, m; double alpha, win, fm, w0, sum; double *hp; if( fp->typ == ffHPF ){ fp->fc = 0.5*fp->fs - fp->fcl; } else if( fp->typ != ffLPF ){ fp->fc = (fp->fch - fp->fcl)/2.0; } else { fp->fc = fp->fcl; } if( fp->att >= 50.0 ){ alpha = 0.1102 * (fp->att - 8.7); } else if( fp->att >= 21 ){ alpha = (0.5842 * pow(fp->att - 21.0, 0.4)) + (0.07886 * (fp->att - 21.0)); } else { alpha = 0.0; } hp = fp->hp; sum = PI*2.0*fp->fc/fp->fs; if( fp->att >= 21 ){ // インパルス応答と窓関数を計算 for( j = 0; j <= (fp->n/2); j++, hp++ ){ fm = (double)(2 * j)/(double)fp->n; win = I0(alpha * sqrt(1.0-(fm*fm)))/I0(alpha); if( !j ){ *hp = fp->fc * 2.0/fp->fs; } else { *hp = (1.0/(PI*(double)j))*sin((double)j*sum)*win; } } } else { // インパルス応答のみ計算 for( j = 0; j <= (fp->n/2); j++, hp++ ){ if( !j ){ *hp = fp->fc * 2.0/fp->fs; } else { *hp = (1.0/(PI*(double)j))*sin((double)j*sum); } } } hp = fp->hp; sum = *hp++; for( j = 1; j <= (fp->n/2); j++, hp++ ) sum += 2.0 * (*hp); hp = fp->hp; if( sum > 0.0 ){ for( j = 0; j <= (fp->n/2); j++, hp++ ) (*hp) /= sum; } // 周波数変換 if( fp->typ == ffHPF ){ hp = fp->hp; for( j = 0; j <= (fp->n/2); j++, hp++ ) (*hp) *= cos((double)j*PI); } else if( fp->typ != ffLPF ){ w0 = PI * (fp->fcl + fp->fch) / fp->fs; if( fp->typ == ffBPF ){ hp = fp->hp; for( j = 0; j <= (fp->n/2); j++, hp++ ) (*hp) *= 2.0*cos((double)j*w0); } else { hp = fp->hp; *hp = 1.0 - (2.0 * (*hp)); for( hp++, j = 1; j <= (fp->n/2); j++, hp++ ) (*hp) *= -2.0*cos((double)j*w0); } } for( m = fp->n/2, hp = &fp->hp[m], j = m; j >= 0; j--, hp-- ){ *HP++ = (*hp) * fp->gain; } for( hp = &fp->hp[1], j = 1; j <= (fp->n/2); j++, hp++ ){ *HP++ = (*hp) * fp->gain; } } //--------------------------------------------------------------------------- //FIRフィルタ(ヒルベルト変換フィルタ)の設計 // void MakeHilbert(double *H, int N, double fs, double fc1, double fc2) { int L = N / 2; double T = 1.0 / fs; double W1 = 2 * PI * fc1; double W2 = 2 * PI * fc2; // 2*fc2*T*SA((n-L)*W2*T) - 2*fc1*T*SA((n-L)*W1*T) double w; int n; double x1, x2; for( n = 0; n <= N; n++ ){ if( n == L ){ x1 = x2 = 0.0; } else if( (n - L) ){ x1 = ((n - L) * W1 * T); x1 = cos(x1) / x1; x2 = ((n - L) * W2 * T); x2 = cos(x2) / x2; } else { x1 = x2 = 1.0; } w = 0.54 - 0.46 * cos(2*PI*n/(N)); H[n] = -(2 * fc2 * T * x2 - 2 * fc1 * T * x1) * w; } if( N < 8 ){ w = 0; for( n = 0; n <= N; n++ ){ w += fabs(H[n]); } if( w ){ w = 1.0 / w; for( n = 0; n <= N; n++ ){ H[n] *= w; } } } } //--------------------------------------------------------------------- // 周波数特性グラフ(フィルタスレッド内でコールしてはいけない) // // H(ejωT) = [Σ0]Hm cos(mωT) - j[Σ1]Hm sin(mωT) // void DrawGraph(Graphics::TBitmap *pBitmap, const double *H, int Tap, int Over, int &nmax, int init, TColor col) { int k, x, y; double f, gdb, g, pi2t, fs; double max; char bf[80]; TCanvas *tp = pBitmap->Canvas; TRect rc; rc.Left = 0; rc.Right = pBitmap->Width; rc.Top = 0; rc.Bottom = pBitmap->Height; if( init ){ tp->Brush->Color = clWhite; tp->FillRect(rc); } int LM; // 周波数表示のあるライン数 int DM; // 内部線の数 int MM; // 実線の間隔 switch(Over){ case 2: max = 3000; fs = SampFreq/2.0; break; case 3: max = 2000; fs = SampFreq/3.0; break; default: max = 4000; fs = SampFreq; break; } if( nmax ){ max = nmax; } else { nmax = max; } switch(nmax){ case 3000: LM = 3; DM = 14; MM = 5; break; case 100: case 200: case 2000: LM = 4; DM = 19; MM = 5; break; case 400: case 800: case 4000: LM = 4; DM = 19; MM = 5; break; default: // 6000 LM = 3; DM = 11; MM = 4; break; } int XL = 32; int XR = pBitmap->Width - 16; int YT = 16; int YB = pBitmap->Height - 24; int i; if( init ){ tp->Pen->Color = clBlack; tp->Font->Size = 8; tp->MoveTo(XL, YT); tp->LineTo(XR, YT); tp->LineTo(XR, YB); tp->LineTo(XL, YB); tp->LineTo(XL, YT); tp->Pen->Color = clGray; for( i = 0; i < 7; i++ ){ tp->Pen->Style = (i & 1) ? psSolid : psDot; y = (int)(double(i + 1) * double(YB - YT)/8.0 + YT); tp->MoveTo(XL, y); tp->LineTo(XR, y); } for( i = 1; i < 5; i++ ){ y = (int)(double(i) * double(YB - YT)/4.0 + YT); sprintf( bf, "-%2u", (80 / 4)*i ); ::SetBkMode(tp->Handle, TRANSPARENT); tp->TextOut(XL - 6 - tp->TextWidth(bf), y - (tp->TextHeight(bf)/2), bf); } strcpy(bf, "dB"); tp->TextOut(XL - 6 - tp->TextWidth(bf), YT-(tp->TextHeight(bf)/2), bf); for( i = 1; i <= DM; i++ ){ tp->Pen->Style = (i % MM) ? psDot : psSolid; x = (int)(double(i) * double(XR - XL)/double(DM+1) + XL); tp->MoveTo(x, YT); tp->LineTo(x, YB); } for( i = 0; i <= LM; i++ ){ x = (int)(double(i) * double(XR - XL)/double(LM) + XL); sprintf(bf, "%4.0lf", (max*i)/LM); ::SetBkMode(tp->Handle, TRANSPARENT); tp->TextOut(x - (tp->TextWidth(bf)/2), YB + 6, bf); } tp->Pen->Color = clRed; tp->Pen->Style = psDot; x = (int)(XL + (fs/2) * (double(XR-XL)/max)); tp->MoveTo(x, YT); tp->LineTo(x, YB); tp->Pen->Color = clBlue; tp->Pen->Style = psSolid; } int ay = 0; double ra, im; pi2t = 2.0 * PI / fs; tp->Pen->Color = col; for( x = XL, f = 0.0; x < XR; x++, f += (max/double(XR-XL)) ){ if( Tap ){ ra = im = 0.0; for( k = 0; k <= Tap; k++ ){ ra += H[k] * cos(pi2t*f*k); if( k ) im -= H[k] * sin(pi2t*f*k); } if( ra * im ){ g = sqrt(ra * ra + im * im); } else { g = 0.0; } } else { g = 1.0; } if( g == 0 ) g = 1.0e-38; gdb = 20*0.4342944*log(fabs(g)) + 80.0; if( gdb < 0.0 ) gdb = 0.0; gdb = (gdb * double(YB-YT))/80.0; y = YB - (int)gdb; if( x == XL ){ tp->MoveTo(x, y); tp->LineTo(x, y); } else { tp->MoveTo(x-1, ay); tp->LineTo(x, y); } ay = y; } } //--------------------------------------------------------------------- // 周波数特性グラフ(フィルタスレッド内でコールしてはいけない) // // void DrawGraphIIR(Graphics::TBitmap *pBitmap, double a0, double a1, double a2, double b1, double b2, int Over, int &nmax, int init, TColor col) { int x, y; double f, gdb, g, pi2t, pi4t, fs; double max; char bf[80]; TCanvas *tp = pBitmap->Canvas; TRect rc; rc.Left = 0; rc.Right = pBitmap->Width; rc.Top = 0; rc.Bottom = pBitmap->Height; if( init ){ tp->Brush->Color = clWhite; tp->FillRect(rc); } int LM; // 周波数表示のあるライン数 int DM; // 内部線の数 int MM; // 実線の間隔 switch(Over){ case 2: max = 3000; fs = SampFreq/2.0; break; case 3: max = 2000; fs = SampFreq/3.0; break; default: max = 4000; fs = SampFreq; break; } if( nmax ){ max = nmax; } else { nmax = max; } switch(nmax){ case 3000: LM = 3; DM = 14; MM = 5; break; case 100: case 200: case 2000: LM = 4; DM = 19; MM = 5; break; case 400: case 800: case 4000: LM = 4; DM = 19; MM = 5; break; default: // 6000 LM = 3; DM = 11; MM = 4; break; } int XL = 32; int XR = pBitmap->Width - 16; int YT = 16; int YB = pBitmap->Height - 24; int i; if( init ){ tp->Pen->Color = clBlack; tp->Font->Size = 8; tp->MoveTo(XL, YT); tp->LineTo(XR, YT); tp->LineTo(XR, YB); tp->LineTo(XL, YB); tp->LineTo(XL, YT); tp->Pen->Color = clGray; for( i = 0; i < 5; i++ ){ tp->Pen->Style = (i & 1) ? psSolid : psDot; y = (int)(double(i + 1) * double(YB - YT)/6.0 + YT); tp->MoveTo(XL, y); tp->LineTo(XR, y); } for( i = 1; i < 4; i++ ){ y = (int)(double(i) * double(YB - YT)/3.0 + YT); sprintf( bf, "-%2u", (60 / 3)*i ); ::SetBkMode(tp->Handle, TRANSPARENT); tp->TextOut(XL - 6 - tp->TextWidth(bf), y - (tp->TextHeight(bf)/2), bf); } strcpy(bf, "dB"); tp->TextOut(XL - 6 - tp->TextWidth(bf), YT-(tp->TextHeight(bf)/2), bf); for( i = 1; i <= DM; i++ ){ tp->Pen->Style = (i % MM) ? psDot : psSolid; x = (int)(double(i) * double(XR - XL)/double(DM+1) + XL); tp->MoveTo(x, YT); tp->LineTo(x, YB); } for( i = 0; i <= LM; i++ ){ x = (int)(double(i) * double(XR - XL)/double(LM) + XL); sprintf(bf, "%4.0lf", (max*i)/LM); ::SetBkMode(tp->Handle, TRANSPARENT); tp->TextOut(x - (tp->TextWidth(bf)/2), YB + 6, bf); } tp->Pen->Color = clRed; tp->Pen->Style = psDot; x = (int)(XL + (fs/2) * (double(XR-XL)/max)); tp->MoveTo(x, YT); tp->LineTo(x, YB); tp->Pen->Color = clBlue; tp->Pen->Style = psSolid; } int ay = 0; pi2t = 2.0 * PI / fs; pi4t = 2.0 * pi2t; tp->Pen->Color = col; double A, B, C, D, P, R; double cosw, sinw, cos2w, sin2w; for( x = XL, f = 0.0; x < XR; x++, f += (max/double(XR-XL)) ){ cosw = cos(pi2t*f); sinw = sin(pi2t*f); cos2w = cos(pi4t*f); sin2w = sin(pi4t*f); A = a0 + a1 * cosw + a2 * cos2w; B = 1 + b1 * cosw + b2 * cos2w; C = a1 * sinw + a2 * sin2w; D = b1 * sinw + b2 * sin2w; P = A*A + C*C; R = B*B + D*D; g = sqrt(P/R); if( g == 0 ) g = 1.0e-38; gdb = 20*0.4342944*log(fabs(g)) + 60.0; if( gdb < 0.0 ) gdb = 0.0; gdb = (gdb * double(YB-YT))/60.0; y = YB - (int)gdb; if( x == XL ){ tp->MoveTo(x, y); tp->LineTo(x, y); } else { tp->MoveTo(x-1, ay); tp->LineTo(x, y); } ay = y; } } //--------------------------------------------------------------------- // 周波数特性グラフ(フィルタスレッド内でコールしてはいけない) // // void DrawGraphIIR(Graphics::TBitmap *pBitmap, CIIR *ip, int Over, int &nmax, int init, TColor col) { int x, y; double f, gdb, g, pi2t, pi4t, fs; double max; char bf[80]; TCanvas *tp = pBitmap->Canvas; TRect rc; rc.Left = 0; rc.Right = pBitmap->Width; rc.Top = 0; rc.Bottom = pBitmap->Height; if( init ){ tp->Brush->Color = clWhite; tp->FillRect(rc); } int LM; // 周波数表示のあるライン数 int DM; // 内部線の数 int MM; // 実線の間隔 switch(Over){ case 2: max = 3000; fs = SampFreq/2.0; break; case 3: max = 2000; fs = SampFreq/3.0; break; default: max = 4000; fs = SampFreq; break; } if( nmax ){ max = nmax; } else { nmax = max; } switch(nmax){ case 3000: LM = 3; DM = 14; MM = 5; break; case 100: case 200: case 2000: LM = 4; DM = 19; MM = 5; break; case 400: case 800: case 4000: LM = 4; DM = 19; MM = 5; break; default: // 6000 LM = 3; DM = 11; MM = 4; break; } int XL = 32; int XR = pBitmap->Width - 16; int YT = 16; int YB = pBitmap->Height - 24; int i; if( init ){ tp->Pen->Color = clBlack; tp->Font->Size = 8; tp->MoveTo(XL, YT); tp->LineTo(XR, YT); tp->LineTo(XR, YB); tp->LineTo(XL, YB); tp->LineTo(XL, YT); tp->Pen->Color = clGray; for( i = 0; i < 5; i++ ){ tp->Pen->Style = (i & 1) ? psSolid : psDot; y = (int)(double(i + 1) * double(YB - YT)/6.0 + YT); tp->MoveTo(XL, y); tp->LineTo(XR, y); } for( i = 1; i < 4; i++ ){ y = (int)(double(i) * double(YB - YT)/3.0 + YT); sprintf( bf, "-%2u", (60 / 3)*i ); ::SetBkMode(tp->Handle, TRANSPARENT); tp->TextOut(XL - 6 - tp->TextWidth(bf), y - (tp->TextHeight(bf)/2), bf); } strcpy(bf, "dB"); tp->TextOut(XL - 6 - tp->TextWidth(bf), YT-(tp->TextHeight(bf)/2), bf); for( i = 1; i <= DM; i++ ){ tp->Pen->Style = (i % MM) ? psDot : psSolid; x = (int)(double(i) * double(XR - XL)/double(DM+1) + XL); tp->MoveTo(x, YT); tp->LineTo(x, YB); } for( i = 0; i <= LM; i++ ){ x = (int)(double(i) * double(XR - XL)/double(LM) + XL); sprintf(bf, "%4.0lf", (max*i)/LM); ::SetBkMode(tp->Handle, TRANSPARENT); tp->TextOut(x - (tp->TextWidth(bf)/2), YB + 6, bf); } tp->Pen->Color = clRed; tp->Pen->Style = psDot; x = (int)(XL + (fs/2) * (double(XR-XL)/max)); tp->MoveTo(x, YT); tp->LineTo(x, YB); tp->Pen->Color = clBlue; tp->Pen->Style = psSolid; } int ay = 0; pi2t = 2.0 * PI / fs; pi4t = 2.0 * pi2t; tp->Pen->Color = col; double A, B, C, D, P, R; double cosw, sinw, cos2w, sin2w; for( x = XL, f = 0.0; x < XR; x++, f += (max/double(XR-XL)) ){ cosw = cos(pi2t*f); sinw = sin(pi2t*f); cos2w = cos(pi4t*f); sin2w = sin(pi4t*f); g = 1.0; double *ap = ip->A; double *bp = ip->B; for( i = 0; i < ip->m_order/2; i++, ap += 3, bp += 2 ){ /* A = a0 + a1 * cosw + a2 * cos2w; B = 1 + b1 * cosw + b2 * cos2w; C = a1 * sinw + a2 * sin2w; D = b1 * sinw + b2 * sin2w; */ A = bp[0] + bp[1] * cosw + bp[0] * cos2w; B = 1 + -ap[1] * cosw + -ap[2] * cos2w; C = bp[1] * sinw + bp[0] * sin2w; D = -ap[1] * sinw + -ap[2] * sin2w; P = A*A + C*C; R = B*B + D*D; g *= sqrt(P/R); } if( ip->m_order & 1 ){ A = bp[0] + bp[1] * cosw; B = 1 + -ap[1] * cosw; C = bp[1] * sinw; D = -ap[1] * sinw; P = A*A + C*C; R = B*B + D*D; g *= sqrt(P/R); } if( g == 0 ) g = 1.0e-38; gdb = 20*0.4342944*log(fabs(g)) + 60.0; if( gdb < 0.0 ) gdb = 0.0; gdb = (gdb * double(YB-YT))/60.0; y = YB - (int)gdb; if( x == XL ){ tp->MoveTo(x, y); tp->LineTo(x, y); } else { tp->MoveTo(x-1, ay); tp->LineTo(x, y); } ay = y; } } double asinh(double x) { return log(x + sqrt(x*x+1.0)); } //------------------------------------------------------------------ // bc : 0-バターワース, 1-チェビシフ // rp : 通過域のリップル void MakeIIR(double *A, double *B, double fc, double fs, int order, int bc, double rp) { double w0, wa, u, zt, x; int j, n; if( bc ){ // チェビシフ u = 1.0/double(order) * asinh(1.0/sqrt(pow(10.0,0.1*rp)-1.0)); } wa = tan(PI*fc/fs); w0 = 1.0; n = (order & 1) + 1; double *pA = A; double *pB = B; double d1, d2; for( j = 1; j <= order/2; j++, pA+=3, pB+=2 ){ if( bc ){ // チェビシフ d1 = sinh(u)*cos(n*PI/(2*order)); d2 = cosh(u)*sin(n*PI/(2*order)); w0 = sqrt(d1 * d1 + d2 * d2); zt = sinh(u)*cos(n*PI/(2*order))/w0; } else { // バターワース w0 = 1.0; zt = cos(n*PI/(2*order)); } pA[0] = 1 + wa*w0*2*zt + wa*w0*wa*w0; pA[1] = -2 * (wa*w0*wa*w0 - 1)/pA[0]; pA[2] = -(1.0 - wa*w0*2*zt + wa*w0*wa*w0)/pA[0]; pB[0] = wa*w0*wa*w0 / pA[0]; pB[1] = 2*pB[0]; n += 2; } if( bc && !(order & 1) ){ x = pow( 1.0/pow(10.0,rp/20.0), 1/double(order/2) ); pB = B; for( j = 1; j <= order/2; j++, pB+=2 ){ pB[0] *= x; pB[1] *= x; } } if( order & 1 ){ if( bc ) w0 = sinh(u); j = (order / 2); pA = A + (j*3); pB = B + (j*2); pA[0] = 1 + wa*w0; pA[1] = -(wa*w0 - 1)/pA[0]; pB[0] = wa*w0/pA[0]; pB[1] = pB[0]; } } //--------------------------------------------------------------------------- CIIR::CIIR() { m_order = 0; A = new double[IIRMAX*3]; B = new double[IIRMAX*2]; Z = new double[IIRMAX*2]; memset(A, 0, sizeof(double[IIRMAX*3])); memset(B, 0, sizeof(double[IIRMAX*2])); memset(Z, 0, sizeof(double[IIRMAX*2])); } CIIR::~CIIR() { if( A != NULL ) delete A; if( B != NULL ) delete B; if( Z != NULL ) delete Z; } void CIIR::Clear(void) { memset(Z, 0, sizeof(double[IIRMAX*2])); } void CIIR::MakeIIR(double fc, double fs, int order, int bc, double rp) { m_order = order; m_bc = bc; m_rp = rp; ::MakeIIR(A, B, fc, fs, order, bc, rp); } double CIIR::Do(double d) { double *pA = A; double *pB = B; double *pZ = Z; double o; for( int i = 0; i < m_order/2; i++, pA+=3, pB+=2, pZ+=2 ){ d += pZ[0] * pA[1] + pZ[1] * pA[2]; o = d * pB[0] + pZ[0] * pB[1] + pZ[1] * pB[0]; pZ[1] = pZ[0]; if( fabs(d) < 1e-37 ) d = 0.0; pZ[0] = d; d = o; } if( m_order & 1 ){ d += pZ[0] * pA[1]; o = d * pB[0] + pZ[0] * pB[0]; if( fabs(d) < 1e-37 ) d = 0.0; pZ[0] = d; d = o; } return d; } //--------------------------------------------------------------------------- // CFIR2クラス CFIR2::CFIR2() { m_pZ = NULL; m_pH = NULL; m_pZP = NULL; m_W = 0; m_Tap = 0; } //--------------------------------------------------------------------------- CFIR2::~CFIR2() { if( m_pZ ) delete m_pZ; if( m_pH ) delete m_pH; } //--------------------------------------------------------------------------- void __fastcall CFIR2::Create(int tap) { if( !tap ){ if( m_pZ ) delete m_pZ; m_pZ = NULL; } else if( (m_Tap != tap) || !m_pZ ){ if( m_pZ ) delete m_pZ; m_pZ = new double[(tap+1)*2]; memset(m_pZ, 0, sizeof(double)*(tap+1)*2); m_W = 0; } m_Tap = tap; m_TapHalf = tap/2; } //--------------------------------------------------------------------------- void __fastcall CFIR2::Create(int tap, int type, double fs, double fcl, double fch, double att, double gain) { if( (m_Tap != tap) || !m_pZ || !m_pH ){ if( m_pZ ) delete m_pZ; m_pZ = new double[(tap+1)*2]; memset(m_pZ, 0, sizeof(double)*(tap+1)*2); if( m_pH ) delete m_pH; m_pH = new double[tap+1]; m_W = 0; } m_Tap = tap; m_TapHalf = tap/2; ::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain); } //--------------------------------------------------------------------------- void __fastcall CFIR2::Clear(void) { if( m_pZ ) memset(m_pZ, 0, sizeof(double)*(m_Tap+1)*2); } //--------------------------------------------------------------------------- double __fastcall CFIR2::Do(double d) { double *dp1 = &m_pZ[m_W+m_Tap+1]; m_pZP = dp1; *dp1 = d; m_pZ[m_W] = d; d = 0; double *hp = m_pH; for( int i = 0; i <= m_Tap; i++ ){ d += (*dp1--) * (*hp++); } m_W++; if( m_W > m_Tap ) m_W = 0; return d; } //--------------------------------------------------------------------------- double __fastcall CFIR2::Do(double d, double *hp) { double *dp1 = &m_pZ[m_W+m_Tap+1]; m_pZP = dp1; *dp1 = d; m_pZ[m_W] = d; d = 0; for( int i = 0; i <= m_Tap; i++ ){ d += (*dp1--) * (*hp++); } m_W++; if( m_W > m_Tap ) m_W = 0; return d; } //--------------------------------------------------------------------------- double __fastcall CFIR2::Do(double *hp) { double d = 0; double *dp = m_pZP; for( int i = 0; i <= m_Tap; i++ ){ d += (*dp--) * (*hp++); } return d; } //--------------------------------------------------------------------------- void __fastcall CFIR2::Do(double &d, double &j, double *hp) { double *dp1 = &m_pZ[m_W+m_Tap+1]; m_pZP = dp1; *dp1 = d; m_pZ[m_W] = d; double dd = 0; for( int i = 0; i <= m_Tap; i++ ){ dd += (*dp1--) * (*hp++); } j = dd; d= m_pZ[m_W+m_TapHalf+1]; m_W++; if( m_W > m_Tap ) m_W = 0; }