mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	Benchmarking: added float->float decimators and corresponding benchmark test
This commit is contained in:
		
							parent
							
								
									b03e9c59cb
								
							
						
					
					
						commit
						17ea5f29b3
					
				| @ -315,6 +315,7 @@ target_link_libraries(sdrangelbench | ||||
|     ${QT_LIBRARIES} | ||||
| ) | ||||
| 
 | ||||
| target_compile_features(sdrangelbench PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0 | ||||
| qt5_use_modules(sdrangelbench Multimedia) | ||||
| 
 | ||||
| ############################################################################## | ||||
|  | ||||
| @ -21,6 +21,7 @@ set(sdrbase_SOURCES | ||||
|     dsp/ctcssdetector.cpp | ||||
|     dsp/cwkeyer.cpp | ||||
|     dsp/cwkeyersettings.cpp | ||||
|     dsp/decimatorsff.cpp | ||||
|     dsp/decimatorsfi.cpp | ||||
|     dsp/dspcommands.cpp | ||||
|     dsp/dspengine.cpp | ||||
| @ -104,6 +105,7 @@ set(sdrbase_HEADERS | ||||
|     dsp/cwkeyer.h | ||||
|     dsp/cwkeyersettings.h | ||||
|     dsp/decimators.h | ||||
|     dsp/decimatorsff.h | ||||
|     dsp/decimatorsfi.h | ||||
|     dsp/decimatorsu.h | ||||
|     dsp/interpolators.h | ||||
| @ -125,7 +127,8 @@ set(sdrbase_HEADERS | ||||
|     dsp/hbfiltertraits.h | ||||
|     dsp/inthalfbandfilter.h | ||||
|     dsp/inthalfbandfilterdb.h | ||||
|     dsp/inthalfbandfilterdbf.h | ||||
|     dsp/inthalfbandfilterdbff.h | ||||
|     dsp/inthalfbandfilterdbfi.h | ||||
|     dsp/inthalfbandfiltereo1.h | ||||
|     dsp/inthalfbandfiltereo1i.h | ||||
|     dsp/inthalfbandfilterst.h | ||||
|  | ||||
							
								
								
									
										1173
									
								
								sdrbase/dsp/decimatorsff.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1173
									
								
								sdrbase/dsp/decimatorsff.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										59
									
								
								sdrbase/dsp/decimatorsff.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								sdrbase/dsp/decimatorsff.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| // 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_DECIMATORSFF_H_ | ||||
| #define SDRBASE_DSP_DECIMATORSFF_H_ | ||||
| 
 | ||||
| #include "dsp/inthalfbandfilterdbff.h" | ||||
| #include "export.h" | ||||
| 
 | ||||
| #define DECIMATORSFF_HB_FILTER_ORDER 64 | ||||
| 
 | ||||
| /** Decimators with float input and float output */ | ||||
| class SDRBASE_API DecimatorsFF | ||||
| { | ||||
| public: | ||||
|     void decimate1(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate2_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate2_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate2_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate4_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate4_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate4_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate8_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate8_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate8_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate16_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate16_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate16_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate32_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate32_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate32_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate64_inf(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate64_sup(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
|     void decimate64_cen(FSampleVector::iterator* it, const float* buf, qint32 nbIAndQ); | ||||
| 
 | ||||
|     IntHalfbandFilterDBFF<double, float, DECIMATORSFF_HB_FILTER_ORDER> m_decimator2;  // 1st stages
 | ||||
|     IntHalfbandFilterDBFF<double, float, DECIMATORSFF_HB_FILTER_ORDER> m_decimator4;  // 2nd stages
 | ||||
|     IntHalfbandFilterDBFF<double, float, DECIMATORSFF_HB_FILTER_ORDER> m_decimator8;  // 3rd stages
 | ||||
|     IntHalfbandFilterDBFF<double, float, DECIMATORSFF_HB_FILTER_ORDER> m_decimator16; // 4th stages
 | ||||
|     IntHalfbandFilterDBFF<double, float, DECIMATORSFF_HB_FILTER_ORDER> m_decimator32; // 5th stages
 | ||||
|     IntHalfbandFilterDBFF<double, float, DECIMATORSFF_HB_FILTER_ORDER> m_decimator64; // 6th stages
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif /* SDRBASE_DSP_DECIMATORSFF_H_ */ | ||||
| @ -17,10 +17,10 @@ | ||||
| #ifndef SDRBASE_DSP_DECIMATORSFI_H_ | ||||
| #define SDRBASE_DSP_DECIMATORSFI_H_ | ||||
| 
 | ||||
| #include "dsp/inthalfbandfilterdbf.h" | ||||
| #include "dsp/inthalfbandfilterdbfi.h" | ||||
| #include "export.h" | ||||
| 
 | ||||
| #define DECIMATORSF_HB_FILTER_ORDER 64 | ||||
| #define DECIMATORSFI_HB_FILTER_ORDER 64 | ||||
| 
 | ||||
| /** Decimators with float input and integer output */ | ||||
| class SDRBASE_API DecimatorsFI | ||||
| @ -46,12 +46,12 @@ public: | ||||
|     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
 | ||||
|     IntHalfbandFilterDBFI<double, float, DECIMATORSFI_HB_FILTER_ORDER> m_decimator2;  // 1st stages
 | ||||
|     IntHalfbandFilterDBFI<double, float, DECIMATORSFI_HB_FILTER_ORDER> m_decimator4;  // 2nd stages
 | ||||
|     IntHalfbandFilterDBFI<double, float, DECIMATORSFI_HB_FILTER_ORDER> m_decimator8;  // 3rd stages
 | ||||
|     IntHalfbandFilterDBFI<double, float, DECIMATORSFI_HB_FILTER_ORDER> m_decimator16; // 4th stages
 | ||||
|     IntHalfbandFilterDBFI<double, float, DECIMATORSFI_HB_FILTER_ORDER> m_decimator32; // 5th stages
 | ||||
|     IntHalfbandFilterDBFI<double, float, DECIMATORSFI_HB_FILTER_ORDER> m_decimator64; // 6th stages
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -64,6 +64,28 @@ struct Sample | ||||
| 	FixReal m_imag; | ||||
| }; | ||||
| 
 | ||||
| struct FSample | ||||
| { | ||||
| 	FSample() : m_real(0), m_imag(0) {} | ||||
| 	FSample(Real real) : m_real(real), m_imag(0) {} | ||||
| 	FSample(Real real, Real imag) : m_real(real), m_imag(imag) {} | ||||
| 	FSample(const FSample& other) : m_real(other.m_real), m_imag(other.m_imag) {} | ||||
| 	inline FSample& operator=(const FSample& other) { m_real = other.m_real; m_imag = other.m_imag; return *this; } | ||||
| 
 | ||||
| 	inline FSample& operator+=(const FSample& other) { m_real += other.m_real; m_imag += other.m_imag; return *this; } | ||||
| 	inline FSample& operator-=(const FSample& other) { m_real -= other.m_real; m_imag -= other.m_imag; return *this; } | ||||
| 	inline FSample& operator/=(const Real& divisor) { m_real /= divisor; m_imag /= divisor; return *this; } | ||||
| 
 | ||||
| 	inline void setReal(Real v) { m_real = v; } | ||||
| 	inline void setImag(Real v) { m_imag = v; } | ||||
| 
 | ||||
| 	inline Real real() const { return m_real; } | ||||
| 	inline Real imag() const { return m_imag; } | ||||
| 
 | ||||
| 	Real m_real; | ||||
| 	Real m_imag; | ||||
| }; | ||||
| 
 | ||||
| struct AudioSample { | ||||
|     qint16 l; | ||||
|     qint16 r; | ||||
| @ -71,6 +93,7 @@ struct AudioSample { | ||||
| #pragma pack(pop) | ||||
| 
 | ||||
| typedef std::vector<Sample> SampleVector; | ||||
| typedef std::vector<FSample> FSampleVector; | ||||
| typedef std::vector<AudioSample> AudioVector; | ||||
| 
 | ||||
| #endif // INCLUDE_DSPTYPES_H
 | ||||
|  | ||||
							
								
								
									
										711
									
								
								sdrbase/dsp/inthalfbandfilterdbff.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										711
									
								
								sdrbase/dsp/inthalfbandfilterdbff.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_DBFF_H | ||||
| #define INCLUDE_INTHALFBANDFILTER_DBFF_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include "dsp/dsptypes.h" | ||||
| #include "dsp/hbfiltertraits.h" | ||||
| #include "export.h" | ||||
| 
 | ||||
| template<typename AccuType, typename SampleType, uint32_t HBFilterOrder> | ||||
| class SDRBASE_API IntHalfbandFilterDBFF { | ||||
| public: | ||||
|     IntHalfbandFilterDBFF(); | ||||
| 
 | ||||
| 	// downsample by 2, return center part of original spectrum
 | ||||
| 	bool workDecimateCenter(FSample* sample) | ||||
| 	{ | ||||
| 		// insert sample into ring-buffer
 | ||||
| 	    storeSampleReal((Real) sample->real(), (Real) 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(FSample* sampleIn, FSample *SampleOut) | ||||
|     { | ||||
|         switch(m_state) | ||||
|         { | ||||
|             case 0: | ||||
|                 // insert sample into ring-buffer
 | ||||
|                 storeSampleReal((Real) 0, (Real) 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
 | ||||
|                 storeSampleReal((Real) sampleIn->real(), (Real) 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(FSample* sampleIn, FSample *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(FSample* sample) | ||||
| 	{ | ||||
| 		switch(m_state) | ||||
| 		{ | ||||
| 			case 0: | ||||
| 				// insert sample into ring-buffer
 | ||||
| 			    storeSampleReal((Real) -sample->imag(), (Real) 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
 | ||||
|                 storeSampleReal((Real) -sample->real(), (Real) -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
 | ||||
|                 storeSampleReal((Real) sample->imag(), (Real) -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
 | ||||
|                 storeSampleReal((Real) sample->real(), (Real) 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(FSample* sampleIn, FSample *sampleOut) | ||||
|     { | ||||
|         FSample 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(FSample* sampleIn, FSample *sampleOut) | ||||
|     { | ||||
|         FSample s; | ||||
| 
 | ||||
|         switch(m_state) | ||||
|         { | ||||
|         case 0: | ||||
|             // insert sample into ring-buffer
 | ||||
|             storeSampleReal((Real) 0, (Real) 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
 | ||||
|             storeSampleReal((Real) sampleIn->real(), (Real) 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
 | ||||
|             storeSampleReal((Real) 0, (Real) 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
 | ||||
|             storeSampleReal((Real) sampleIn->real(), (Real) 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(FSample* sample) | ||||
| 	{ | ||||
| 		switch(m_state) | ||||
| 		{ | ||||
| 			case 0: | ||||
| 				// insert sample into ring-buffer
 | ||||
| 	            storeSampleReal((Real) sample->imag(), (Real) -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
 | ||||
|                 storeSampleReal((Real) -sample->real(), (Real) -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
 | ||||
|                 storeSampleReal((Real) -sample->imag(), (Real) 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
 | ||||
|                 storeSampleReal((Real) sample->real(), (Real) 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(FSample* sampleIn, FSample *sampleOut) | ||||
|     { | ||||
|         FSample 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(FSample* sampleIn, FSample *sampleOut) | ||||
|     { | ||||
|         FSample s; | ||||
| 
 | ||||
|         switch(m_state) | ||||
|         { | ||||
|         case 0: | ||||
|             // insert sample into ring-buffer
 | ||||
|             storeSampleReal((Real) 0, (Real) 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
 | ||||
|             storeSampleReal((Real) sampleIn->real(), (Real) 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
 | ||||
|             storeSampleReal((Real) 0, (Real) 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
 | ||||
|             storeSampleReal((Real) sampleIn->real(), (Real) 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 FSample* sample1, FSample* sample2) | ||||
|     { | ||||
|         storeSampleReal((Real) sample1->real(), (Real) sample1->imag()); | ||||
|         advancePointer(); | ||||
| 
 | ||||
|         storeSampleReal((Real) sample2->real(), (Real) 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(FSample* sample1, FSample* sample2) | ||||
|     { | ||||
|         storeSampleReal((Real) sample1->real(), (Real) sample1->imag()); | ||||
|         doFIR(sample1); | ||||
|         advancePointer(); | ||||
| 
 | ||||
|         storeSampleReal((Real) 0, (Real) 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 storeSampleReal(const Real& sampleI, const Real& sampleQ) | ||||
|     { | ||||
|         m_samplesDB[m_ptr][0] = sampleI; | ||||
|         m_samplesDB[m_ptr][1] = sampleQ; | ||||
|         m_samplesDB[m_ptr + m_size][0] = sampleI; | ||||
|         m_samplesDB[m_ptr + m_size][1] = sampleQ; | ||||
|     } | ||||
| 
 | ||||
|     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(FSample* 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); | ||||
|         sample->setImag(qAcc); | ||||
|     } | ||||
| 
 | ||||
|     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(FSample* 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); | ||||
|         sample->setImag(qAcc); | ||||
|     } | ||||
| 
 | ||||
|     void doInterpolateFIR(Real *x, Real *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; | ||||
|         *y = qAcc; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<typename AccuType, typename SampleType, uint32_t HBFilterOrder> | ||||
| IntHalfbandFilterDBFF<AccuType, SampleType, HBFilterOrder>::IntHalfbandFilterDBFF() | ||||
| { | ||||
|     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_DBFF_H
 | ||||
| @ -18,8 +18,8 @@ | ||||
| // along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 | ||||
| ///////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef INCLUDE_INTHALFBANDFILTER_DBF_H | ||||
| #define INCLUDE_INTHALFBANDFILTER_DBF_H | ||||
| #ifndef INCLUDE_INTHALFBANDFILTER_DBFI_H | ||||
| #define INCLUDE_INTHALFBANDFILTER_DBFI_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include "dsp/dsptypes.h" | ||||
| @ -27,9 +27,9 @@ | ||||
| #include "export.h" | ||||
| 
 | ||||
| template<typename AccuType, typename SampleType, uint32_t HBFilterOrder> | ||||
| class SDRBASE_API IntHalfbandFilterDBF { | ||||
| class SDRBASE_API IntHalfbandFilterDBFI { | ||||
| public: | ||||
|     IntHalfbandFilterDBF(); | ||||
|     IntHalfbandFilterDBFI(); | ||||
| 
 | ||||
| 	// downsample by 2, return center part of original spectrum
 | ||||
| 	bool workDecimateCenter(Sample* sample) | ||||
| @ -694,7 +694,7 @@ protected: | ||||
| }; | ||||
| 
 | ||||
| template<typename AccuType, typename SampleType, uint32_t HBFilterOrder> | ||||
| IntHalfbandFilterDBF<AccuType, SampleType, HBFilterOrder>::IntHalfbandFilterDBF() | ||||
| IntHalfbandFilterDBFI<AccuType, SampleType, HBFilterOrder>::IntHalfbandFilterDBFI() | ||||
| { | ||||
|     m_size = HBFIRFilterTraits<HBFilterOrder>::hbOrder - 1; | ||||
| 
 | ||||
| @ -26,7 +26,8 @@ MainBench *MainBench::m_instance = 0; | ||||
| MainBench::MainBench(qtwebapp::LoggerWithFile *logger, const ParserBench& parser, QObject *parent) : | ||||
|     QObject(parent), | ||||
|     m_logger(logger), | ||||
|     m_parser(parser) | ||||
|     m_parser(parser), | ||||
|     m_uniform_distribution(-1.0, 1.0) | ||||
| { | ||||
|     qDebug() << "MainBench::MainBench: start"; | ||||
|     m_instance = this; | ||||
| @ -49,6 +50,10 @@ void MainBench::run() | ||||
|         testDecimateII(); | ||||
|     } else if (m_parser.getTestType() == ParserBench::TestDecimatorsFI) { | ||||
|         testDecimateFI(); | ||||
|     } else if (m_parser.getTestType() == ParserBench::TestDecimatorsFF) { | ||||
|         testDecimateFF(); | ||||
|     } else { | ||||
|         qDebug() << "MainBench::run: unknown test type: " << m_parser.getTestType(); | ||||
|     } | ||||
| 
 | ||||
|     emit finished(); | ||||
| @ -73,13 +78,9 @@ void MainBench::testDecimateII() | ||||
|     } | ||||
| 
 | ||||
|     nsecs = timer.nsecsElapsed(); | ||||
|     QDebug debug = qDebug(); | ||||
|     debug.noquote(); | ||||
|     debug << tr("MainBench::testDecimateII: ran test in %L1 ns").arg(nsecs); | ||||
| 
 | ||||
|     printResults("MainBench::testDecimateII", nsecs); | ||||
| 
 | ||||
|     qDebug() << "MainBench::testDecimateII: cleanup test data"; | ||||
| 
 | ||||
|     delete[] buf; | ||||
| } | ||||
| 
 | ||||
| @ -92,6 +93,8 @@ void MainBench::testDecimateFI() | ||||
| 
 | ||||
|     float *buf = new float[m_parser.getNbSamples()*2]; | ||||
|     m_convertBuffer.resize(m_parser.getNbSamples()/(1<<m_parser.getLog2Factor())); | ||||
|     auto my_rand = std::bind(m_uniform_distribution, m_generator); | ||||
|     std::generate(buf, buf + m_parser.getNbSamples()*2 - 1, my_rand); // make sure data is in [-1.0..1.0] range
 | ||||
| 
 | ||||
|     qDebug() << "MainBench::testDecimateFI: run test"; | ||||
|     timer.start(); | ||||
| @ -102,13 +105,36 @@ void MainBench::testDecimateFI() | ||||
|     } | ||||
| 
 | ||||
|     nsecs = timer.nsecsElapsed(); | ||||
|     QDebug debug = qDebug(); | ||||
|     debug.noquote(); | ||||
|     debug << tr("MainBench::testDecimateFI: ran test in %L1 ns").arg(nsecs); | ||||
| 
 | ||||
|     printResults("MainBench::testDecimateFI", nsecs); | ||||
| 
 | ||||
|     qDebug() << "MainBench::testDecimateFI: cleanup test data"; | ||||
|     delete[] buf; | ||||
| } | ||||
| 
 | ||||
| void MainBench::testDecimateFF() | ||||
| { | ||||
|     QElapsedTimer timer; | ||||
|     qint64 nsecs; | ||||
| 
 | ||||
|     qDebug() << "MainBench::testDecimateFF: create test data"; | ||||
| 
 | ||||
|     float *buf = new float[m_parser.getNbSamples()*2]; | ||||
|     m_convertBufferF.resize(m_parser.getNbSamples()/(1<<m_parser.getLog2Factor())); | ||||
|     auto my_rand = std::bind(m_uniform_distribution, m_generator); | ||||
|     std::generate(buf, buf + m_parser.getNbSamples()*2 - 1, my_rand); // make sure data is in [-1.0..1.0] range
 | ||||
| 
 | ||||
|     qDebug() << "MainBench::testDecimateFF: run test"; | ||||
|     timer.start(); | ||||
| 
 | ||||
|     for (uint32_t i = 0; i < m_parser.getRepetition(); i++) | ||||
|     { | ||||
|         decimateFF(buf, m_parser.getNbSamples()*2); | ||||
|     } | ||||
| 
 | ||||
|     nsecs = timer.nsecsElapsed(); | ||||
|     printResults("MainBench::testDecimateFF", nsecs); | ||||
| 
 | ||||
|     qDebug() << "MainBench::testDecimateFF: cleanup test data"; | ||||
|     delete[] buf; | ||||
| } | ||||
| 
 | ||||
| @ -175,3 +201,43 @@ void MainBench::decimateFI(const float *buf, int len) | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MainBench::decimateFF(const float *buf, int len) | ||||
| { | ||||
|     FSampleVector::iterator it = m_convertBufferF.begin(); | ||||
| 
 | ||||
|     switch (m_parser.getLog2Factor()) | ||||
|     { | ||||
|     case 0: | ||||
|         m_decimatorsFF.decimate1(&it, buf, len); | ||||
|         break; | ||||
|     case 1: | ||||
|         m_decimatorsFF.decimate2_cen(&it, buf, len); | ||||
|         break; | ||||
|     case 2: | ||||
|         m_decimatorsFF.decimate4_cen(&it, buf, len); | ||||
|         break; | ||||
|     case 3: | ||||
|         m_decimatorsFF.decimate8_cen(&it, buf, len); | ||||
|         break; | ||||
|     case 4: | ||||
|         m_decimatorsFF.decimate16_cen(&it, buf, len); | ||||
|         break; | ||||
|     case 5: | ||||
|         m_decimatorsFF.decimate32_cen(&it, buf, len); | ||||
|         break; | ||||
|     case 6: | ||||
|         m_decimatorsFF.decimate64_cen(&it, buf, len); | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MainBench::printResults(const QString& prefix, qint64 nsecs) | ||||
| { | ||||
|     double ratekSs = (m_parser.getNbSamples()*m_parser.getRepetition() / (double) nsecs) * 1e6; | ||||
|     QDebug debug = qDebug(); | ||||
|     debug.noquote(); | ||||
|     debug << tr("%1: ran test in %L2 ns - sample rate: %3 kS/s").arg(prefix).arg(nsecs).arg(ratekSs); | ||||
| } | ||||
|  | ||||
| @ -20,9 +20,12 @@ | ||||
| #define SDRBENCH_MAINBENCH_H_ | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include <random> | ||||
| #include <functional> | ||||
| 
 | ||||
| #include "dsp/decimators.h" | ||||
| #include "dsp/decimatorsfi.h" | ||||
| #include "dsp/decimatorsff.h" | ||||
| #include "parserbench.h" | ||||
| 
 | ||||
| namespace qtwebapp { | ||||
| @ -45,12 +48,17 @@ signals: | ||||
| private: | ||||
|     void testDecimateII(); | ||||
|     void testDecimateFI(); | ||||
|     void testDecimateFF(); | ||||
|     void decimateII(const qint16 *buf, int len); | ||||
|     void decimateFI(const float *buf, int len); | ||||
|     void decimateFF(const float *buf, int len); | ||||
|     void printResults(const QString& prefix, qint64 nsecs); | ||||
| 
 | ||||
|     static MainBench *m_instance; | ||||
|     qtwebapp::LoggerWithFile *m_logger; | ||||
|     const ParserBench& m_parser; | ||||
|     std::mt19937 m_generator; | ||||
|     std::uniform_real_distribution<float> m_uniform_distribution; | ||||
| 
 | ||||
| #ifdef SDR_RX_SAMPLE_24BIT | ||||
|     Decimators<qint64, qint16, SDR_RX_SAMP_SZ, 12> m_decimatorsII; | ||||
| @ -58,8 +66,10 @@ private: | ||||
| 	Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12> m_decimatorsII; | ||||
| #endif | ||||
| 	DecimatorsFI m_decimatorsFI; | ||||
|     DecimatorsFF m_decimatorsFF; | ||||
| 
 | ||||
|     SampleVector m_convertBuffer; | ||||
|     FSampleVector m_convertBufferF; | ||||
| }; | ||||
| 
 | ||||
| #endif // SDRBENCH_MAINBENCH_H_
 | ||||
|  | ||||
| @ -116,6 +116,8 @@ ParserBench::TestType ParserBench::getTestType() const | ||||
| { | ||||
|     if (m_testStr == "decimatefi") { | ||||
|         return TestDecimatorsFI; | ||||
|     } else if (m_testStr == "decimateff") { | ||||
|         return TestDecimatorsFF; | ||||
|     } else { | ||||
|         return TestDecimatorsII; | ||||
|     } | ||||
|  | ||||
| @ -27,7 +27,8 @@ public: | ||||
|     typedef enum | ||||
|     { | ||||
|         TestDecimatorsII, | ||||
|         TestDecimatorsFI | ||||
|         TestDecimatorsFI, | ||||
|         TestDecimatorsFF | ||||
|     } TestType; | ||||
| 
 | ||||
|     ParserBench(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user