//Copyright+LGPL //----------------------------------------------------------------------------------------------------------------------------------------------- // Copyright 2000-2013 Makoto Mori, Nobuyuki Oba //----------------------------------------------------------------------------------------------------------------------------------------------- // This file is part of MMTTY. // MMTTY 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. // MMTTY 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 #pragma hdrstop #include "Rtty.h" #define LOGFFT FALSE CSinTable g_SinTable; //--------------------------------------------------------------------------- // CSinTableクラス // Added by JE3HHT on Aug.2010 __fastcall CSinTable::CSinTable() { m_Size = 48000; m_tSin = new double[m_Size]; double pi2t = 2 * PI / double(m_Size); for( int i = 0; i < m_Size; i++ ){ m_tSin[i] = sin(double(i) * pi2t); } } //--------------------------------------------------------------------------- __fastcall CSinTable::~CSinTable() { delete[] m_tSin; } //--------------------------------------------------------------------------- CTICK::CTICK() { ptbl[0] = new int[12500]; ptbl[1] = new int[12500]; memset(ptbl[0], 0, sizeof(int[12500])); memset(ptbl[1], 0, sizeof(int[12500])); } CTICK::~CTICK() { delete[] ptbl[0]; //JA7UDE 0428 delete[] ptbl[1]; //JA7UDE 0428 } void CTICK::Init(void) { m_wsel = 0; m_wp = ptbl[0]; m_wcnt = 0; m_Trig = 0; } void CTICK::Write(double d) { *m_wp = int(d); m_wp++; m_wcnt++; if( m_wcnt >= m_Samp ){ m_wcnt = 0; m_wsel++; m_wsel &= 1; m_wp = ptbl[m_wsel]; m_Trig = 1; } } int *CTICK::GetData(void) { if( !m_Trig ) return NULL; m_Trig = 0; int sel = m_wsel + 1; sel &= 1; return ptbl[sel]; } //--------------------------------------------------------------------------- // VCOクラス CVCO::CVCO() { m_vlock = 0; m_SampleFreq = SampFreq; m_FreeFreq = 1900.0; m_TableSize = int(SampFreq*2); pSinTbl = new double[m_TableSize]; m_c1 = m_TableSize/16.0; m_c2 = int( double(m_TableSize) * m_FreeFreq / m_SampleFreq ); m_z = 0; double pi2t = 2 * PI / double(m_TableSize); for( int i = 0; i < m_TableSize; i++ ){ pSinTbl[i] = sin(double(i) * pi2t); } } CVCO::~CVCO() { if( m_vlock ) ::VirtualUnlock(pSinTbl, sizeof(double)*m_TableSize); delete[] pSinTbl; } void CVCO::SetGain(double gain) { m_c1 = double(m_TableSize) * gain / m_SampleFreq; } void CVCO::VirtualLock(void) { if( !m_vlock ){ ::VirtualLock(pSinTbl, sizeof(double)*m_TableSize); m_vlock = 1; } } void CVCO::SetSampleFreq(double f) { m_SampleFreq = f; int size = int(m_SampleFreq*2); if( m_TableSize != size ){ if( pSinTbl != NULL ){ if( m_vlock ) ::VirtualUnlock(pSinTbl, sizeof(double)*m_TableSize); delete[] pSinTbl; } m_TableSize = size; pSinTbl = new double[m_TableSize]; if( m_vlock ) ::VirtualLock(pSinTbl, sizeof(double)*m_TableSize); double pi2t = 2 * PI / double(m_TableSize); for( int i = 0; i < m_TableSize; i++ ){ pSinTbl[i] = sin(double(i) * pi2t); } } SetFreeFreq(m_FreeFreq); } void CVCO::SetFreeFreq(double f) { m_FreeFreq = f; m_c2 = double(m_TableSize) * m_FreeFreq / m_SampleFreq; } void CVCO::InitPhase(void) { m_z = 0; } double CVCO::Do(double d) { // -1 to 1 m_z += (d * m_c1 + m_c2) + 0.5; while( m_z >= m_TableSize ){ m_z -= m_TableSize; } while( m_z < 0 ){ m_z += m_TableSize; } return pSinTbl[int(m_z)]; } //--------------------------------------------------------------------------- // VCOXクラス __fastcall CVCOX::CVCOX() { m_SampleFreq = SampFreq; m_FreeFreq = 2000.0; m_TableSize = g_SinTable.m_Size; m_TableCOS = m_TableSize / 4; m_c1 = 0.0; m_c2 = double(m_TableSize) * m_FreeFreq / m_SampleFreq; m_z = 0.0; } __fastcall CVCOX::~CVCOX() { } void __fastcall CVCOX::SetGain(double gain) { m_c1 = double(m_TableSize) * gain / m_SampleFreq; } void __fastcall CVCOX::SetSampleFreq(double f) { m_SampleFreq = f; SetFreeFreq(m_FreeFreq); } void __fastcall CVCOX::SetFreeFreq(double f) { m_FreeFreq = f; m_c2 = double(m_TableSize) * m_FreeFreq / m_SampleFreq; if( f < 1.0 ) m_z = 0; } void __fastcall CVCOX::InitPhase(void) { m_z = 0.0; } //------------------------------------------------------------------ double __fastcall CVCOX::Do(void) { m_z += m_c2; if( m_z >= m_TableSize ){ m_z -= m_TableSize; } if( m_z < 0 ){ m_z += m_TableSize; } return g_SinTable.m_tSin[int(m_z)]; } //------------------------------------------------------------------ double __fastcall CVCOX::Do(double d) { // -1 to 1 m_z += (d * m_c1 + m_c2); while( m_z >= m_TableSize ){ m_z -= m_TableSize; } while( m_z < 0 ){ m_z += m_TableSize; } return g_SinTable.m_tSin[int(m_z)]; } //------------------------------------------------------------------ double __fastcall CVCOX::DoCos(void) { double z = m_z + m_TableCOS; if(z >= m_TableSize ) z -= m_TableSize; return g_SinTable.m_tSin[int(z)]; } //--------------------------------------------------------------------------- // CFSKMODクラス CFSKMOD::CFSKMOD() { m_SampFreq = sys.m_SampFreq + sys.m_TxOffset; vco.SetSampleFreq(m_SampFreq); memset(ZBPF, 0, sizeof(ZBPF)); memset(HBPF, 0, sizeof(HBPF)); m_bpftap = 48; m_rp = 0; m_wp = 0; m_cnt = 0; m_BitLen = 5; m_StopLen = 4; // 0-1bit, 1-1.5bit, 2-2bit, 3-1.5bit, 4-1.5bit m_Parity = 0; m_SumParity = 0; m_Data = 0; m_DataCount = 0; m_mode = 0; m_inv = 0; m_diddle = 2; m_fig = 0; m_figout = 0; SetBaudRate(45.45); SetOutputGain(24576.0); m_MarkFreq = 2125; m_SpaceFreq = 2295; SetMarkFreq(2125); SetSpaceFreq(2295); m_out = 1; m_bpf = 1; SetLPFFreq(100.0); m_lpf = 0; m_CharWaitCount = 0; m_CharWait = 0; m_DiddleWait = 0; m_CharWaitDiddle = 0; m_idle = 1; pDem = NULL; m_RandomDiddle = 0; m_WaitTimer = 0; m_WaitTimerCount = 0; m_DisDiddle = 0; m_AmpVal = 0; } void CFSKMOD::CalcBPF(void) { MakeFilter(HBPF, m_bpftap, ffBPF, SampFreq, m_MarkFreq - 150, m_SpaceFreq + 150, 60, 1.0); } void CFSKMOD::SetMarkFreq(double d) { m_MarkFreq = d; vco.SetFreeFreq(m_SpaceFreq); vco.SetGain(m_MarkFreq - m_SpaceFreq); CalcBPF(); } void CFSKMOD::SetSpaceFreq(double d) { m_SpaceFreq = d; vco.SetFreeFreq(m_SpaceFreq); vco.SetGain(m_MarkFreq - m_SpaceFreq); CalcBPF(); } void CFSKMOD::SetSampFreq(double f) { m_SampFreq = sys.m_SampFreq + sys.m_TxOffset; vco.SetSampleFreq(m_SampFreq); SetBaudRate(m_BaudRate); SetLPFFreq(m_LPFFreq); } void CFSKMOD::SetBaudRate(double b) { if( b >= 1.0 ){ m_BaudRate = b; m_Count = m_ReCount = int(m_SampFreq/b + 0.5); m_Amp.SetMax(m_Count); } } void CFSKMOD::SetLPFFreq(double f) { m_LPFFreq = f; avgLPF.SetCount(int(m_SampFreq/f + 0.5)); } void CFSKMOD::PutData(int d) { if( m_cnt < MODBUFMAX ){ m_idle = 0; m_Buff[m_wp] = BYTE(d); m_wp++; if( m_wp >= MODBUFMAX ) m_wp = 0; m_cnt++; } } void CFSKMOD::OutTone(int sw, int bsize) { if( sw ){ m_out = 1; m_Count = m_ReCount/2; } else { m_out = -1; m_Count = m_ReCount * (1 + ((220 * bsize)/(m_SampFreq))); } } double CFSKMOD::Do(int echo){ if( m_CharWaitDiddle && m_CharWaitCount ){ m_CharWaitCount--; } if( m_DisDiddle > 0 ) m_DisDiddle--; if( sys.m_TxPort && m_FSKCount ) m_FSKCount--; if( !m_Count ){ m_Count = m_ReCount; switch(m_mode){ case 0: // スタートビット出力 if( sys.m_TxPort == txTXD ) FSKDeff = m_cnt - FSKCount; if( !m_CharWaitDiddle ){ if( m_CharWaitCount ){ m_CharWaitCount--; m_out = 1; m_Count = 1; break; } else if( m_CharWait && m_cnt ){ m_CharWaitCount = m_CharWait * m_ReCount/3; } } _try:; if( m_cnt && ((!m_CharWaitDiddle) || (!m_CharWaitCount)) && ((sys.m_TxPort != txTXD) || (FSKCount <= m_cnt) || (m_FSKCount) || (m_Buff[m_rp]==0xff) || (m_Buff[m_rp]==0xfe) ) ){ m_WaitTimerCount = 4; m_idle = 0; m_out = 0; if( m_figout && (m_fig == 0x1b) && (m_Buff[m_rp]!=0x1f) ){ m_Data = 0x1b; if( !echo ){ pDem->WriteData(m_Data); } } else { if( sys.m_TxPort == txTXDOnly ){ // FSK Only時の同期 #if 0 while( FSKCount1 == FSKCount2 ){ ::Sleep(10); } #endif FSKCount2++; } m_Data = m_Buff[m_rp]; if( m_Data == 0xff ){ // マーク信号送信 m_out = 1; m_Count = m_ReCount * 3; m_cnt--; m_rp++; if( m_rp >= MODBUFMAX ) m_rp = 0; m_CharWaitCount = 0; break; } else if( m_Data == 0xfe ){ // キャリア切断 m_out = -1; m_Count = m_ReCount * 3; m_cnt--; m_rp++; if( m_rp >= MODBUFMAX ) m_rp = 0; m_CharWaitCount = 0; break; } else if( m_Data == 0xfd ){ // Dis Diddle m_DisDiddle = -1; m_cnt--; m_rp++; if( m_rp >= MODBUFMAX ) m_rp = 0; goto _try; } else if( m_Data == 0xfc ){ // Enb Diddle m_DisDiddle = 0; m_cnt--; m_rp++; if( m_rp >= MODBUFMAX ) m_rp = 0; goto _try; } else if( (m_Data == 0x1b)||(m_Data == 0x1f) ){ m_fig = m_Data; } m_cnt--; m_rp++; if( m_rp >= MODBUFMAX ) m_rp = 0; if( !echo ){ pDem->WriteData(m_Data); } } m_figout = 0; m_DataCount = m_BitLen; m_SumParity = 0; m_mode++; } else if( m_Data == 0x00fe ){ m_idle = 1; m_out = -1; m_Count = m_ReCount * 50; m_Data = 0; break; } else if( (m_BitLen < 6) && ((m_diddle && !m_DisDiddle) || ((sys.m_TxPort == txTXD)&& m_cnt)) ){ // else if( m_diddle && (!m_DisDiddle || ((sys.m_TxPort == txTXD)&& m_cnt) ) ){ // else if( m_diddle && !m_DisDiddle ){ #if 0 if( sys.m_TxPort == txTXDOnly ){ ::Sleep((m_ReCount * m_BitLen)*1000/m_SampFreq); } #endif if( !m_cnt ) m_idle = 1; m_out = 0; switch(m_diddle){ case 1: // BLK if( m_RandomDiddle && !(rand() & 3) ){ m_Data = 0x1f; if( m_BitLen <= 6 ) m_figout = 1; } else { m_Data = 0x00; } break; default: // LTR if( m_RandomDiddle && !(rand() & 3) ){ m_Data = 0x00; } else { m_Data = 0x1f; if( m_BitLen <= 6 ) m_figout = 1; } break; } m_DataCount = m_BitLen; m_SumParity = 0; m_mode++; if( !m_CharWaitDiddle ){ if( (sys.m_LWait == 2) || m_cnt ){ m_CharWaitCount = m_CharWait * m_ReCount/3; } else if( m_DiddleWait ){ m_CharWaitCount = m_DiddleWait * m_ReCount/3; } else { m_CharWaitCount = 0; } if( sys.m_LWait != 2 ){ if( m_WaitTimer ){ if( !m_WaitTimerCount ){ m_CharWaitCount = 0; } else { m_WaitTimerCount--; } } } } } else { if( !m_cnt ) m_idle = 1; m_out = 1; m_Count = 1; #if 0 if( sys.m_TxPort == txTXDOnly ){ ::Sleep(11); m_Count = m_ReCount; } #endif } if( m_CharWaitDiddle && (!m_CharWaitCount) ){ if( m_Data != 0x1b ){ m_CharWaitCount = m_CharWait * m_ReCount/3; } } break; case 1: // 符号出力 if( m_DataCount ){ switch(m_BitLen){ case 6: m_out = (m_Data & 0x20) ? 1 : 0; break; case 7: m_out = (m_Data & 0x40) ? 1 : 0; break; case 8: m_out = (m_Data & 0x80) ? 1 : 0; break; default: m_out = (m_Data & 0x10) ? 1 : 0; break; } m_Data = BYTE(m_Data << 1); m_DataCount--; if( m_out ) m_SumParity++; } else { // ストップビット if( m_Parity ){ m_mode++; switch(m_Parity){ case 1: // Even m_out = m_SumParity & 1 ? 0 : 1; break; case 2: // Odd m_out = m_SumParity & 1 ? 1 : 0; break; case 3: m_out = 1; break; case 4: m_out = 0; break; } } else { m_mode++; goto _nx; } } break; case 2: _nx:; m_out = 1; m_mode++; switch(m_StopLen){ case 0: // 1bit m_Count = 1; break; case 1: // 1.5bit case 3: case 4: m_Count = (m_ReCount/2) - 1; break; case 2: // 2bit m_Count = m_ReCount - 1; break; } break; case 3: // ストップビット終了 m_mode = 0; break; } } m_Count--; double d; if( m_lpf ){ // GMSK if( m_inv ){ d = m_out ? 0 : 1; } else { d = m_out; } d = avgLPF.Avg(d); d = vco.Do(d) * m_OutputGain; } else { // AFSK if( m_inv ){ d = vco.Do(m_out ? 0 : 1) * m_OutputGain; } else { d = vco.Do(m_out) * m_OutputGain; } } if( m_out < 0 ) d = 0; if( m_bpf ){ d = DoFIR(HBPF, ZBPF, d, m_bpftap); } return d * m_Amp.Do(m_AmpVal); } //--------------------------------------------------------------------------- // CFSKDEMクラス CFSKDEM::CFSKDEM() { m_OverFlow = 0; m_lpf = 0; m_lpfOrder = 5; SetLPFFreq(40.0); m_pll.SetSampleFreq(DemSamp); m_Phase.SetSampleFreq(DemSamp); memset(ZMark, 0, sizeof(ZMark)); memset(ZSpace, 0, sizeof(ZSpace)); memset(HMark, 0, sizeof(HMark)); memset(HSpace, 0, sizeof(HSpace)); i2 = 0; // o1 = o2 = 0; Count = 0; SetSmoozFreq(70.0); avgMark.SetCount(m_Smooz); avgSpace.SetCount(m_Smooz); m_BitLen = 5; m_StopLen = 4; // 0-1bit, 1-1.5bit, 2-2bit, 3-1bit, 4-1.42bit m_Parity = 0; m_SumParity = 0; m_mode = 0; m_DataCount = 0; m_inv = 0; m_sq = 0; m_SQLevel = 600.0; m_Tap = 72; m_FilWidth = GetFilWidth(m_Tap); m_wp = 0; m_rp = 0; m_BufCount = 0; SetBaudRate(45.45); m_MarkFreq = 2125; m_SpaceFreq = 2295; SetMarkFreq(2125); SetSpaceFreq(2295); m_dMark = 0; m_dSpace = 0; m_Scope = 0; m_majority = 1; m_ignoreFream = 0; m_XYScope = 0; SetIIR(60.0); m_Limit = 1; m_LimitGain = 10.0; m_deff = 0; m_avgdeff = 0; m_sqcount = 0; // SmoozSQ.SetCount(4); SmoozSQ.SetCount(8); m_LimitOverSampling = 0; m_Tick = 0; m_atcPLL.m_Max = 12; m_LimitAGC = 1; m_limitMax = 1; m_limitMin = -1; m_d = 0; } void CFSKDEM::SetIIR(double bw) { m_iirfw = bw; m_iirm.SetFreq(m_AFCMarkFreq, DemSamp, m_iirfw); m_iirs.SetFreq(m_AFCSpaceFreq, DemSamp, m_iirfw); m_pll.SetFreeFreq(m_AFCMarkFreq, m_AFCSpaceFreq); } void CFSKDEM::SetBaudRate(double b) { if( b >= 1.0 ){ m_BaudRate = b; m_Count = m_ReCount = int(DemSamp/b + 0.5); } } void CFSKDEM::SetSmoozFreq(double f) { m_SmoozFreq = f; m_Smooz = int(DemSamp / f + 0.5); avgMark.SetCount(m_Smooz); avgSpace.SetCount(m_Smooz); } void CFSKDEM::SetLPFFreq(double f) { m_lpffreq = f; LpfMark.MakeIIR(f, DemSamp, m_lpfOrder, 0, 1.0); LpfSpace.MakeIIR(f, DemSamp, m_lpfOrder, 0, 1.0); } void CFSKDEM::SetMarkFreq(double d) { m_SetMarkFreq = m_AFCMarkFreq = m_MarkFreq = d; MakeFilter(HMark, m_Tap, ffBPF, DemSamp, m_MarkFreq-m_FilWidth, m_MarkFreq+m_FilWidth, 60, 1.0); SetIIR(m_iirfw); m_Phase.SetCarrierFreq(m_AFCMarkFreq); if( m_AFCSpaceFreq > m_AFCMarkFreq ) m_Phase.SetShift(m_AFCSpaceFreq - m_AFCMarkFreq); m_AA6YQ.SetMarkFreq(m_AFCMarkFreq); } void CFSKDEM::SetSpaceFreq(double d) { m_SetSpaceFreq = m_AFCSpaceFreq = m_SpaceFreq = d; MakeFilter(HSpace, m_Tap, ffBPF, DemSamp, m_SpaceFreq-m_FilWidth, m_SpaceFreq+m_FilWidth, 60, 1.0); SetIIR(m_iirfw); m_Phase.SetCarrierFreq(m_AFCMarkFreq); if( m_AFCSpaceFreq > m_AFCMarkFreq ) m_Phase.SetShift(m_AFCSpaceFreq - m_AFCMarkFreq); m_AA6YQ.SetSpaceFreq(m_AFCSpaceFreq); } void CFSKDEM::AFCMarkFreq(double d) { if( d != m_MarkFreq ){ m_MarkFreq = d; if( fabs(d - m_AFCMarkFreq) >= (m_type ? 10.0 : 5.0) ){ m_AFCMarkFreq = d; MakeFilter(HMark, m_Tap, ffBPF, DemSamp, m_MarkFreq-m_FilWidth, m_MarkFreq+m_FilWidth, 60, 1.0); SetIIR(m_iirfw); m_Phase.SetCarrierFreq(m_AFCMarkFreq); } m_AA6YQ.SetMarkFreqByAFC(d); } } void CFSKDEM::AFCSpaceFreq(double d) { if( d != m_SpaceFreq ){ m_SpaceFreq = d; if( fabs(d - m_AFCSpaceFreq) >= (m_type ? 10.0 : 5.0) ){ m_AFCSpaceFreq = d; MakeFilter(HSpace, m_Tap, ffBPF, DemSamp, m_SpaceFreq-m_FilWidth, m_SpaceFreq+m_FilWidth, 60, 1.0); SetIIR(m_iirfw); } m_AA6YQ.SetSpaceFreqByAFC(d); } } double CFSKDEM::GetFilWidth(int tap) { double Width; if( tap >= 256 ){ Width = 20; } else if( tap >= 192 ){ Width = 30; } else { Width = 40; } return Width; } void CFSKDEM::SetFilterTap(int tap) { if( tap != m_Tap ){ m_Tap = tap; m_FilWidth = GetFilWidth(tap); MakeFilter(HSpace, m_Tap, ffBPF, DemSamp, m_SpaceFreq-m_FilWidth, m_SpaceFreq+m_FilWidth, 60, 1.0); MakeFilter(HMark, m_Tap, ffBPF, DemSamp, m_MarkFreq-m_FilWidth, m_MarkFreq+m_FilWidth, 60, 1.0); } } void CFSKDEM::WriteData(BYTE d) { if( m_BufCount < DEMBUFMAX ){ m_Buff[m_wp] = d; m_wp++; m_BufCount++; if( m_wp >= DEMBUFMAX ) m_wp = 0; } } void CFSKDEM::DoFSK(void) { int b; if( m_Tick ){ Tick.Write(m_dMark); return; } if( m_dMark >= m_dSpace ){ // マークの時 b = m_inv ? 0 : 1; } else { // スペースの時 b = m_inv ? 1 : 0; } double deff = fabs(m_dMark - m_dSpace); // Adjustment for the level meter, added by JE3HHT (Ver 1.68A) if( m_AA6YQ.m_fEnabled && (m_type != 3) ){ deff *= 4; deff -= 30000; } // till end if( m_deff < deff ) m_deff = deff; if( !m_sqcount ){ m_avgdeff = SmoozSQ.Avg(m_deff); m_deff = 0; m_sqcount = DemSamp / 10; } m_sqcount--; if( m_sq ){ if( !m_mode ){ if( m_Limit ){ // 受信時 if( (m_SQLevel * 10.0) > m_avgdeff ){ b = 1; } } else { // 送信時 if( m_SQLevel > m_avgdeff ){ b = 1; } } } } // m_Bit = b; if( m_Scope ){ m_ScopeSync.WriteData(m_Count ? 0 : 8192.0); m_ScopeBit.WriteData(b ? 8192.0 : 0); } switch(m_mode){ case 0: // スタートビット検出待ち if( !b ){ m_Count = m_ReCount/2; if( m_majority ){ m_mark = m_space = 0; m_mode = 256; // 多数決ロジック } else { m_mode++; } #if BITDEBUG m_bitCountA = m_bitCount; m_bitCount = 0; #endif } else { m_Count = m_ReCount; } break; // 通常ロジックによる判定 case 1: // スタートビット検出待ち(Half) if( b ){ m_mode = 0; } else if( !m_Count ){ if( m_Scope ){ m_ScopeSync.UpdateData(-8192.0); // スタートビット位置 } m_Count = m_ReCount; m_Data = 0; m_DataCount = m_BitLen; m_SumParity = 0; m_mode++; } break; case 2: // 符号記録中 if( !m_Count ){ m_Count = m_ReCount; m_Data = BYTE(m_Data << 1); m_Data |= BYTE(b); m_DataCount--; if( !m_DataCount ){ if( m_Parity ){ m_mode++; } else { m_mode += 2; } } if( m_Parity ){ m_SumParity += b; } } break; case 3: // パリティビット if( !m_Count ){ m_Count = m_ReCount; m_mode++; switch(m_Parity){ case 1: // Even if( (!(m_SumParity & 1) ^ b) & 1 ) m_mode = 0; // パリティエラー break; case 2: // Odd if( ((m_SumParity & 1) ^ b) & 1 ) m_mode = 0; // パリティエラー break; case 3: if( !b ) m_mode = 0; break; case 4: if( b ) m_mode = 0; break; default: break; } if( !m_mode ){ // パリティエラー m_Count = m_ReCount; m_mode = 7; } } break; case 4: // ストップビットの確認 if( !m_Count ){ if( m_Scope ){ m_ScopeSync.UpdateData(-4096.0); // Stopbit位置 } if( b || m_ignoreFream ){ if( m_BufCount < DEMBUFMAX ){ m_Buff[m_wp] = m_Data; m_wp++; m_BufCount++; if( m_wp >= DEMBUFMAX ) m_wp = 0; } switch(m_StopLen){ case 2: // 2bit m_Count = (m_ReCount * 11/8); // 23/16bit時間のウエイト break; case 1: // 1.5bit m_Count = (m_ReCount * 7/8); // 15/16bit時間のウエイト break; case 4: // 1.42bit m_Count = (m_ReCount * 4/5); // 0.82bit時間のウエイト break; case 3: default: // 1bit m_Count = (m_ReCount * 3/8); // 7/16bit時間のウエイト break; } m_mode++; } if( !b ){ // フレーミングエラー m_mode = 8; } } break; case 5: // ストップビット終了待ちタイマー if( !m_Count ){ if( m_Scope ){ m_ScopeSync.UpdateData(-4096.0); // Stopbits終了位置 } m_mode++; } break; case 6: // ストップ終了待ち if( b ){ m_Count = m_ReCount; } else { // 次のスタートビット m_Count = m_ReCount/2; m_mode = 0; } break; case 7: // パリティエラー時 if( !m_Count ){ m_ScopeSync.UpdateData(-4096.0); // Stopbit位置 m_mode--; } break; case 8: // フレーミングエラー時 m_Count = m_ReCount; if( b ){ m_mode = 0; } break; // 多数決ロジックによるデータ取りこみ case 256: // スタートビット検出待ち(Half) if( b ){m_mark++;} else {m_space++;} if( !m_Count ){ b = (m_mark >= m_space) ? 1 : 0; if( b ){ m_mode = 0; } else { if( m_Scope ){ m_ScopeSync.UpdateData(-8192.0); // スタートビット位置 } m_Count = m_ReCount/2; m_mode++; } } break; case 257: // スタートビット終了待ち if( !m_Count ){ if( m_Scope ){ m_ScopeSync.UpdateData(-8192.0); // スタートビット位置 } m_Count = m_ReCount; m_mark = m_space = 0; m_Data = 0; m_DataCount = m_BitLen; m_SumParity = 0; m_mode++; } break; case 258: // 符号記録中 if( b ){m_mark++;} else {m_space++;} if( !m_Count ){ b = (m_mark >= m_space) ? 1 : 0; m_mark = m_space = 0; m_Count = m_ReCount; m_Data = BYTE(m_Data << 1); m_Data |= BYTE(b); m_DataCount--; if( !m_DataCount ){ if( m_Parity ){ m_mode++; } else { switch(m_StopLen){ case 2: // 2bit case 1: // 1.5bit case 4: // 1.42bit break; case 3: default: // 1bit m_Count = m_ReCount * 7 / 8; break; } m_mode += 2; } } if( m_Parity ){ m_SumParity += b; } } break; case 259: // パリティビット if( b ){ m_mark++; } else { m_space++; } if( !m_Count ){ b = (m_mark >= m_space) ? 1 : 0; m_mark = m_space = 0; m_Count = m_ReCount; m_mode++; switch(m_Parity){ case 1: // Even if( (!(m_SumParity & 1) ^ b) & 1 ) m_mode = 0; // パリティエラー break; case 2: // Odd if( ((m_SumParity & 1) ^ b) & 1 ) m_mode = 0; // パリティエラー break; case 3: if( !b ) m_mode = 0; break; case 4: if( b ) m_mode = 0; break; default: break; } if( !m_mode ){ // パリティエラー m_Count = m_ReCount; m_mode = 7; } else { switch(m_StopLen){ case 2: // 2bit case 1: // 1.5bit case 4: // 1.42bit break; case 3: default: // 1bit m_Count = m_ReCount * 7 / 8; break; } } } break; case 260: // ストップビットの確認 if( b ){ m_mark++; } else { m_space++; } if( !m_Count ){ b = (m_mark >= m_space) ? 1 : 0; m_mark = m_space = 0; if( m_Scope ){ m_ScopeSync.UpdateData(-4096.0); // Stopbit位置 } if( b || m_ignoreFream ){ if( m_BufCount < DEMBUFMAX ){ m_Buff[m_wp] = m_Data; m_wp++; m_BufCount++; if( m_wp >= DEMBUFMAX ) m_wp = 0; } switch(m_StopLen){ case 2: // 2bit m_Count = (m_ReCount * 7/8); break; case 1: // 1.5bit m_Count = (m_ReCount * 3/8); break; case 4: // 1.42bit m_Count = (m_ReCount * 2/5); break; case 3: default: // 1bit m_Count = m_ReCount; if( m_Scope ){ m_ScopeSync.UpdateData(-4096.0); // Stopbits終了位置 } m_mode = -1; break; } m_mode++; } if( !b ){ // フレーミングエラー m_mode = 8; } } break; case 261: // ストップビット終了待ちタイマー if( !m_Count ){ if( m_Scope ){ m_ScopeSync.UpdateData(-4096.0); // Stopbits終了位置 } m_mode++; } break; case 262: // ストップ終了待ち if( b ){ m_Count = m_ReCount; } else { // 次のスタートビット m_Count = m_ReCount/2; m_mode = 0; } break; }; m_Count--; #if BITDEBUG m_bitCount++; #endif } void CFSKDEM::Do(double d) { if( m_AA6YQ.m_fEnabled ) d = m_AA6YQ.Do(d); double ds = d; if( (d > 24578.0) || (d < -24578.0) ){ m_OverFlow = 1; } if( m_Limit ){ if( m_LimitAGC ){ if( m_limitMax < d ) m_limitMax = d; if( m_limitMin > d ) m_limitMin = d; if( (d >= 0) && (m_d < 0) ){ m_limitagc = (m_limitMax - m_limitMin); if( m_limitagc ){ m_limitagc = (64.0 * 16384.0)/ m_limitagc; if( m_limitagc >= 4096.0 ) m_limitagc = 4096; } else { m_limitagc = 200; } m_limitMax = 1; m_limitMin = -1; } m_d = d; if( m_LimitOverSampling ){ d = OverLimit.Do(d, m_limitagc); } else { d *= m_limitagc; if( d > 16384.0 ) d = 16384.0; if( d < -16384.0 ) d = -16384.0; } } else { if( m_LimitOverSampling ){ d = OverLimit.Do(d, m_LimitGain); } else { d *= m_LimitGain; if( d > 16384.0 ) d = 16384.0; if( d < -16384.0 ) d = -16384.0; } } // if( m_AA6YQ.m_fEnabled ) d *= 0.3333; // Delete by JE3HHT (Ver1.68A) } if( (Count & 1) || (!DemOver) ){ if( DemOver ) d = DECM2.Do(d, i2); // 1/2デシメータ switch(m_type){ case 2: // PLL { double dm = m_iirm.Do(d); double ds = m_iirs.Do(d); d = m_pll.Do(d); if( m_XYScope ){ // For XY-Scope m_XYScopeMark.WriteData(dm); m_XYScopeSpace.WriteData(ds); } if( m_Scope ){ // For Scope m_ScopeMark[0].WriteData(dm); m_ScopeSpace[0].WriteData(ds); } if( m_Scope ){ m_ScopeMark[1].WriteData(m_pll.GetOut()); m_ScopeSpace[1].WriteData(d); } d = m_atcPLL.Do(d + 8192.0) - 8192.0; if( d >= 0 ){ m_dMark = d; m_dSpace = 0; } else { m_dMark = 0; m_dSpace = -d; } // 平滑 if( m_lpf ){ m_dMark = LpfMark.Do(m_dMark); m_dSpace = LpfSpace.Do(m_dSpace); } else { m_dMark = avgMark.Avg(m_dMark); m_dSpace = avgSpace.Avg(m_dSpace); } if( m_Scope ){ m_ScopeMark[2].WriteData(m_dMark); m_ScopeSpace[2].WriteData(m_dSpace); } if( m_atc ){ m_dMark = m_atcMark.Do(m_dMark); m_dSpace = m_atcSpace.Do(m_dSpace); if( m_Scope ){ m_ScopeMark[3].WriteData(m_dMark); m_ScopeSpace[3].WriteData(m_dSpace); } } break; } case 3: // FFT { m_Phase.DoFSK(ds); m_dMark = m_Phase.m_dm; m_dSpace = m_Phase.m_ds; if( m_XYScope || m_Scope ){ double dm = m_iirm.Do(d); double ds = m_iirs.Do(d); if( m_XYScope ){ // For XY-Scope m_XYScopeMark.WriteData(dm); m_XYScopeSpace.WriteData(ds); } if( m_Scope ){ // For Scope m_ScopeMark[0].WriteData(dm); m_ScopeSpace[0].WriteData(ds); } } // 検波 // m_dMark = fabs(m_dMark); // m_dSpace = fabs(m_dSpace); if( m_dMark < 0.0 ) m_dMark = -m_dMark; if( m_dSpace < 0.0 ) m_dSpace = -m_dSpace; if( m_Scope ){ m_ScopeMark[1].WriteData(m_dMark); m_ScopeSpace[1].WriteData(m_dSpace); } // 平滑 if( m_lpf ){ m_dMark = LpfMark.Do(m_dMark); m_dSpace = LpfSpace.Do(m_dSpace); } else { m_dMark = avgMark.Avg(m_dMark); m_dSpace = avgSpace.Avg(m_dSpace); } if( m_Scope ){ m_ScopeMark[2].WriteData(m_dMark); m_ScopeSpace[2].WriteData(m_dSpace); } if( m_atc ){ m_dMark = m_atcMark.Do(m_dMark); m_dSpace = m_atcSpace.Do(m_dSpace); if( m_Scope ){ m_ScopeMark[3].WriteData(m_dMark); m_ScopeSpace[3].WriteData(m_dSpace); } } #if 1 // 高速計算 m_dMark /= (64*32768.0); m_dSpace /= (64*32768.0); #else m_dMark = m_dMark > 0.0 ? sqrt(m_dMark) : 0.0; m_dSpace = m_dSpace > 0.0 ? sqrt(m_dSpace) : 0.0; m_dMark *= (1.0/16.0); m_dSpace *= (1.0/16.0); #endif break; } default: { if( m_type ){ // FIR m_dMark = DoFIR(HMark, ZMark, d, m_Tap); m_dSpace = DoFIR(HSpace, ZSpace, d, m_Tap); } else { // IIR m_dMark = m_iirm.Do(d); m_dSpace = m_iirs.Do(d); } if( m_XYScope ){ // For XY-Scope m_XYScopeMark.WriteData(m_dMark); m_XYScopeSpace.WriteData(m_dSpace); } if( m_Scope ){ // For Scope m_ScopeMark[0].WriteData(m_dMark); m_ScopeSpace[0].WriteData(m_dSpace); } // 検波 // m_dMark = fabs(m_dMark); // m_dSpace = fabs(m_dSpace); if( m_dMark < 0 ) m_dMark = -m_dMark; if( m_dSpace < 0 ) m_dSpace = -m_dSpace; if( m_Scope ){ m_ScopeMark[1].WriteData(m_dMark); m_ScopeSpace[1].WriteData(m_dSpace); } // 平滑 if( m_lpf ){ m_dMark = LpfMark.Do(m_dMark); m_dSpace = LpfSpace.Do(m_dSpace); } else { m_dMark = avgMark.Avg(m_dMark); m_dSpace = avgSpace.Avg(m_dSpace); } if( m_Scope ){ m_ScopeMark[2].WriteData(m_dMark); m_ScopeSpace[2].WriteData(m_dSpace); } if( m_atc ){ m_dMark = m_atcMark.Do(m_dMark); m_dSpace = m_atcSpace.Do(m_dSpace); if( m_Scope ){ m_ScopeMark[3].WriteData(m_dMark); m_ScopeSpace[3].WriteData(m_dSpace); } } break; } } DoFSK(); } else { i2 = d; } Count++; } int CFSKDEM::GetData(void) { int r; if( m_BufCount ){ r = m_Buff[m_rp]; m_BufCount--; m_rp++; if( m_rp >= DEMBUFMAX ) m_rp = 0; } else { r = -1; } return r; } BCODETBL _TTY[]={ // S-BELL // 0x20 - 0x7f {0x04, 2}, {0x16, 1}, {0x11, 1}, {0x00, 2}, // !"# {0x12, 1}, {0x00, 2}, {0x0b, 1}, {0x1a, 1}, // $%&' {0x1e, 1}, {0x09, 1}, {0x00, 2}, {0x00, 2}, // ()*+ {0x06, 1}, {0x18, 1}, {0x07, 1}, {0x17, 1}, // ,-./ {0x0d, 1}, {0x1d, 1}, {0x19, 1}, {0x10, 1}, // 0123 30-33 {0x0a, 1}, {0x01, 1}, {0x15, 1}, {0x1c, 1}, // 4567 34-37 {0x0c, 1}, {0x03, 1}, {0x0e, 1}, {0x0f, 1}, // 89 38-3b {0x00, 2}, {0x00, 2}, {0x00, 2}, {0x13, 1}, // <=>? 3c-3f {0x00, 2}, {0x18, 0}, {0x13, 0}, {0x0e, 0}, // @ABC 40-43 {0x12, 0}, {0x10, 0}, {0x16, 0}, {0x0b, 0}, // DEFG {0x05, 0}, {0x0c, 0}, {0x1a, 0}, {0x1e, 0}, // HIJK {0x09, 0}, {0x07, 0}, {0x06, 0}, {0x03, 0}, // LMNO {0x0d, 0}, {0x1d, 0}, {0x0a, 0}, {0x14, 0}, // PQRS {0x01, 0}, {0x1c, 0}, {0x0f, 0}, {0x19, 0}, // TUVW {0x17, 0}, {0x15, 0}, {0x11, 0}, {0x00, 2}, // XYZ[ 58-5b {0x00, 2}, {0x00, 2}, {0x00, 2}, {0x00, 2}, // \]^_ {0x00, 2}, {0x18, 0}, {0x13, 0}, {0x0e, 0}, // @ABC 60-63 {0x12, 0}, {0x10, 0}, {0x16, 0}, {0x0b, 0}, // DEFG {0x05, 0}, {0x0c, 0}, {0x1a, 0}, {0x1e, 0}, // HIJK {0x09, 0}, {0x07, 0}, {0x06, 0}, {0x03, 0}, // LMNO {0x0d, 0}, {0x1d, 0}, {0x0a, 0}, {0x14, 0}, // PQRS {0x01, 0}, {0x1c, 0}, {0x0f, 0}, {0x19, 0}, // TUVW {0x17, 0}, {0x15, 0}, {0x11, 0}, {0x00, 2}, // XYZ[ 78-7b {0x00, 2}, {0x00, 2}, {0x00, 2}, {0x00, 2}, // |{~ }; const char _LTR[32]={ 0x00, 'T', 0x0d, 'O', ' ', 'H', 'N', 'M', 0x0a, 'L', 'R', 'G', 'I', 'P', 'C', 'V', 'E', 'Z', 'D', 'B', 'S', 'Y', 'F', 'X', 'A', 'W', 'J', 0x00, 'U', 'Q', 'K', 0x00, }; const char _FIG[32]={ 0x00, '5', 0x0d, '9', ' ', 'h', ',', '.', 0x0a, ')', '4', '&', '8', '0', ':', ';', '3', '"', '$', '?', 's', '6', '!', '/', '-', '2', 0x27, 0x00, '7', '1', '(', 0x00, }; CRTTY::CRTTY() { m_outfig = 3; m_fig = 0; m_uos = 0; m_txuos = 1; SetCodeSet(); } void CRTTY::SetCodeSet(void) { memcpy(m_TBL, _TTY, sizeof(m_TBL)); if( sys.m_CodeSet ){ // J-BELL m_TBL[7].Code = 0x14; } } // 11011 FIG // 11111 LTR char CRTTY::ConvAscii(int d) { char c = 0; d &= 0x1f; if( d == 0x1b ){ // FIG m_fig = 1; } else if( d == 0x1f ){ // LTR m_fig = 0; } else if( m_fig ){ c = _FIG[d]; if( sys.m_CodeSet ){ switch(c){ case 's': c = 0x27; break; case 0x27: c = 'j'; break; } } if( m_uos ){ switch(c){ case ' ': // case 0x0d: // case 0x0a: m_fig = 0; break; default: break; } } } else { c = _LTR[d]; } return c; } int CRTTY::ConvRTTY(char d) { int fig = 2; int r = 0; switch(d){ case '_': r = 0x00ff; break; case '~': r = 0x00fe; break; case '[': r = 0x00fd; break; case ']': r = 0x00fc; break; case 0x0a: r = 0x08; break; case 0x0d: r = 0x02; break; case 0x1b: r = 0x1b; fig = 1; break; case 0x1f: r = 0x1f; fig = 0; break; default: if( d >= 0x20 ){ d -= char(0x20); r = m_TBL[d].Code; fig = m_TBL[d].Fig; } break; } if( fig != 2 ){ if( fig != m_outfig ){ r |= (fig ? 0x1b00 : 0x1f00); m_outfig = fig; } } else if( r == 0x04 ){ // スペースの時 if( sys.m_txuos && (m_outfig == 1) ) m_outfig = 2; } return r; } int CRTTY::ConvRTTY(BYTE *t, LPCSTR p) { int n; int d; for( n = 0;*p; p++ ){ d = ConvRTTY(*p); if( d & 0x0000ff00 ){ *t++ = BYTE(d >> 8); n++; if( sys.m_dblsft ){ *t++ = BYTE(d >> 8); n++; } } *t++ = BYTE(d); n++; } return n; } int CRTTY::GetShift(char d) { int fig = 2; switch(d){ default: if( d >= 0x20 ){ d -= char(0x20); fig = m_TBL[d].Fig; if( !m_TBL[d].Code ){ fig = 2; } } break; } return fig; } char CRTTY::InvShift(char c) { int fs = GetShift(c); if( (c == 'h') || (c == 's') || (c == 'j') ) fs = 1; int d = ConvRTTY(c) & 0x001f; switch(fs){ case 0: if( _FIG[d] ){ c = _FIG[d]; if( sys.m_CodeSet ){ switch(c){ case 's': c = 0x27; break; case 0x27: c = 'j'; break; } } } return c; case 1: return _LTR[d] ? _LTR[d] : c; default: return c; } } //-------------------------------------------------------- // CScopeクラス CScope::CScope() { m_ScopeSize = SCOPESIZE; m_DataFlag = 0; pScopeData = new double[m_ScopeSize]; memset(pScopeData, 0, sizeof(double)*m_ScopeSize); } CScope::~CScope() { delete[] pScopeData; } void CScope::WriteData(double d) { if( !m_DataFlag ){ if( m_wp < m_ScopeSize ){ pScopeData[m_wp] = d; m_wp++; if( m_wp >= m_ScopeSize ){ m_DataFlag = 1; } } } } void CScope::UpdateData(double d) { if( !m_DataFlag ){ if( m_wp ){ pScopeData[m_wp-1] = d; } } } void CScope::Collect(int size) { m_DataFlag = 1; m_ScopeSize = size; m_wp = 0; m_DataFlag = 0; } //-------------------------------------------------------- // CNoiseクラス CNoise::CNoise() { reg = 0x12345; memset(Z, 0, sizeof(Z)); MakeFilter(H, NOISEBPFTAP, ffLPF, SampFreq, 3000.0, 3000.0, 60, 1.0); }; double CNoise::GetNoise(void) { DWORD r = reg >> 1; if( (reg ^ r) & 1 ){ r |= 0xffe00000; } else { r &= 0x001fffff; } reg = r; double d = double(reg) / 500000.0; // return d; return DoFIR(H, Z, d, NOISEBPFTAP); // 帯域制限 } //-------------------------------------------------------- // CSamplePeakクラス CSamplePeak::CSamplePeak() { memset(Strage, 0, sizeof(Strage)); m_CurPeak = 0.0; m_Peak = 0.0; m_Strage = 8 - 1; SetBaudRate(45.45); } void CSamplePeak::SetBaudRate(double b) { if( b >= 1.0 ){ m_ReCount = m_Count = int(DemSamp/b + 0.5); } } void CSamplePeak::Sync(int Delay) { m_Count = m_ReCount - Delay; while( m_Count < 0 ) m_Count += m_ReCount; memcpy(Strage, &Strage[1], sizeof(double)*m_Strage); Strage[m_Strage] = m_CurPeak; m_Peak = 0.0; int i; for( i = 0; i <= m_Strage; i++ ){ if( m_Peak < Strage[i] ) m_Peak = Strage[i]; } m_CurPeak = 0.0; } int CSamplePeak::Sample(double d) { int r = 0; if( m_CurPeak < d ){ m_CurPeak = d; if( m_Peak < d ){ m_Peak = d; r = 1; } } if( !m_Count ){ Sync(0); r = 1; } m_Count--; return r; } //-------------------------------------------------------- // CAGCクラス CAGC::CAGC() { m_MaxGain = 2048.0; m_StepGain = 3.0; m_MarkGain = 1.0; m_SpaceGain = 1.0; m_DeffGain = 12.0; m_Sync = 1; } void CAGC::Sync(int Delay) { if( m_Sync ){ Mark.Sync(Delay); Space.Sync(Delay); } } double CAGC::SampleMark(double d) { if( Mark.Sample(d) ){ double gain = Mark.GetPeak(); if( gain ){ gain = 8192.0 / gain; double ugain = m_MarkGain * m_StepGain; double dgain = m_MarkGain / m_StepGain; if( ugain < gain ){ m_MarkGain = ugain; } else if( dgain > gain ){ m_MarkGain = dgain; } else { m_MarkGain = gain; } if( m_MarkGain > m_MaxGain ) m_MarkGain = m_MaxGain; } else { m_MarkGain = 1.0; } } return d * m_MarkGain; } double CAGC::SampleSpace(double d) { if( Space.Sample(d) ){ double gain = Space.GetPeak(); if( gain ){ gain = 8192.0 / gain; double ugain = m_SpaceGain * m_StepGain; double dgain = m_SpaceGain / m_StepGain; if( ugain < gain ){ m_SpaceGain = ugain; } else if( dgain > gain ){ m_SpaceGain = dgain; } else { m_SpaceGain = gain; } if( m_SpaceGain > m_MaxGain ) m_SpaceGain = m_MaxGain; if( m_SpaceGain > m_MarkGain ){ if( m_SpaceGain > m_MarkGain * m_DeffGain ){ m_SpaceGain = m_MarkGain * m_DeffGain; } } else { if( m_SpaceGain * m_DeffGain < m_MarkGain ){ m_SpaceGain = m_MarkGain / m_DeffGain; } } } else { m_SpaceGain = 1.0; } } return d * m_SpaceGain; } //-------------------------------------------------------- // CATCクラス CATC::CATC() { m_Low = 0; m_High = 16384.0; m_CurLow = MAXDOUBLE; m_CurHigh = -MAXDOUBLE; m_Max = 4; m_Cnt = 0; int i; for( i = 0; i < ATCMAX; i++ ){ m_LowList[i] = m_Low; m_HighList[i] = m_High; } m_iir.MakeIIR(100, DemSamp, 3, 0, 0); } double CATC::Do(double d) { if( m_CurLow > d ) m_CurLow = d; if( m_CurHigh < d ) m_CurHigh = d; // if( m_Low > d ) m_Low = d; // if( m_High < d ) m_High = d; if( !m_Cnt ){ m_Cnt = 64; if( m_CurLow > (ATCC-ATCW) ) m_CurLow = (ATCC-ATCW); if( m_CurHigh < (ATCC+ATCW) ) m_CurHigh = (ATCC+ATCW); if( m_Max ){ memcpy(m_LowList, &m_LowList[1], (m_Max)*sizeof(double)); memcpy(m_HighList, &m_HighList[1], (m_Max)*sizeof(double)); } m_LowList[m_Max] = m_CurLow; m_HighList[m_Max] = m_CurHigh; int i; m_Low = m_LowList[0]; m_High = m_HighList[0]; for( i = 1; i <= m_Max; i++ ){ if( m_Low > m_LowList[i] ) m_Low = m_LowList[i]; if( m_High < m_HighList[i] ) m_High = m_HighList[i]; } m_CurLow = MAXDOUBLE; m_CurHigh = -MAXDOUBLE; } m_Cnt--; double th = ((m_High + m_Low)*0.5); th = m_iir.Do(th); if( m_High > m_Low ){ d = (d - th) * 1.1 + th; } d += (ATCC - th); return d; } //--------------------------------------------------------------------------- // CFIRクラス __fastcall CFIR::CFIR() { m_pZ = NULL; m_pH = NULL; m_Tap = 0; } //--------------------------------------------------------------------------- __fastcall CFIR::~CFIR() { if( m_pZ ) delete[] m_pZ; if( m_pH ) delete[] m_pH; } //--------------------------------------------------------------------------- void __fastcall CFIR::Create(int tap, int type, double fs, double fcl, double fch, double att, double gain) { m_Tap = tap; if( m_pZ ) delete[] m_pZ; if( m_pH ) delete[] m_pH; m_pZ = new double[tap+1]; m_pH = new double[tap+1]; memset(m_pZ, 0, sizeof(double)*(tap+1)); ::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain); } //--------------------------------------------------------------------------- double __fastcall CFIR::Do(double d) { return DoFIR(m_pH, m_pZ, d, m_Tap); } //--------------------------------------------------------------------------- void __fastcall CFIR::SaveCoef(LPCSTR pName) { FILE *fp; if( (fp = fopen(pName, "wt")) != NULL ){ int i; for( i = 0; i <= m_Tap; i++ ){ fprintf(fp, "H[%u]=%lf\n", i, m_pH[i]); } fclose(fp); } } //--------------------------------------------------------------------------- // CFIR2クラス __fastcall CFIR2::CFIR2() { m_pZ = NULL; m_pH = NULL; m_pZP = NULL; m_W = 0; m_Tap = 0; m_fs = 0; } //--------------------------------------------------------------------------- __fastcall CFIR2::~CFIR2() { if( m_pZ ) delete[] m_pZ; if( m_pH ) delete[] m_pH; } //--------------------------------------------------------------------------- void __fastcall CFIR2::Delete(void) { if( m_pZ ) delete[] m_pZ; if( m_pH ) delete[] m_pH; m_pZ = NULL; m_pH = NULL; m_pZP = NULL; m_W = 0; m_Tap = 0; m_fs = 0; } //--------------------------------------------------------------------------- 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; m_fs = fs; ::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain); } //--------------------------------------------------------------------------- void __fastcall CFIR2::Create(int tap, double fs, double fcl, double fch) { 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; m_fs = fs; ::MakeHilbert(m_pH, tap, fs, fcl, fch); } //--------------------------------------------------------------------------- void __fastcall CFIR2::CreateSamp(int tap, double fs, const double *pSmpFQ) { 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; } int htap = tap/2; int i, j; double *pSamp = new double[tap+1]; memcpy(pSamp, pSmpFQ, sizeof(double)*(tap/2)); for( i = 0; i < tap/2; i++ ){ pSamp[tap-i] = pSamp[i]; } pSamp[tap/2] = pSamp[tap/2 - 1]; double *pH = new double[tap+1]; double re, fm; for( i = 0; i <= htap; i++ ){ re = 0.0; for( j = 0; j < tap; j++ ){ fm = 2.0 * PI * double((i*j)%tap)/double(tap); re += pSamp[j] * cos(fm); } pH[i] = re / tap; } #if 0 fm = 0; for( i = 0; i <= htap; i++ ){ fm += pH[i]; } fm = 0.5 / fm; for( i = 0; i <= htap; i++ ){ pH[i] *= fm; } #endif for( i = 0; i <= htap; i++ ) m_pH[htap-i] = pH[i]; for( i = 0; i < htap; i++ ) m_pH[tap-i] = m_pH[i]; delete[] pH; delete[] pSamp; m_Tap = tap; m_TapHalf = htap; m_fs = fs; } //--------------------------------------------------------------------------- void __fastcall CFIR2::Clear(void) { if( m_pZ ) memset(m_pZ, 0, sizeof(double)*(m_Tap+1)*2); m_W = 0; } //--------------------------------------------------------------------------- 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 *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(CLX &z, 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++); } z.j = d; z.r = m_pZ[m_W+m_TapHalf+1]; m_W++; if( m_W > m_Tap ) m_W = 0; } //--------------------------------------------------------------------------- // CFIRXクラス __fastcall CFIRX::CFIRX() { m_pZ = NULL; m_pH = NULL; m_pZP = NULL; m_W = 0; m_Tap = 0; m_fs = 0; } //--------------------------------------------------------------------------- __fastcall CFIRX::~CFIRX() { if( m_pZ ) delete[] m_pZ; if( m_pH ) delete[] m_pH; } //--------------------------------------------------------------------------- void __fastcall CFIRX::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 CLX[(tap+1)*2]; memset(m_pZ, 0, sizeof(CLX)*(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; m_fs = fs; ::MakeFilter(m_pH, tap, type, fs, fcl, fch, att, gain); } //--------------------------------------------------------------------------- void __fastcall CFIRX::Clear(void) { if( m_pZ ) memset(m_pZ, 0, sizeof(CLX)*(m_Tap+1)*2); m_W = 0; } //--------------------------------------------------------------------------- void __fastcall CFIRX::Do(CLX &d) { CLX *dp1 = &m_pZ[m_W+m_Tap+1]; m_pZP = dp1; *dp1 = d; m_pZ[m_W] = d; CLX z = 0; double *hp = m_pH; for( int i = 0; i <= m_Tap; i++, dp1-- ){ z.r += dp1->r * (*hp); z.j += dp1->j * (*hp++); } m_W++; if( m_W > m_Tap ) m_W = 0; d = z; } /*============================================================================= CSlideFFTクラス スライディング FFT =============================================================================*/ #define SLIDE_WINDOW_COEFF 0.9999 __fastcall CSlideFFT::CSlideFFT(void) { m_Length = 0; m_Base = 0; m_Tones = 0; m_kWindow = 0; m_pBase = NULL; m_pCur = m_pEnd = NULL; } //-------------------------------------------------------------------------- __fastcall CSlideFFT::~CSlideFFT() { if( m_pBase ) delete[] m_pBase; } //-------------------------------------------------------------------------- void __fastcall CSlideFFT::Create(int len, int base, int tones) { #if LOGFFT FILE *fp = fopen("SLIDERFFT.txt", "wt"); fprintf(fp, "len=%d, base=%d, tones=%d\n", len, base, tones); fclose(fp); #endif if( !m_pBase || (len != m_Length) ){ if( m_pBase ) delete[] m_pBase; m_pBase = new CLX[len]; } memset(m_pBase, 0, sizeof(CLX)*len); memset(m_tWindow, 0, sizeof(m_tWindow)); memset(m_tData, 0, sizeof(m_tData)); m_Length = len; m_Base = base; m_Tones = tones; double k = 2.0 * PI / double(len); for(int i = 0; i < tones; i++){ m_tWindow[i].r = cos((i+base) * k) * SLIDE_WINDOW_COEFF; m_tWindow[i].j = sin((i+base) * k) * SLIDE_WINDOW_COEFF; } m_kWindow = pow(SLIDE_WINDOW_COEFF, len); m_pCur = m_pBase; m_pEnd = &m_pBase[m_Length]; } //-------------------------------------------------------------------------- CLX* __fastcall CSlideFFT::Do(const CLX &zIn) { CLX z; if( m_pCur >= m_pEnd ) m_pCur = m_pBase; z = *m_pCur; *m_pCur = zIn; m_pCur++; z *= m_kWindow; CLX *pData = m_tData; CLX *pWindow = m_tWindow; for( int i = 0; i < m_Tones; i++, pData++ ){ *pData -= z; *pData += zIn; *pData *= *pWindow++; } return m_tData; } /*============================================================================= CPHASEクラス =============================================================================*/ __fastcall CPHASE::CPHASE() { m_TONES = 4; m_SHIFT = 170.0; m_SampleFreq = 11025.0*0.5; m_CarrierFreq = 1750; m_MixerFreq = 0; SetSampleFreq(m_SampleFreq); } //-------------------------------------------------------------------------- void __fastcall CPHASE::ShowPara(void) { /* if( Application->MainForm ){ char bf[256]; sprintf(bf, "Car=%.lf, Shift=%.lf", m_CarrierFreq, m_SHIFT); Application->MainForm->Caption = bf; } */ } //-------------------------------------------------------------------------- void __fastcall CPHASE::SetSampleFreq(double f) { m_SampleFreq = f; Create(); } //-------------------------------------------------------------------------- void __fastcall CPHASE::Create(void) { // m_fftSHIFT = m_SHIFT * (m_TONES + 1) / m_TONES; m_fftSHIFT = m_SHIFT * m_TONES / (m_TONES - 1); m_SymbolLen = m_TONES * m_SampleFreq / m_fftSHIFT; m_BASEPOINT = int(CPHASE_BASEFREQ * m_TONES / m_fftSHIFT); m_MixerFreq = double(m_BASEPOINT) * m_SampleFreq / m_SymbolLen; m_VCO.SetSampleFreq(m_SampleFreq); m_Hilbert.Create(20, m_SampleFreq, 25.0, m_SampleFreq*0.5 - 25.0); m_Hilbert.Clear(); SetCarrierFreq(m_CarrierFreq); m_SlideFFT.Create(int(m_SymbolLen + 0.5), m_BASEPOINT, m_TONES); m_AGC.SetSampleFreq(m_SampleFreq); m_AGC.SetCarrierFreq(m_CarrierFreq); // m_LPF.Create(192, ffBEF, m_SampleFreq, 85.0 - 20, 85.0 + 20, 60, 1.0); #if LOGFFT m_fp = fopen("FFT.txt", "wt"); #endif // ShowPara(); } //-------------------------------------------------------------------------- void __fastcall CPHASE::SetShift(double f) { m_SHIFT = f; Create(); } //-------------------------------------------------------------------------- void __fastcall CPHASE::SetCarrierFreq(double f) { m_CarrierFreq = f; m_VCO.SetFreeFreq(m_CarrierFreq - m_MixerFreq); m_AGC.SetCarrierFreq(m_CarrierFreq); // ShowPara(); } //-------------------------------------------------------------------------- CLX* __fastcall CPHASE::Do(double d) { m_Hilbert.Do(m_sig, d); // 複素数化 CLX z; z.r = m_VCO.Do(); z.j = m_VCO.DoCos(); z *= m_sig; // 周波数変換 // m_LPF.Do(z); return m_SlideFFT.Do(z); } //-------------------------------------------------------------------------- void __fastcall CPHASE::DoFSK(double d) { // d = m_AGC.Do(d); CLX *pFFT = Do(d); m_dm = pFFT[0].vAbs(); m_ds = pFFT[m_TONES-1].vAbs(); #if LOGFFT for( int i = 0; i < m_TONES; i++ ){ if( i ) fprintf(m_fp, ","); fprintf(m_fp, "%.0lf", pFFT[i].vAbs()); } fprintf(m_fp, "\n"); #endif } //-------------------------------------------------------------------------- void __fastcall DoAvg(double &av, double in, double factor) { av = av * (1.0 - factor) + (in * factor); } //--------------------------------------------------------------------------- __fastcall CFAVG::CFAVG() { Create(16); } //--------------------------------------------------------------------------- void __fastcall CFAVG::Reset(void) { m_Cnt = 0; m_Sum = 0; m_Avg = 0; } //--------------------------------------------------------------------------- void __fastcall CFAVG::Reset(double d) { m_Cnt = m_Max; m_Sum = d * m_Max; m_Avg = d; } //--------------------------------------------------------------------------- void __fastcall CFAVG::Create(int max) { m_Max = max; m_Mul = 1.0 / m_Max; Reset(); } //--------------------------------------------------------------------------- double __fastcall CFAVG::DoZ(double d) { m_Sum += d; if( m_Cnt < m_Max ){ m_Cnt++; } else { m_Sum -= m_Avg; } m_Avg = m_Sum * m_Mul; return m_Avg; } //--------------------------------------------------------------------------- double __fastcall CFAVG::Do(double d) { m_Sum += d; if( m_Cnt < m_Max ){ m_Cnt++; m_Avg = m_Sum / m_Cnt; } else { m_Sum -= m_Avg; m_Avg = m_Sum * m_Mul; } return m_Avg; } //-------------------------------------------------------- // CAGCクラス __fastcall CAGCX::CAGCX() { m_fc = 1000.0; m_MonitorFreq = SampFreq/2048; m_SampleFreq = SampFreq; m_CarrierFreq = 1750.0; m_LimitGain = 0.005; m_AvgOver.Create(4); Create(); } //-------------------------------------------------------- void __fastcall CAGCX::Create(void) { m_Count = 0; m_Max = -1.0; m_Min = 1.0; m_d = 0; m_agc = 1.0; // m_Level.Create(ffLPF, 0.3, m_MonitorFreq, 3, 0, 0); SetCarrierFreq(m_CarrierFreq); } //-------------------------------------------------------- void __fastcall CAGCX::SetCarrierFreq(double f) { m_CarrierFreq = f; if( m_CarrierFreq >= 1000.0 ){ m_Gain = (m_CarrierFreq / 1000.0); /* 500 0.003 333 1000 0.0035 285 1.0 1.0 1500 0.005 200 1.4 1.5 1800 0.006 166 1.71 2000 0.008 125 2.3 2.0 2100 0.01 100 2.85 2.1 2200 0.012 83 3.4 2.2 2300 0.015 66 4.3 2.3 2400 0.025 40 7.1 2.4 2500 0.028 36 7.9 2.5 2600 0.030 33 8.6 2.6 */ if( m_Gain >= 2.35 ){ m_Gain *= 7.1 / 2.4; } else if( m_Gain >= 2.25 ){ m_Gain *= 4.3 / 2.3; } else if( m_Gain >= 2.15 ){ m_Gain *= 3.4 / 2.2; } else if( m_Gain >= 2.05 ){ m_Gain *= 2.9 / 2.1; } else if( m_Gain >= 1.8 ){ m_Gain *= 2.3 / 2.2; } } else { m_Gain = 1.0; } SetFC(m_fc); } //-------------------------------------------------------- void __fastcall CAGCX::SetFC(double fc) { m_fc = fc; if( fc > m_CarrierFreq*0.45 ) fc = m_CarrierFreq*0.45; // m_LPF.Create(ffLPF, fc, m_CarrierFreq, 1, 0, 0); m_LPF.MakeIIR(fc, m_CarrierFreq, 1, 0, 0); m_d = 0; m_TLimit = m_SampleFreq*0.8/m_CarrierFreq; m_AvgOver.Reset(1.0); } //-------------------------------------------------------- void __fastcall CAGCX::Reset(void) { m_Max = -1.0; m_Min = 1.0; m_agc = 1.0; m_d = 0; m_Count = 0; for( int i = 0; i < 12; i++ ){ m_LPF.Do(1.0); // m_Level.Do(0); } m_AvgOver.Reset(1.0); } //-------------------------------------------------------- double __fastcall CAGCX::Do(double d) { if( m_Max < d ) m_Max = d; if( m_Min > d ) m_Min = d; if( (d >= 0) && (m_d < 0) && (m_Count >= m_TLimit) ){ double amp = m_Max - m_Min; if( amp > 0.1 ){ m_agc = m_LPF.Do(5.0/amp); if( m_agc >= 1.0 ) m_agc = 1.0; m_Max = -32768.0; m_Min = 32768.0; } m_Count = 0; } m_Count++; m_d = d; d *= m_agc; if( d > 2.5 ){ d = 2.5; } else if( d < -2.5 ){ d = -2.5; } return d; } //-------------------------------------------------------- BOOL __fastcall CAGCX::GetOver(void) { // 5.0 / (65536 * 0.666) return (m_AvgOver.Do(m_agc) < 0.0001146); // return (m_agc < 0.0001146); } /******************************************************** CAMPCONT class by JE3HHT on Sep.2010 *********************************************************/ __fastcall CAMPCONT::CAMPCONT() { m_Max = g_SinTable.m_Size / 4; m_iMax = g_SinTable.m_Size / 4; m_Cnt = m_Max; m_S = 0; SetMax(16); } //--------------------------------------------------------------------------- void __fastcall CAMPCONT::SetMax(int max) { m_ADD = m_Max / double(max); } //--------------------------------------------------------------------------- void __fastcall CAMPCONT::Reset(void) { m_Cnt = m_Max; m_S = 0; } //--------------------------------------------------------------------------- double __fastcall CAMPCONT::Do(int s) { if( s != m_S ){ m_Cnt = 0.0; m_S = s; } int r = m_Cnt; if( r >= m_Max ) return s; m_Cnt += m_ADD; if( s ){ return g_SinTable.m_tSin[r]; } else { return g_SinTable.m_tSin[r+m_iMax]; } } /******************************************************** CAA6YQ class by JE3HHT on Sep.2010 *********************************************************/ __fastcall CAA6YQ::CAA6YQ(void) { m_fEnabled = FALSE; m_bpfTaps = 512; m_bpfFW = 35.0; m_befTaps = 256; m_befFW = 15.0; m_afcERR = 5.0; m_dblMark = 2125.0; m_dblSpace = 2295.0; m_dblMarkAFC = m_dblMark; m_dblSpaceAFC = m_dblSpace; Create(); } //-------------------------------------------------------- void __fastcall CAA6YQ::Create(void) { m_BPF.Create(m_bpfTaps, ffBPF, SampFreq, m_dblMark-m_bpfFW, m_dblSpace+m_bpfFW, 60.0, 1.0); double fc = (m_dblMark + m_dblSpace)/2.0; m_BEF.Create(m_befTaps, ffBEF, SampFreq, fc-m_befFW, fc+m_befFW, 10.0, 1.0); } //-------------------------------------------------------- void __fastcall CAA6YQ::SetMarkFreq(double f) { m_dblMark = f; m_dblMarkAFC = f; if( m_fEnabled ) Create(); } //-------------------------------------------------------- void __fastcall CAA6YQ::SetSpaceFreq(double f) { m_dblSpace = f; m_dblSpaceAFC = f; if( m_fEnabled ) Create(); } //-------------------------------------------------------- void __fastcall CAA6YQ::SetMarkFreqByAFC(double f) { m_dblMark = f; double df = fabs(f - m_dblMarkAFC); if( df >= m_afcERR ){ m_dblMarkAFC = f; if( m_fEnabled ) Create(); } } //-------------------------------------------------------- void __fastcall CAA6YQ::SetSpaceFreqByAFC(double f) { m_dblSpace = f; double df = fabs(f - m_dblSpaceAFC); if( df >= m_afcERR ){ m_dblSpaceAFC = f; if( m_fEnabled ) Create(); } } //-------------------------------------------------------- double __fastcall CAA6YQ::Do(double d) { return m_BEF.Do(m_BPF.Do(d)); } //--------------------------------------------------------