mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	Merge pull request #2006 from srcejon/freq_scanner
Use log2 approximation in spectrum power calculation
This commit is contained in:
		
						commit
						54ab8f61ca
					
				| @ -5,6 +5,7 @@ | ||||
| // Copyright (C) 2015-2023 Edouard Griffiths, F4EXB <f4exb06@gmail.com>          //
 | ||||
| // Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai>                      //
 | ||||
| // Copyright (C) 2023 Arne Jünemann <das-iro@das-iro.de>                         //
 | ||||
| // Copyright (C) 2023 Vladimir Pleskonjic                                        //
 | ||||
| //                                                                               //
 | ||||
| // 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          //
 | ||||
| @ -135,7 +136,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length) | ||||
| 
 | ||||
|             v = c.real() * c.real() + c.imag() * c.imag(); | ||||
|             m_psd[i] = v/m_powFFTDiv; | ||||
|             v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|             v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|             m_powerSpectrum[i] = v; | ||||
|         } | ||||
| 
 | ||||
| @ -176,7 +177,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length) | ||||
|             v = c.real() * c.real() + c.imag() * c.imag(); | ||||
|             v = m_movingAverage.storeAndGetAvg(v, i); | ||||
|             m_psd[i] = v/m_powFFTDiv; | ||||
|             v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|             v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|             m_powerSpectrum[i] = v; | ||||
|         } | ||||
| 
 | ||||
| @ -224,7 +225,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length) | ||||
|             if (m_fixedAverage.storeAndGetAvg(avg, v, i)) | ||||
|             { | ||||
|                 m_psd[i] = avg/m_powFFTDiv; | ||||
|                 avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | ||||
|                 avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2fapprox(avg) + m_ofs; | ||||
|                 m_powerSpectrum[i] = avg; | ||||
|             } | ||||
|         } | ||||
| @ -275,7 +276,7 @@ void SpectrumVis::feed(const Complex *begin, unsigned int length) | ||||
|             if (m_max.storeAndGetMax(max, v, i)) | ||||
|             { | ||||
|                 m_psd[i] = max/m_powFFTDiv; | ||||
|                 max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | ||||
|                 max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2fapprox(max) + m_ofs; | ||||
|                 m_powerSpectrum[i] = max; | ||||
|             } | ||||
|         } | ||||
| @ -450,7 +451,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 v = c.real() * c.real() + c.imag() * c.imag(); | ||||
|                 m_psd[i] = v/m_powFFTDiv; | ||||
|                 m_specMax = v > m_specMax ? v : m_specMax; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|                 m_powerSpectrum[i * 2] = v; | ||||
|                 m_powerSpectrum[i * 2 + 1] = v; | ||||
|             } | ||||
| @ -463,14 +464,14 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 v = c.real() * c.real() + c.imag() * c.imag(); | ||||
|                 m_psd[i] = v/m_powFFTDiv; | ||||
|                 m_specMax = v > m_specMax ? v : m_specMax; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|                 m_powerSpectrum[i] = v; | ||||
| 
 | ||||
|                 c = fftOut[i]; | ||||
|                 v = c.real() * c.real() + c.imag() * c.imag(); | ||||
|                 m_psd[i + halfSize] = v/m_powFFTDiv; | ||||
|                 m_specMax = v > m_specMax ? v : m_specMax; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|                 m_powerSpectrum[i + halfSize] = v; | ||||
|             } | ||||
|         } | ||||
| @ -512,7 +513,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 v = m_movingAverage.storeAndGetAvg(v, i); | ||||
|                 m_psd[i] = v/m_powFFTDiv; | ||||
|                 m_specMax = v > m_specMax ? v : m_specMax; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|                 m_powerSpectrum[i * 2] = v; | ||||
|                 m_powerSpectrum[i * 2 + 1] = v; | ||||
|             } | ||||
| @ -526,7 +527,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 v = m_movingAverage.storeAndGetAvg(v, i+halfSize); | ||||
|                 m_psd[i] = v/m_powFFTDiv; | ||||
|                 m_specMax = v > m_specMax ? v : m_specMax; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|                 m_powerSpectrum[i] = v; | ||||
| 
 | ||||
|                 c = fftOut[i]; | ||||
| @ -534,7 +535,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 v = m_movingAverage.storeAndGetAvg(v, i); | ||||
|                 m_psd[i + halfSize] = v/m_powFFTDiv; | ||||
|                 m_specMax = v > m_specMax ? v : m_specMax; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2f(v) + m_ofs; | ||||
|                 v = m_settings.m_linear ? v/m_powFFTDiv : m_mult * log2fapprox(v) + m_ofs; | ||||
|                 m_powerSpectrum[i + halfSize] = v; | ||||
|             } | ||||
|         } | ||||
| @ -582,7 +583,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 { | ||||
|                     m_psd[i] = avg/m_powFFTDiv; | ||||
|                     specMax = avg > specMax ? avg : specMax; | ||||
|                     avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | ||||
|                     avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2fapprox(avg) + m_ofs; | ||||
|                     m_powerSpectrum[i * 2] = avg; | ||||
|                     m_powerSpectrum[i * 2 + 1] = avg; | ||||
|                 } | ||||
| @ -600,7 +601,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 { | ||||
|                     m_psd[i] = avg/m_powFFTDiv; | ||||
|                     specMax = avg > specMax ? avg : specMax; | ||||
|                     avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | ||||
|                     avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2fapprox(avg) + m_ofs; | ||||
|                     m_powerSpectrum[i] = avg; | ||||
|                 } | ||||
| 
 | ||||
