mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-03-23 12:48:49 -04:00
AirspyHF (float): working plugin
This commit is contained in:
parent
e7e8702d17
commit
d43ecaf8f7
@ -135,7 +135,7 @@ bool AirspyHFFInput::openDevice()
|
||||
|
||||
delete[] sampleRates;
|
||||
|
||||
airspyhf_set_sample_type(m_dev, AIRSPYHF_SAMPLE_INT16_IQ);
|
||||
airspyhf_set_sample_type(m_dev, AIRSPYHF_SAMPLE_FLOAT32_IQ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ void AirspyHFFThread::run()
|
||||
}
|
||||
|
||||
// Decimate according to specified log2 (ex: log2=4 => decim=16)
|
||||
void AirspyHFFThread::callback(const qint16* buf, qint32 len)
|
||||
void AirspyHFFThread::callback(const float* buf, qint32 len)
|
||||
{
|
||||
SampleVector::iterator it = m_convertBuffer.begin();
|
||||
|
||||
@ -136,7 +136,7 @@ void AirspyHFFThread::callback(const qint16* buf, qint32 len)
|
||||
|
||||
int AirspyHFFThread::rx_callback(airspyhf_transfer_t* transfer)
|
||||
{
|
||||
qint32 bytes_to_write = transfer->sample_count * sizeof(qint16);
|
||||
m_this->callback((qint16 *) transfer->samples, bytes_to_write);
|
||||
qint32 nbIAndQ = transfer->sample_count * 2;
|
||||
m_this->callback((float *) transfer->samples, nbIAndQ);
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <libairspyhf/airspyhf.h>
|
||||
|
||||
#include "dsp/samplesinkfifo.h"
|
||||
#include "dsp/decimators.h"
|
||||
#include "dsp/decimatorsf.h"
|
||||
|
||||
#define AIRSPYHFF_BLOCKSIZE (1<<17)
|
||||
|
||||
@ -53,14 +53,10 @@ private:
|
||||
unsigned int m_log2Decim;
|
||||
static AirspyHFFThread *m_this;
|
||||
|
||||
#ifdef SDR_RX_SAMPLE_24BIT
|
||||
Decimators<qint64, qint16, SDR_RX_SAMP_SZ, 16> m_decimators;
|
||||
#else
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators;
|
||||
#endif
|
||||
DecimatorsF m_decimators;
|
||||
|
||||
void run();
|
||||
void callback(const qint16* buf, qint32 len);
|
||||
void callback(const float* buf, qint32 len);
|
||||
static int rx_callback(airspyhf_transfer_t* transfer);
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,7 @@ set(sdrbase_SOURCES
|
||||
dsp/ctcssdetector.cpp
|
||||
dsp/cwkeyer.cpp
|
||||
dsp/cwkeyersettings.cpp
|
||||
dsp/decimatorsf.cpp
|
||||
dsp/dspcommands.cpp
|
||||
dsp/dspengine.cpp
|
||||
dsp/dspdevicesourceengine.cpp
|
||||
@ -100,6 +101,7 @@ set(sdrbase_HEADERS
|
||||
dsp/cwkeyer.h
|
||||
dsp/cwkeyersettings.h
|
||||
dsp/decimators.h
|
||||
dsp/decimatorsf.h
|
||||
dsp/decimatorsu.h
|
||||
dsp/interpolators.h
|
||||
dsp/dspcommands.h
|
||||
@ -120,6 +122,7 @@ set(sdrbase_HEADERS
|
||||
dsp/hbfiltertraits.h
|
||||
dsp/inthalfbandfilter.h
|
||||
dsp/inthalfbandfilterdb.h
|
||||
dsp/inthalfbandfilterdbf.h
|
||||
dsp/inthalfbandfiltereo1.h
|
||||
dsp/inthalfbandfiltereo1i.h
|
||||
dsp/inthalfbandfilterst.h
|
||||
|
1173
sdrbase/dsp/decimatorsf.cpp
Normal file
1173
sdrbase/dsp/decimatorsf.cpp
Normal file
File diff suppressed because it is too large
Load Diff
57
sdrbase/dsp/decimatorsf.h
Normal file
57
sdrbase/dsp/decimatorsf.h
Normal file
@ -0,0 +1,57 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program 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 General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SDRBASE_DSP_DECIMATORSF_H_
|
||||
#define SDRBASE_DSP_DECIMATORSF_H_
|
||||
|
||||
#include "dsp/inthalfbandfilterdbf.h"
|
||||
|
||||
#define DECIMATORSF_HB_FILTER_ORDER 64
|
||||
|
||||
class DecimatorsF
|
||||
{
|
||||
public:
|
||||
void decimate1(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate2_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate2_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate2_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate4_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate4_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate4_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate8_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate8_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate8_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate16_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate16_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate16_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate32_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate32_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate32_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate64_inf(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate64_sup(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
void decimate64_cen(SampleVector::iterator* it, const float* buf, qint32 nbIAndQ);
|
||||
|
||||
IntHalfbandFilterDBF<double, float, DECIMATORSF_HB_FILTER_ORDER> m_decimator2; // 1st stages
|
||||
IntHalfbandFilterDBF<double, float, DECIMATORSF_HB_FILTER_ORDER> m_decimator4; // 2nd stages
|
||||
IntHalfbandFilterDBF<double, float, DECIMATORSF_HB_FILTER_ORDER> m_decimator8; // 3rd stages
|
||||
IntHalfbandFilterDBF<double, float, DECIMATORSF_HB_FILTER_ORDER> m_decimator16; // 4th stages
|
||||
IntHalfbandFilterDBF<double, float, DECIMATORSF_HB_FILTER_ORDER> m_decimator32; // 5th stages
|
||||
IntHalfbandFilterDBF<double, float, DECIMATORSF_HB_FILTER_ORDER> m_decimator64; // 6th stages
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* SDRBASE_DSP_DECIMATORSF_H_ */
|
@ -30,6 +30,13 @@ const int32_t HBFIRFilterTraits<16>::hbCoeffs[4] = {
|
||||
(int32_t)(0.3076987787367443383246268240327481180429 * (1 << hbShift)),
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<16>::hbCoeffsF[4] = {
|
||||
-0.0052391810630145274965685509016566356877,
|
||||
0.0232111017863650750947535073009930783883,
|
||||
-0.0761058457486735451258397233686991967261,
|
||||
0.3076987787367443383246268240327481180429,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<32>::hbMod[32+6] = {
|
||||
31,32,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, 20,21,22,
|
||||
23,24,25,26,27,28,29,30,31,32,0,1,2
|
||||
@ -57,6 +64,17 @@ const int32_t HBFIRFilterTraits<32>::hbCoeffs[8] = {
|
||||
// (qint32)( 0.317237706405931241260276465254719369113 * (1 << hbShift))
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<32>::hbCoeffsF[8] = {
|
||||
-0.0018878783958199373254477348993418672762,
|
||||
0.0038624783041994003966734805288751886110,
|
||||
-0.0082424665965482504098593707908548822161,
|
||||
0.0159471139705940345709933581019868142903,
|
||||
-0.0286765592339759019246958615667608682998,
|
||||
0.0507185615622293764492845014046906726435,
|
||||
-0.0980159074728618323613105189906491432339,
|
||||
0.3159417644358786247948955860920250415802,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<48>::hbMod[48+6] = {
|
||||
47,48,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
|
||||
24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,
|
||||
@ -93,6 +111,21 @@ const int32_t HBFIRFilterTraits<48>::hbCoeffs[12] = {
|
||||
// (qint32)( 0.317491986549921390015072120149852707982 * (1 << hbShift))
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<48>::hbCoeffsF[12] = {
|
||||
-0.0011627994808655962074434020436797254661,
|
||||
0.0017451165792459334517860991553561689216,
|
||||
-0.0029357205890606303047563052643909031758,
|
||||
0.0048726090910227891003780875678330630763,
|
||||
-0.0077313759655872928144848543752232217230,
|
||||
0.0117637971494846688830238079503942572046,
|
||||
-0.0173810771817523163074170611253066454083,
|
||||
0.0253500636065296450216699497559602605179,
|
||||
-0.0373266939135983855102551842719549313188,
|
||||
0.0576685041500848358242414803953579394147,
|
||||
-0.1024912545928038654086122960507054813206,
|
||||
0.3173768238826674692454332671331940218806,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<64>::hbMod[64+6] = {
|
||||
63,64,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
|
||||
24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,
|
||||
@ -137,6 +170,25 @@ const int32_t HBFIRFilterTraits<64>::hbCoeffs[16] = {
|
||||
// (qint32)( 0.317657589850154464805598308885237202048 * (1 << hbShift)),
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<64>::hbCoeffsF[16] = {
|
||||
-0.0004653050334792540416659067936677729449,
|
||||
0.0007120490624526883919470643391491648799,
|
||||
-0.0012303473710125558716887983479182366864,
|
||||
0.0019716520179919017584369012041634050547,
|
||||
-0.0029947484165425580261710170049127555103,
|
||||
0.0043703902150498061263128590780979720876,
|
||||
-0.0061858352927315653213558022116558277048,
|
||||
0.0085554408639278121950777489246320328675,
|
||||
-0.0116397924445187355563247066925214312505,
|
||||
0.0156852221106748394852115069397768820636,
|
||||
-0.0211070832238078286147153761476147337817,
|
||||
0.0286850846890029896607554604770484729670,
|
||||
-0.0400956173930921908055147184768429724500,
|
||||
0.0597215923200692666572564348825835622847,
|
||||
-0.1036982054813635201195864965484361164272,
|
||||
0.3175014394028848885298543791577685624361,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<80>::hbMod[80+6] = {
|
||||
79,80,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
|
||||
24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,
|
||||
@ -169,6 +221,29 @@ const int32_t HBFIRFilterTraits<80>::hbCoeffs[20] = {
|
||||
(int32_t)( 0.3176437752925042046214798574510496109724 * (1 << hbShift)),
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<80>::hbCoeffsF[20] = {
|
||||
-0.0001054430663706784843331246137587697831, // ~1/9483 => hbShift = 14
|
||||
0.0001895717826405601933066613629108587702,
|
||||
-0.0003519516996893227891822497621632237497,
|
||||
0.0005975111594421821190753485453228677216,
|
||||
-0.0009524124279789792160699768430731637636,
|
||||
0.0014474605824692796454677967687985074008,
|
||||
-0.0021186428821101787461911314380813564640,
|
||||
0.0030082068742630901220236339099756150972,
|
||||
-0.0041664004891296358909502650647027621744,
|
||||
0.0056547140936428538088298623165428580251,
|
||||
-0.0075518323360079901707120342280177283101,
|
||||
0.0099644038858163180155669280679830990266,
|
||||
-0.0130470841719700410971105597468522319105,
|
||||
0.0170422818715445859028001507340377429500,
|
||||
-0.0223637819225956900603957677731159492396,
|
||||
0.0297925991327811050257690084208661573939,
|
||||
-0.0410092859102263174175817539435229264200,
|
||||
0.0604034694948822267757115866970707429573,
|
||||
-0.1041194584045879306666293473426776472479,
|
||||
0.3176437752925042046214798574510496109724,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<96>::hbMod[96+6] = {
|
||||
95,96,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
|
||||
24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,
|
||||
@ -206,6 +281,33 @@ const int32_t HBFIRFilterTraits<96>::hbCoeffs[24] = {
|
||||
(int32_t)( 0.3177437550265513332981015537370694801211 * (1 << hbShift)),
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<96>::hbCoeffsF[24] = {
|
||||
-0.0000243052463317893968695708462046667364,
|
||||
0.0000503567741519847557611806732058568059,
|
||||
-0.0001002354600628052128195172310043403741,
|
||||
0.0001801275832684542921834081052878673290,
|
||||
-0.0003014864432246496970743687704441526876,
|
||||
0.0004783148860127731604417744559754055445,
|
||||
-0.0007274200147704492930983422027679807798,
|
||||
0.0010686503612886001472748187524075547117,
|
||||
-0.0015251456116906108098629779590282851132,
|
||||
0.0021238131085570461677181075543785482296,
|
||||
-0.0028960654265650425873146467381502588978,
|
||||
0.0038789688077727475616629515542399531114,
|
||||
-0.0051173875903961539915454359572777320864,
|
||||
0.0066675444490017317031305132957186287967,
|
||||
-0.0086031967328669932404405784609480178915,
|
||||
0.0110268456349653827530676863943881471641,
|
||||
-0.0140900919878225727721599014330422505736,
|
||||
0.0180336055419063577553995258995200856589,
|
||||
-0.0232708957455770061584221508610426099040,
|
||||
0.0305843805330435619671547442521841730922,
|
||||
-0.0416576245224431485070226699463091790676,
|
||||
0.0608846679850302968661779345893592108041,
|
||||
-0.1044156487571061137087369274922821205109,
|
||||
0.3177437550265513332981015537370694801211,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<112>::hbMod[112+6] = {
|
||||
111,112,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
|
||||
24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,
|
||||
@ -248,6 +350,36 @@ const int32_t HBFIRFilterTraits<112>::hbCoeffs[28] = {
|
||||
(int32_t)( 0.3178181645034457436516106554336147382855 * (1 << hbShift)),
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<112>::hbCoeffsF[28] = {
|
||||
-0.0000057182612173497993884982611156875265,
|
||||
0.0000134089330475142792093150995169636985,
|
||||
-0.0000285019056923813186876261183133607346,
|
||||
0.0000540489980941085909355720007241075109,
|
||||
-0.0000947833751586818473982426480617391462,
|
||||
0.0001567867952902222809536542103003853299,
|
||||
-0.0002476681450895876299839182266282477940,
|
||||
0.0003767405865262860096935593201550318554,
|
||||
-0.0005551920408570068304551781146471967077,
|
||||
0.0007962529081739059839267769191906154447,
|
||||
-0.0011153731476064448775026294313761354715,
|
||||
0.0015304714714705458088878087252737714152,
|
||||
-0.0020622467141092528514212389723070373293,
|
||||
0.0027347048425079849461039049884902851772,
|
||||
-0.0035759786171320282616159502708796935622,
|
||||
0.0046196952795832949348331375460929848487,
|
||||
-0.0059072308383088713984454543037827534135,
|
||||
0.0074914857942512255370437479484735376900,
|
||||
-0.0094433233524672671732602680094714742154,
|
||||
0.0118628557280401076418074879370578855742,
|
||||
-0.0149000865720731560937206694461565348320,
|
||||
0.0187949228094094408780811988890491193160,
|
||||
-0.0239611153097040799342387629167205886915,
|
||||
0.0311823240686547251132587632582726655528,
|
||||
-0.0421443341867254184229807378869736567140,
|
||||
0.0612443342926724393349147135268140118569,
|
||||
-0.1046363792986205604185201423206308390945,
|
||||
0.3178181645034457436516106554336147382855,
|
||||
};
|
||||
|
||||
const int16_t HBFIRFilterTraits<128>::hbMod[128+6] = {
|
||||
127,128,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,
|
||||
@ -295,5 +427,40 @@ const int32_t HBFIRFilterTraits<128>::hbCoeffs[32] = {
|
||||
(int32_t)( 0.3178751792920155860855402352171950042248 * (1 << hbShift)),
|
||||
};
|
||||
|
||||
const double HBFIRFilterTraits<128>::hbCoeffsF[32] = {
|
||||
//* Remez as in https://www.dsprelated.com/showcode/270.php */
|
||||
-0.0000013530084481063586964138655693856705, // ~1/739098 => hbShift = 20
|
||||
0.0000035468835939308468221931557040615957,
|
||||
-0.0000080263259193852748679242486984364291,
|
||||
0.0000160249362715262112246382419922241525,
|
||||
-0.0000293930772937943995460653712203935584,
|
||||
0.0000506245785103059592661099708177374623,
|
||||
-0.0000829848508757281692112955928664064231,
|
||||
0.0001306421953216197048494584542766006052,
|
||||
-0.0001988007175677746298826653603697423023,
|
||||
0.0002938302746977689504891129157471141298,
|
||||
-0.0004233934809845499216279796073081342911,
|
||||
0.0005965709177428588560684885599982862914,
|
||||
-0.0008239883872841064762701512869114139903,
|
||||
0.0011179618447797630680778935285957231827,
|
||||
-0.0014926744261021872121897313689942166093,
|
||||
0.0019644262679035678388628216595179765136,
|
||||
-0.0025520032927806384458191413244776413194,
|
||||
0.0032772538071471992750238744207536001340,
|
||||
-0.0041660018952565701713663948169141804101,
|
||||
0.0052495120038521464814196271220225753495,
|
||||
-0.0065668614662222155736737150277804175857,
|
||||
0.0081688408784787811672822854802689107601,
|
||||
-0.0101245136956070701239607245724982931279,
|
||||
0.0125326183062810583845880785247572930530,
|
||||
-0.0155423066893098579810406079104723175988,
|
||||
0.0193932322698959942741669948418348212726,
|
||||
-0.0244995384963461564076236953724219347350,
|
||||
0.0316459368298866380864176051090908003971,
|
||||
-0.0425198999626832385700936356442980468273,
|
||||
0.0615208850123762293615747864805598510429,
|
||||
-0.1048057030317238041972061068918264936656,
|
||||
0.3178751792920155860855402352171950042248,
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@ struct HBFIRFilterTraits<16>
|
||||
static const int32_t hbShift = 12;
|
||||
static const int16_t hbMod[16+6];
|
||||
static const int32_t hbCoeffs[4] __attribute__ ((aligned (16)));
|
||||
static const double hbCoeffsF[4];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -47,6 +48,7 @@ struct HBFIRFilterTraits<32>
|
||||
static const int32_t hbShift = 12;
|
||||
static const int16_t hbMod[32+6];
|
||||
static const int32_t hbCoeffs[8] __attribute__ ((aligned (32)));
|
||||
static const double hbCoeffsF[8];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -56,6 +58,7 @@ struct HBFIRFilterTraits<48>
|
||||
static const int32_t hbShift = 12;
|
||||
static const int16_t hbMod[48+6];
|
||||
static const int32_t hbCoeffs[12] __attribute__ ((aligned (16)));
|
||||
static const double hbCoeffsF[12];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -65,6 +68,7 @@ struct HBFIRFilterTraits<64>
|
||||
static const int32_t hbShift = 12;
|
||||
static const int16_t hbMod[64+6];
|
||||
static const int32_t hbCoeffs[16] __attribute__ ((aligned (32)));
|
||||
static const double hbCoeffsF[16];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -74,6 +78,7 @@ struct HBFIRFilterTraits<80>
|
||||
static const int32_t hbShift = 14;
|
||||
static const int16_t hbMod[80+6];
|
||||
static const int32_t hbCoeffs[20] __attribute__ ((aligned (16)));
|
||||
static const double hbCoeffsF[20];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -83,6 +88,7 @@ struct HBFIRFilterTraits<96>
|
||||
static const int32_t hbShift = 16;
|
||||
static const int16_t hbMod[96+6];
|
||||
static const int32_t hbCoeffs[24] __attribute__ ((aligned (32)));
|
||||
static const double hbCoeffsF[24];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -92,6 +98,7 @@ struct HBFIRFilterTraits<112>
|
||||
static const int32_t hbShift = 18;
|
||||
static const int16_t hbMod[112+6];
|
||||
static const int32_t hbCoeffs[28] __attribute__ ((aligned (16)));
|
||||
static const double hbCoeffsF[28];
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -101,6 +108,7 @@ struct HBFIRFilterTraits<128>
|
||||
static const int32_t hbShift = 20;
|
||||
static const int16_t hbMod[128+6];
|
||||
static const int32_t hbCoeffs[32] __attribute__ ((aligned (16)));
|
||||
static const double hbCoeffsF[32];
|
||||
};
|
||||
|
||||
#endif /* SDRBASE_DSP_HBFILTERTRAITS_H_ */
|
||||
|
711
sdrbase/dsp/inthalfbandfilterdbf.h
Normal file
711
sdrbase/dsp/inthalfbandfilterdbf.h
Normal file
@ -0,0 +1,711 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2018 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// Float half-band FIR based interpolator and decimator //
|
||||
// This is the double buffer variant //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation as version 3 of the License, or //
|
||||
// //
|
||||
// This program 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 General Public License V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_INTHALFBANDFILTER_DBF_H
|
||||
#define INCLUDE_INTHALFBANDFILTER_DBF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dsp/dsptypes.h"
|
||||
#include "dsp/hbfiltertraits.h"
|
||||
#include "util/export.h"
|
||||
|
||||
template<typename AccuType, typename SampleType, uint32_t HBFilterOrder>
|
||||
class SDRANGEL_API IntHalfbandFilterDBF {
|
||||
public:
|
||||
IntHalfbandFilterDBF();
|
||||
|
||||
// downsample by 2, return center part of original spectrum
|
||||
bool workDecimateCenter(Sample* sample)
|
||||
{
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sample->real(), (FixReal) sample->imag());
|
||||
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 1;
|
||||
// tell caller we don't have a new sample
|
||||
return false;
|
||||
|
||||
default:
|
||||
// save result
|
||||
doFIR(sample);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 0;
|
||||
|
||||
// tell caller we have a new sample
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// upsample by 2, return center part of original spectrum - double buffer variant
|
||||
bool workInterpolateCenterZeroStuffing(Sample* sampleIn, Sample *SampleOut)
|
||||
{
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) 0, (FixReal) 0);
|
||||
// save result
|
||||
doFIR(SampleOut);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 1;
|
||||
// tell caller we didn't consume the sample
|
||||
return false;
|
||||
|
||||
default:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag());
|
||||
// save result
|
||||
doFIR(SampleOut);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 0;
|
||||
// tell caller we consumed the sample
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Optimized upsampler by 2 not calculating FIR with inserted null samples */
|
||||
bool workInterpolateCenter(Sample* sampleIn, Sample *SampleOut)
|
||||
{
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// return the middle peak
|
||||
SampleOut->setReal(m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][0]);
|
||||
SampleOut->setImag(m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][1]);
|
||||
m_state = 1; // next state
|
||||
return false; // tell caller we didn't consume the sample
|
||||
|
||||
default:
|
||||
// calculate with non null samples
|
||||
doInterpolateFIR(SampleOut);
|
||||
|
||||
// insert sample into ring double buffer
|
||||
m_samplesDB[m_ptr][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr][1] = sampleIn->imag();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][1] = sampleIn->imag();
|
||||
|
||||
// advance pointer
|
||||
if (m_ptr < (HBFIRFilterTraits<HBFilterOrder>::hbOrder/2) - 1) {
|
||||
m_ptr++;
|
||||
} else {
|
||||
m_ptr = 0;
|
||||
}
|
||||
|
||||
m_state = 0; // next state
|
||||
return true; // tell caller we consumed the sample
|
||||
}
|
||||
}
|
||||
|
||||
// downsample by 2, return lower half of original spectrum
|
||||
bool workDecimateLowerHalf(Sample* sample)
|
||||
{
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) -sample->imag(), (FixReal) sample->real());
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 1;
|
||||
// tell caller we don't have a new sample
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) -sample->real(), (FixReal) -sample->imag());
|
||||
// save result
|
||||
doFIR(sample);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 2;
|
||||
// tell caller we have a new sample
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sample->imag(), (FixReal) -sample->real());
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 3;
|
||||
// tell caller we don't have a new sample
|
||||
return false;
|
||||
|
||||
default:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sample->real(), (FixReal) sample->imag());
|
||||
// save result
|
||||
doFIR(sample);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 0;
|
||||
// tell caller we have a new sample
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Optimized upsampler by 2 not calculating FIR with inserted null samples */
|
||||
bool workInterpolateLowerHalf(Sample* sampleIn, Sample *sampleOut)
|
||||
{
|
||||
Sample s;
|
||||
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// return the middle peak
|
||||
sampleOut->setReal(m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][1]); // imag
|
||||
sampleOut->setImag(-m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][0]); // - real
|
||||
m_state = 1; // next state
|
||||
return false; // tell caller we didn't consume the sample
|
||||
|
||||
case 1:
|
||||
// calculate with non null samples
|
||||
doInterpolateFIR(&s);
|
||||
sampleOut->setReal(-s.real());
|
||||
sampleOut->setImag(-s.imag());
|
||||
|
||||
// insert sample into ring double buffer
|
||||
m_samplesDB[m_ptr][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr][1] = sampleIn->imag();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][1] = sampleIn->imag();
|
||||
|
||||
// advance pointer
|
||||
if (m_ptr < (HBFIRFilterTraits<HBFilterOrder>::hbOrder/2) - 1) {
|
||||
m_ptr++;
|
||||
} else {
|
||||
m_ptr = 0;
|
||||
}
|
||||
|
||||
m_state = 2; // next state
|
||||
return true; // tell caller we consumed the sample
|
||||
|
||||
case 2:
|
||||
// return the middle peak
|
||||
sampleOut->setReal(-m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][1]); // - imag
|
||||
sampleOut->setImag(m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][0]); // real
|
||||
m_state = 3; // next state
|
||||
return false; // tell caller we didn't consume the sample
|
||||
|
||||
default:
|
||||
// calculate with non null samples
|
||||
doInterpolateFIR(&s);
|
||||
sampleOut->setReal(s.real());
|
||||
sampleOut->setImag(s.imag());
|
||||
|
||||
// insert sample into ring double buffer
|
||||
m_samplesDB[m_ptr][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr][1] = sampleIn->imag();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][1] = sampleIn->imag();
|
||||
|
||||
// advance pointer
|
||||
if (m_ptr < (HBFIRFilterTraits<HBFilterOrder>::hbOrder/2) - 1) {
|
||||
m_ptr++;
|
||||
} else {
|
||||
m_ptr = 0;
|
||||
}
|
||||
|
||||
m_state = 0; // next state
|
||||
return true; // tell caller we consumed the sample
|
||||
}
|
||||
}
|
||||
|
||||
// upsample by 2, from lower half of original spectrum - double buffer variant
|
||||
bool workInterpolateLowerHalfZeroStuffing(Sample* sampleIn, Sample *sampleOut)
|
||||
{
|
||||
Sample s;
|
||||
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) 0, (FixReal) 0);
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(s.imag());
|
||||
sampleOut->setImag(-s.real());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 1;
|
||||
|
||||
// tell caller we didn't consume the sample
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag());
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(-s.real());
|
||||
sampleOut->setImag(-s.imag());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 2;
|
||||
|
||||
// tell caller we consumed the sample
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) 0, (FixReal) 0);
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(-s.imag());
|
||||
sampleOut->setImag(s.real());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 3;
|
||||
|
||||
// tell caller we didn't consume the sample
|
||||
return false;
|
||||
|
||||
default:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag());
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(s.real());
|
||||
sampleOut->setImag(s.imag());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 0;
|
||||
|
||||
// tell caller we consumed the sample
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// downsample by 2, return upper half of original spectrum
|
||||
bool workDecimateUpperHalf(Sample* sample)
|
||||
{
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sample->imag(), (FixReal) -sample->real());
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 1;
|
||||
// tell caller we don't have a new sample
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) -sample->real(), (FixReal) -sample->imag());
|
||||
// save result
|
||||
doFIR(sample);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 2;
|
||||
// tell caller we have a new sample
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) -sample->imag(), (FixReal) sample->real());
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 3;
|
||||
// tell caller we don't have a new sample
|
||||
return false;
|
||||
|
||||
default:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sample->real(), (FixReal) sample->imag());
|
||||
// save result
|
||||
doFIR(sample);
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
// next state
|
||||
m_state = 0;
|
||||
// tell caller we have a new sample
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Optimized upsampler by 2 not calculating FIR with inserted null samples */
|
||||
bool workInterpolateUpperHalf(Sample* sampleIn, Sample *sampleOut)
|
||||
{
|
||||
Sample s;
|
||||
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// return the middle peak
|
||||
sampleOut->setReal(-m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][1]); // - imag
|
||||
sampleOut->setImag(m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][0]); // + real
|
||||
m_state = 1; // next state
|
||||
return false; // tell caller we didn't consume the sample
|
||||
|
||||
case 1:
|
||||
// calculate with non null samples
|
||||
doInterpolateFIR(&s);
|
||||
sampleOut->setReal(-s.real());
|
||||
sampleOut->setImag(-s.imag());
|
||||
|
||||
// insert sample into ring double buffer
|
||||
m_samplesDB[m_ptr][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr][1] = sampleIn->imag();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][1] = sampleIn->imag();
|
||||
|
||||
// advance pointer
|
||||
if (m_ptr < (HBFIRFilterTraits<HBFilterOrder>::hbOrder/2) - 1) {
|
||||
m_ptr++;
|
||||
} else {
|
||||
m_ptr = 0;
|
||||
}
|
||||
|
||||
m_state = 2; // next state
|
||||
return true; // tell caller we consumed the sample
|
||||
|
||||
case 2:
|
||||
// return the middle peak
|
||||
sampleOut->setReal(m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][1]); // + imag
|
||||
sampleOut->setImag(-m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][0]); // - real
|
||||
m_state = 3; // next state
|
||||
return false; // tell caller we didn't consume the sample
|
||||
|
||||
default:
|
||||
// calculate with non null samples
|
||||
doInterpolateFIR(&s);
|
||||
sampleOut->setReal(s.real());
|
||||
sampleOut->setImag(s.imag());
|
||||
|
||||
// insert sample into ring double buffer
|
||||
m_samplesDB[m_ptr][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr][1] = sampleIn->imag();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][0] = sampleIn->real();
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][1] = sampleIn->imag();
|
||||
|
||||
// advance pointer
|
||||
if (m_ptr < (HBFIRFilterTraits<HBFilterOrder>::hbOrder/2) - 1) {
|
||||
m_ptr++;
|
||||
} else {
|
||||
m_ptr = 0;
|
||||
}
|
||||
|
||||
m_state = 0; // next state
|
||||
return true; // tell caller we consumed the sample
|
||||
}
|
||||
}
|
||||
|
||||
// upsample by 2, move original spectrum to upper half - double buffer variant
|
||||
bool workInterpolateUpperHalfZeroStuffing(Sample* sampleIn, Sample *sampleOut)
|
||||
{
|
||||
Sample s;
|
||||
|
||||
switch(m_state)
|
||||
{
|
||||
case 0:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) 0, (FixReal) 0);
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(-s.imag());
|
||||
sampleOut->setImag(s.real());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 1;
|
||||
|
||||
// tell caller we didn't consume the sample
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag());
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(-s.real());
|
||||
sampleOut->setImag(-s.imag());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 2;
|
||||
|
||||
// tell caller we consumed the sample
|
||||
return true;
|
||||
|
||||
case 2:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) 0, (FixReal) 0);
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(s.imag());
|
||||
sampleOut->setImag(-s.real());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 3;
|
||||
|
||||
// tell caller we didn't consume the sample
|
||||
return false;
|
||||
|
||||
default:
|
||||
// insert sample into ring-buffer
|
||||
storeSampleFixReal((FixReal) sampleIn->real(), (FixReal) sampleIn->imag());
|
||||
|
||||
// save result
|
||||
doFIR(&s);
|
||||
sampleOut->setReal(s.real());
|
||||
sampleOut->setImag(s.imag());
|
||||
|
||||
// advance write-pointer
|
||||
advancePointer();
|
||||
|
||||
// next state
|
||||
m_state = 0;
|
||||
|
||||
// tell caller we consumed the sample
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void myDecimate(const Sample* sample1, Sample* sample2)
|
||||
{
|
||||
storeSampleFixReal((FixReal) sample1->real(), (FixReal) sample1->imag());
|
||||
advancePointer();
|
||||
|
||||
storeSampleFixReal((FixReal) sample2->real(), (FixReal) sample2->imag());
|
||||
doFIR(sample2);
|
||||
advancePointer();
|
||||
}
|
||||
|
||||
void myDecimate(AccuType x1, AccuType y1, AccuType *x2, AccuType *y2)
|
||||
{
|
||||
storeSampleAccu(x1, y1);
|
||||
advancePointer();
|
||||
|
||||
storeSampleAccu(*x2, *y2);
|
||||
doFIRAccu(x2, y2);
|
||||
advancePointer();
|
||||
}
|
||||
|
||||
/** Simple zero stuffing and filter */
|
||||
void myInterpolateZeroStuffing(Sample* sample1, Sample* sample2)
|
||||
{
|
||||
storeSampleFixReal((FixReal) sample1->real(), (FixReal) sample1->imag());
|
||||
doFIR(sample1);
|
||||
advancePointer();
|
||||
|
||||
storeSampleFixReal((FixReal) 0, (FixReal) 0);
|
||||
doFIR(sample2);
|
||||
advancePointer();
|
||||
}
|
||||
|
||||
/** Optimized upsampler by 2 not calculating FIR with inserted null samples */
|
||||
void myInterpolate(qint32 *x1, qint32 *y1, qint32 *x2, qint32 *y2)
|
||||
{
|
||||
// insert sample into ring double buffer
|
||||
m_samplesDB[m_ptr][0] = *x1;
|
||||
m_samplesDB[m_ptr][1] = *y1;
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][0] = *x1;
|
||||
m_samplesDB[m_ptr + HBFIRFilterTraits<HBFilterOrder>::hbOrder/2][1] = *y1;
|
||||
|
||||
// advance pointer
|
||||
if (m_ptr < (HBFIRFilterTraits<HBFilterOrder>::hbOrder/2) - 1) {
|
||||
m_ptr++;
|
||||
} else {
|
||||
m_ptr = 0;
|
||||
}
|
||||
|
||||
// first output sample calculated with the middle peak
|
||||
*x1 = m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][0];
|
||||
*y1 = m_samplesDB[m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder/4) - 1][1];
|
||||
|
||||
// second sample calculated with the filter
|
||||
doInterpolateFIR(x2, y2);
|
||||
}
|
||||
|
||||
protected:
|
||||
SampleType m_samplesDB[2*(HBFIRFilterTraits<HBFilterOrder>::hbOrder - 1)][2]; // double buffer technique
|
||||
int m_ptr;
|
||||
int m_size;
|
||||
int m_state;
|
||||
|
||||
void storeSampleFixReal(const FixReal& sampleI, const FixReal& sampleQ)
|
||||
{
|
||||
m_samplesDB[m_ptr][0] = sampleI / SDR_RX_SCALED;
|
||||
m_samplesDB[m_ptr][1] = sampleQ / SDR_RX_SCALED;
|
||||
m_samplesDB[m_ptr + m_size][0] = sampleI / SDR_RX_SCALED;
|
||||
m_samplesDB[m_ptr + m_size][1] = sampleQ / SDR_RX_SCALED;
|
||||
}
|
||||
|
||||
void storeSampleAccu(AccuType x, AccuType y)
|
||||
{
|
||||
m_samplesDB[m_ptr][0] = x;
|
||||
m_samplesDB[m_ptr][1] = y;
|
||||
m_samplesDB[m_ptr + m_size][0] = x;
|
||||
m_samplesDB[m_ptr + m_size][1] = y;
|
||||
}
|
||||
|
||||
void advancePointer()
|
||||
{
|
||||
m_ptr = m_ptr + 1 < m_size ? m_ptr + 1: 0;
|
||||
}
|
||||
|
||||
void doFIR(Sample* sample)
|
||||
{
|
||||
int a = m_ptr + m_size; // tip pointer
|
||||
int b = m_ptr + 1; // tail pointer
|
||||
AccuType iAcc = 0;
|
||||
AccuType qAcc = 0;
|
||||
|
||||
for (int i = 0; i < HBFIRFilterTraits<HBFilterOrder>::hbOrder / 4; i++)
|
||||
{
|
||||
iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
a -= 2;
|
||||
b += 2;
|
||||
}
|
||||
|
||||
iAcc += m_samplesDB[b-1][0] << (HBFIRFilterTraits<HBFilterOrder>::hbShift - 1);
|
||||
qAcc += m_samplesDB[b-1][1] << (HBFIRFilterTraits<HBFilterOrder>::hbShift - 1);
|
||||
|
||||
sample->setReal(iAcc*SDR_RX_SCALED);
|
||||
sample->setImag(qAcc*SDR_RX_SCALED);
|
||||
}
|
||||
|
||||
void doFIRAccu(AccuType *x, AccuType *y)
|
||||
{
|
||||
int a = m_ptr + m_size; // tip pointer
|
||||
int b = m_ptr + 1; // tail pointer
|
||||
AccuType iAcc = 0;
|
||||
AccuType qAcc = 0;
|
||||
|
||||
for (int i = 0; i < HBFIRFilterTraits<HBFilterOrder>::hbOrder / 4; i++)
|
||||
{
|
||||
iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
a -= 2;
|
||||
b += 2;
|
||||
}
|
||||
|
||||
iAcc += m_samplesDB[b-1][0] / 2.0;
|
||||
qAcc += m_samplesDB[b-1][1] / 2.0;
|
||||
|
||||
*x = iAcc; // HB_SHIFT incorrect do not loose the gained bit
|
||||
*y = qAcc;
|
||||
}
|
||||
|
||||
void doInterpolateFIR(Sample* sample)
|
||||
{
|
||||
qint16 a = m_ptr;
|
||||
qint16 b = m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder / 2) - 1;
|
||||
|
||||
// go through samples in buffer
|
||||
AccuType iAcc = 0;
|
||||
AccuType qAcc = 0;
|
||||
|
||||
for (int i = 0; i < HBFIRFilterTraits<HBFilterOrder>::hbOrder / 4; i++)
|
||||
{
|
||||
iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
a++;
|
||||
b--;
|
||||
}
|
||||
|
||||
sample->setReal(iAcc * SDR_RX_SCALED);
|
||||
sample->setImag(qAcc * SDR_RX_SCALED);
|
||||
}
|
||||
|
||||
void doInterpolateFIR(qint32 *x, qint32 *y)
|
||||
{
|
||||
qint16 a = m_ptr;
|
||||
qint16 b = m_ptr + (HBFIRFilterTraits<HBFilterOrder>::hbOrder / 2) - 1;
|
||||
|
||||
// go through samples in buffer
|
||||
AccuType iAcc = 0;
|
||||
AccuType qAcc = 0;
|
||||
|
||||
for (int i = 0; i < HBFIRFilterTraits<HBFilterOrder>::hbOrder / 4; i++)
|
||||
{
|
||||
iAcc += (m_samplesDB[a][0] + m_samplesDB[b][0]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
qAcc += (m_samplesDB[a][1] + m_samplesDB[b][1]) * HBFIRFilterTraits<HBFilterOrder>::hbCoeffsF[i];
|
||||
a++;
|
||||
b--;
|
||||
}
|
||||
|
||||
*x = iAcc * SDR_RX_SCALED;
|
||||
*y = qAcc * SDR_RX_SCALED;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename AccuType, typename SampleType, uint32_t HBFilterOrder>
|
||||
IntHalfbandFilterDBF<AccuType, SampleType, HBFilterOrder>::IntHalfbandFilterDBF()
|
||||
{
|
||||
m_size = HBFIRFilterTraits<HBFilterOrder>::hbOrder - 1;
|
||||
|
||||
for (int i = 0; i < m_size; i++)
|
||||
{
|
||||
m_samplesDB[i][0] = 0;
|
||||
m_samplesDB[i][1] = 0;
|
||||
}
|
||||
|
||||
m_ptr = 0;
|
||||
m_state = 0;
|
||||
}
|
||||
|
||||
#endif // INCLUDE_INTHALFBANDFILTER_DBF_H
|
Loading…
Reference in New Issue
Block a user