| @ -612,7 +613,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 { | ||||
|                     m_psd[i + halfSize] = avg/m_powFFTDiv; | ||||
|                     specMax = avg > specMax ? avg : specMax; | ||||
|                     avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2f(avg) + m_ofs; | ||||
|                     avg = m_settings.m_linear ? avg/m_powFFTDiv : m_mult * log2fapprox(avg) + m_ofs; | ||||
|                     m_powerSpectrum[i + halfSize] = avg; | ||||
|                 } | ||||
|             } | ||||
| @ -665,7 +666,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 { | ||||
|                     m_psd[i] = max/m_powFFTDiv; | ||||
|                     specMax = max > specMax ? max : specMax; | ||||
|                     max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | ||||
|                     max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2fapprox(max) + m_ofs; | ||||
|                     m_powerSpectrum[i * 2] = max; | ||||
|                     m_powerSpectrum[i * 2 + 1] = max; | ||||
|                 } | ||||
| @ -683,7 +684,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 { | ||||
|                     m_psd[i] = max/m_powFFTDiv; | ||||
|                     specMax = max > specMax ? max : specMax; | ||||
|                     max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | ||||
|                     max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2fapprox(max) + m_ofs; | ||||
|                     m_powerSpectrum[i] = max; | ||||
|                 } | ||||
| 
 | ||||
| @ -695,7 +696,7 @@ void SpectrumVis::processFFT(bool positiveOnly) | ||||
|                 { | ||||
|                     m_psd[i + halfSize] = max/m_powFFTDiv; | ||||
|                     specMax = max > specMax ? max : specMax; | ||||
|                     max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2f(max) + m_ofs; | ||||
|                     max = m_settings.m_linear ? max/m_powFFTDiv : m_mult * log2fapprox(max) + m_ofs; | ||||
|                     m_powerSpectrum[i + halfSize] = max; | ||||
|                 } | ||||
|             } | ||||
| @ -1084,3 +1085,48 @@ void SpectrumVis::webapiUpdateSpectrumSettings( | ||||
| 
 | ||||
|     settings.updateFrom(prefixedKeys, &response); | ||||
| } | ||||
| 
 | ||||
| // To calculate power, the usual equation:
 | ||||
| //    10*log10(V1/V2), where V2=fftSize^2
 | ||||
| // is calculated using log2 instead, with:
 | ||||
| //   ofs=20.0f * log10f(1.0f / fftSize)
 | ||||
| //   mult=(10.0f / log2(10.0f))
 | ||||
| //   dB = m_mult * log2f(v) + m_ofs
 | ||||
| // However, while the gcc version of log2f is twice as fast as log10f,
 | ||||
| // MSVC version is 6x slower.
 | ||||
| // Also, we don't need full accuracy of log2f for calculating the power for the spectrum,
 | ||||
| // so we can use the following approximation to get a good speed-up for both compilers:
 | ||||
| // https://www.vplesko.com/posts/replacing_log2f.html
 | ||||
| // https://www.vplesko.com/assets/replacing_log2f/main.c.txt
 | ||||
| float SpectrumVis::log2fapprox(float x) const | ||||
| { | ||||
|     // IEEE 754 representation constants.
 | ||||
|     const int32_t mantissaLen = 23; | ||||
|     const int32_t mantissaMask = (1 << mantissaLen) - 1; | ||||
|     const int32_t baseExponent = -127; | ||||
| 
 | ||||
|     // Reinterpret x as int in a standard compliant way.
 | ||||
|     int32_t xi; | ||||
|     memcpy(&xi, &x, sizeof(xi)); | ||||
| 
 | ||||
|     // Calculate exponent of x.
 | ||||
|     float e = (float)((xi >> mantissaLen) + baseExponent); | ||||
| 
 | ||||
|     // Calculate mantissa of x. It will be in range [1, 2).
 | ||||
|     float m; | ||||
|     int32_t mxi = (xi & mantissaMask) | ((-baseExponent) << mantissaLen); | ||||
|     memcpy(&m, &mxi, sizeof(m)); | ||||
| 
 | ||||
|     // Use Remez algorithm-generated approximation polynomial
 | ||||
|     // for log2(a) where a is in range [1, 2].
 | ||||
|     float l = 0.15824871f; | ||||
|     l = l * m + -1.051875f; | ||||
|     l = l * m + 3.0478842f; | ||||
|     l = l * m + -2.1536207f; | ||||
| 
 | ||||
|     // Add exponent to the calculation.
 | ||||
|     // Final log is log2(m*2^e)=log2(m)+e.
 | ||||
|     l += e; | ||||
| 
 | ||||
|     return l; | ||||
| } | ||||
|  | ||||
| @ -259,6 +259,7 @@ private: | ||||
|     void handleScalef(Real scalef); | ||||
|     void handleWSOpenClose(bool openClose); | ||||
|     void handleConfigureWSSpectrum(const QString& address, uint16_t port); | ||||
|     float log2fapprox(float x) const; | ||||
| 
 | ||||
|     static void webapiFormatSpectrumSettings(SWGSDRangel::SWGGLSpectrum& response, const SpectrumSettings& settings); | ||||
|     static void webapiUpdateSpectrumSettings( | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user