mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-29 20:10:22 -04:00 
			
		
		
		
	Corrected Highpass and Bandpass filters normalization. Implements #642
This commit is contained in:
		
							parent
							
								
									71f96aded6
								
							
						
					
					
						commit
						ae60808de8
					
				| @ -189,7 +189,6 @@ void AMDemodSink::processOneSample(Complex &ci) | ||||
|         if (m_settings.m_bandpassEnable) | ||||
|         { | ||||
|             demod = m_bandpass.filter(demod); | ||||
|             demod /= 301.0f; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|  | ||||
| @ -121,7 +121,7 @@ void NFMDemodSink::processOneSample(Complex &ci) | ||||
| 
 | ||||
|     if (m_settings.m_deltaSquelch) | ||||
|     { | ||||
|         if (m_afSquelch.analyze(demod * m_discriCompensation)) | ||||
|         if (m_afSquelch.analyze(demod)) | ||||
|         { | ||||
|             m_afSquelchOpen = m_afSquelch.evaluate(); // ? m_squelchGate + m_squelchDecay : 0;
 | ||||
| 
 | ||||
| @ -132,7 +132,7 @@ void NFMDemodSink::processOneSample(Complex &ci) | ||||
| 
 | ||||
|         if (m_afSquelchOpen) | ||||
|         { | ||||
|             m_squelchDelayLine.write(demod * m_discriCompensation); | ||||
|             m_squelchDelayLine.write(demod); | ||||
| 
 | ||||
|             if (m_squelchCount < 2*m_squelchGate) { | ||||
|                 m_squelchCount++; | ||||
| @ -159,7 +159,7 @@ void NFMDemodSink::processOneSample(Complex &ci) | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             m_squelchDelayLine.write(demod * m_discriCompensation); | ||||
|             m_squelchDelayLine.write(demod); | ||||
| 
 | ||||
|             if (m_squelchCount < 2*m_squelchGate) { | ||||
|                 m_squelchCount++; | ||||
| @ -179,7 +179,7 @@ void NFMDemodSink::processOneSample(Complex &ci) | ||||
|         { | ||||
|             if (m_settings.m_ctcssOn) | ||||
|             { | ||||
|                 Real ctcss_sample = m_ctcssLowpass.filter(demod * m_discriCompensation); | ||||
|                 Real ctcss_sample = m_ctcssLowpass.filter(demod); | ||||
| 
 | ||||
|                 if ((m_sampleCount & 7) == 7) // decimate 48k -> 6k
 | ||||
|                 { | ||||
| @ -224,7 +224,7 @@ void NFMDemodSink::processOneSample(Complex &ci) | ||||
|             else | ||||
|             { | ||||
|                 if (m_settings.m_highPass) { | ||||
|                     sample = m_bandpass.filter(m_squelchDelayLine.readBack(m_squelchGate)) * m_settings.m_volume; | ||||
|                     sample = m_bandpass.filter(m_squelchDelayLine.readBack(m_squelchGate)) * m_settings.m_volume * 301.0f; | ||||
|                 } else { | ||||
|                     sample = m_lowpass.filter(m_squelchDelayLine.readBack(m_squelchGate)) * m_settings.m_volume * 301.0f; | ||||
|                 } | ||||
| @ -375,14 +375,10 @@ void NFMDemodSink::applyAudioSampleRate(unsigned int sampleRate) | ||||
| 
 | ||||
|     if (sampleRate < 16000) { | ||||
|         m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones_lowrate); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
 | ||||
| 
 | ||||
|     } else { | ||||
|         m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0, afSqTones); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
 | ||||
|     } | ||||
| 
 | ||||
|     m_discriCompensation = (sampleRate/48000.0f); | ||||
|     m_discriCompensation *= sqrt(m_discriCompensation); | ||||
| 
 | ||||
|     m_phaseDiscri.setFMScaling((8.0f*sampleRate) / static_cast<float>(m_settings.m_fmDeviation)); // integrate 4x factor
 | ||||
|     m_audioFifo.setSize(sampleRate); | ||||
|     m_squelchDelayLine.resize(sampleRate/2); | ||||
|  | ||||
| @ -104,8 +104,6 @@ private: | ||||
|     uint m_audioBufferFill; | ||||
|     AudioFifo m_audioFifo; | ||||
| 
 | ||||
| 	float m_discriCompensation; //!< compensation factor that depends on audio rate (1 for 48 kS/s)
 | ||||
| 
 | ||||
| 	NCO m_nco; | ||||
| 	Interpolator m_interpolator; | ||||
| 	Real m_interpolatorDistance; | ||||
|  | ||||
| @ -256,7 +256,6 @@ void UDPSinkSink::feed(const SampleVector::const_iterator& begin, const SampleVe | ||||
|                 { | ||||
|                     double demodf = sqrt(inMagSq); | ||||
|                     demodf = m_bandpass.filter(demodf); | ||||
|                     demodf /= 301.0; | ||||
|                     Real amplitude = demodf * agcFactor * m_settings.m_gain; | ||||
|                     FixReal demod = (FixReal) amplitude; | ||||
|                     udpWriteMono(demod); | ||||
|  | ||||
| @ -134,14 +134,11 @@ void NFMModSource::modulateSample() | ||||
|     calculateLevel(t); | ||||
|     m_audioBufferFill++; | ||||
| 
 | ||||
|     if (m_settings.m_ctcssOn) | ||||
|     { | ||||
|         m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 189.0f * m_ctcssNco.next()) * (M_PI / 189.0f); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // 378 = 302 * 1.25; 302 = number of filter taps (established experimentally) and 189 = 378/2 for 2*PI
 | ||||
|         m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 189.0f); | ||||
|     // 0.625 = 1/1.25 (heuristic)
 | ||||
|     if (m_settings.m_ctcssOn) { | ||||
|         m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * (0.85f * m_bandpass.filter(t) + 0.15f * 0.625f * m_ctcssNco.next()) * (M_PI / 0.625f); | ||||
|     } else { | ||||
|         m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * m_bandpass.filter(t) * (M_PI / 0.625f); | ||||
|     } | ||||
| 
 | ||||
|     // limit phasor range to ]-pi,pi]
 | ||||
|  | ||||
| @ -23,27 +23,34 @@ public: | ||||
| 		int i; | ||||
| 
 | ||||
| 		// check constraints
 | ||||
| 		if(!(nTaps & 1)) { | ||||
| 		if (!(nTaps & 1)) | ||||
| 		{ | ||||
| 			qDebug("Bandpass filter has to have an odd number of taps"); | ||||
| 			nTaps++; | ||||
| 		} | ||||
| 
 | ||||
| 		// make room
 | ||||
| 		m_samples.resize(nTaps); | ||||
| 		for(int i = 0; i < nTaps; i++) | ||||
| 
 | ||||
| 		for (int i = 0; i < nTaps; i++) { | ||||
| 			m_samples[i] = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		m_ptr = 0; | ||||
| 		m_taps.resize(nTaps / 2 + 1); | ||||
| 		taps_lp.resize(nTaps / 2 + 1); | ||||
| 		taps_hp.resize(nTaps / 2 + 1); | ||||
| 
 | ||||
| 		// generate Sinc filter core
 | ||||
| 		for(i = 0; i < nTaps / 2 + 1; i++) { | ||||
| 			if(i == (nTaps - 1) / 2) { | ||||
| 		for (i = 0; i < nTaps / 2 + 1; i++) | ||||
| 		{ | ||||
| 			if (i == (nTaps - 1) / 2) | ||||
| 			{ | ||||
| 				taps_lp[i] = Wch / M_PI; | ||||
| 				taps_hp[i] = -(Wcl / M_PI); | ||||
| 			} | ||||
| 			else { | ||||
| 			else | ||||
| 			{ | ||||
| 				taps_lp[i] = sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wch) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI); | ||||
| 				taps_hp[i] = -sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wcl) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI); | ||||
| 			} | ||||
| @ -52,7 +59,8 @@ public: | ||||
| 		taps_hp[(nTaps - 1) / 2] += 1; | ||||
| 
 | ||||
| 		// apply Hamming window and combine lowpass and highpass
 | ||||
| 		for(i = 0; i < nTaps / 2 + 1; i++) { | ||||
| 		for (i = 0; i < nTaps / 2 + 1; i++) | ||||
| 		{ | ||||
| 			taps_lp[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps); | ||||
| 			taps_hp[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps); | ||||
| 			m_taps[i] = -(taps_lp[i]+taps_hp[i]); | ||||
| @ -63,13 +71,13 @@ public: | ||||
| 		// normalize
 | ||||
| 		Real sum = 0; | ||||
| 
 | ||||
| 		for(i = 0; i < (int)m_taps.size() - 1; i++) { | ||||
| 		for (i = 0; i < (int)m_taps.size() - 1; i++) { | ||||
| 			sum += m_taps[i] * 2; | ||||
| 		} | ||||
| 
 | ||||
| 		sum += m_taps[i]; | ||||
| 		sum += m_taps[i] - 1; | ||||
| 
 | ||||
| 		for(i = 0; i < (int)m_taps.size(); i++) { | ||||
| 		for (i = 0; i < (int)m_taps.size(); i++) { | ||||
| 			m_taps[i] /= sum; | ||||
| 		} | ||||
| 	} | ||||
| @ -84,8 +92,7 @@ public: | ||||
| 		m_samples[m_ptr] = sample; | ||||
| 		size = m_samples.size(); // Valgrind optim (2)
 | ||||
| 
 | ||||
| 		while(b < 0) | ||||
| 		{ | ||||
| 		while (b < 0) { | ||||
| 			b += size; | ||||
| 		} | ||||
| 
 | ||||
| @ -96,15 +103,13 @@ public: | ||||
| 			acc += (m_samples[a] + m_samples[b]) * m_taps[i]; | ||||
| 			a++; | ||||
| 
 | ||||
| 			while (a >= size) | ||||
| 			{ | ||||
| 			while (a >= size) { | ||||
| 				a -= size; | ||||
| 			} | ||||
| 
 | ||||
| 			b--; | ||||
| 
 | ||||
| 			while(b < 0) | ||||
| 			{ | ||||
| 			while(b < 0) { | ||||
| 				b += size; | ||||
| 			} | ||||
| 		} | ||||
| @ -113,8 +118,7 @@ public: | ||||
| 
 | ||||
| 		m_ptr++; | ||||
| 
 | ||||
| 		while (m_ptr >= size) | ||||
| 		{ | ||||
| 		while (m_ptr >= size) { | ||||
| 			m_ptr -= size; | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -16,40 +16,52 @@ public: | ||||
| 		int i; | ||||
| 
 | ||||
| 		// check constraints
 | ||||
| 		if(!(nTaps & 1)) { | ||||
| 		if (!(nTaps & 1)) | ||||
| 		{ | ||||
| 			qDebug("Highpass filter has to have an odd number of taps"); | ||||
| 			nTaps++; | ||||
| 		} | ||||
| 
 | ||||
| 		// make room
 | ||||
| 		m_samples.resize(nTaps); | ||||
| 		for(int i = 0; i < nTaps; i++) | ||||
| 
 | ||||
| 		for (int i = 0; i < nTaps; i++) { | ||||
| 			m_samples[i] = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		m_ptr = 0; | ||||
| 		m_taps.resize(nTaps / 2 + 1); | ||||
| 
 | ||||
| 		// generate Sinc filter core for lowpass but inverting every other tap for highpass keeping center tap
 | ||||
| 		for(i = 0; i < nTaps / 2 + 1; i++) { | ||||
| 			if(i == (nTaps - 1) / 2) | ||||
| 		for (i = 0; i < nTaps / 2 + 1; i++) | ||||
| 		{ | ||||
| 			if (i == (nTaps - 1) / 2) { | ||||
| 				m_taps[i] = -(Wc / M_PI); | ||||
| 			else | ||||
| 			} else { | ||||
| 				m_taps[i] = -sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wc) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		m_taps[(nTaps - 1) / 2] += 1; | ||||
| 
 | ||||
| 		// apply Hamming window
 | ||||
| 		for(i = 0; i < nTaps / 2 + 1; i++) | ||||
| 		for (i = 0; i < nTaps / 2 + 1; i++) { | ||||
| 			m_taps[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps); | ||||
| 		} | ||||
| 
 | ||||
| 		// normalize
 | ||||
| 		Real sum = 0; | ||||
| 		for(i = 0; i < (int)m_taps.size() - 1; i++) | ||||
| 
 | ||||
| 		for (i = 0; i < (int)m_taps.size() - 1; i++) { | ||||
| 			sum += m_taps[i] * 2; | ||||
| 		sum += m_taps[i]; | ||||
| 		for(i = 0; i < (int)m_taps.size(); i++) | ||||
| 		} | ||||
| 
 | ||||
| 		sum += m_taps[i] - 1; | ||||
| 
 | ||||
| 		for (i = 0; i < (int)m_taps.size(); i++) { | ||||
| 			m_taps[i] /= sum; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Type filter(Type sample) | ||||
| 	{ | ||||
| @ -61,8 +73,7 @@ public: | ||||
| 		m_samples[m_ptr] = sample; | ||||
| 		size = m_samples.size(); // Valgrind optim (2)
 | ||||
| 
 | ||||
| 		while(b < 0) | ||||
| 		{ | ||||
| 		while (b < 0) { | ||||
| 			b += size; | ||||
| 		} | ||||
| 
 | ||||
| @ -73,15 +84,13 @@ public: | ||||
| 			acc +=  (m_samples[a] + m_samples[b]) * m_taps[i]; | ||||
| 			a++; | ||||
| 
 | ||||
| 			while (a >= size) | ||||
| 			{ | ||||
| 			while (a >= size) { | ||||
| 				a -= size; | ||||
| 			} | ||||
| 
 | ||||
| 			b--; | ||||
| 
 | ||||
| 			while (b < 0) | ||||
| 			{ | ||||
| 			while (b < 0) { | ||||
| 				b += size; | ||||
| 			} | ||||
| 		} | ||||
| @ -89,8 +98,7 @@ public: | ||||
| 		acc += m_samples[a] * m_taps[i]; | ||||
| 		m_ptr++; | ||||
| 
 | ||||
| 		while (m_ptr >= size) | ||||
| 		{ | ||||
| 		while (m_ptr >= size) { | ||||
| 			m_ptr -= size; | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -16,38 +16,50 @@ public: | ||||
| 		int i; | ||||
| 
 | ||||
| 		// check constraints
 | ||||
| 		if(!(nTaps & 1)) { | ||||
| 		if (!(nTaps & 1)) | ||||
| 		{ | ||||
| 			qDebug("Lowpass filter has to have an odd number of taps"); | ||||
| 			nTaps++; | ||||
| 		} | ||||
| 
 | ||||
| 		// make room
 | ||||
| 		m_samples.resize(nTaps); | ||||
| 		for(int i = 0; i < nTaps; i++) | ||||
| 
 | ||||
| 		for (int i = 0; i < nTaps; i++) { | ||||
| 			m_samples[i] = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		m_ptr = 0; | ||||
| 		m_taps.resize(nTaps / 2 + 1); | ||||
| 
 | ||||
| 		// generate Sinc filter core
 | ||||
| 		for(i = 0; i < nTaps / 2 + 1; i++) { | ||||
| 			if(i == (nTaps - 1) / 2) | ||||
| 		for (i = 0; i < nTaps / 2 + 1; i++) | ||||
| 		{ | ||||
| 			if(i == (nTaps - 1) / 2) { | ||||
| 				m_taps[i] = Wc / M_PI; | ||||
| 			else | ||||
| 			} else { | ||||
| 				m_taps[i] = sin(((double)i - ((double)nTaps - 1.0) / 2.0) * Wc) / (((double)i - ((double)nTaps - 1.0) / 2.0) * M_PI); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// apply Hamming window
 | ||||
| 		for(i = 0; i < nTaps / 2 + 1; i++) | ||||
| 		for (i = 0; i < nTaps / 2 + 1; i++) { | ||||
| 			m_taps[i] *= 0.54 + 0.46 * cos((2.0 * M_PI * ((double)i - ((double)nTaps - 1.0) / 2.0)) / (double)nTaps); | ||||
| 		} | ||||
| 
 | ||||
| 		// normalize
 | ||||
| 		Real sum = 0; | ||||
| 		for(i = 0; i < (int)m_taps.size() - 1; i++) | ||||
| 
 | ||||
| 		for (i = 0; i < (int)m_taps.size() - 1; i++) { | ||||
| 			sum += m_taps[i] * 2; | ||||
| 		} | ||||
| 
 | ||||
| 		sum += m_taps[i]; | ||||
| 		for(i = 0; i < (int)m_taps.size(); i++) | ||||
| 
 | ||||
| 		for (i = 0; i < (int)m_taps.size(); i++) { | ||||
| 			m_taps[i] /= sum; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Type filter(Type sample) | ||||
| 	{ | ||||
| @ -59,8 +71,7 @@ public: | ||||
| 		m_samples[m_ptr] = sample; | ||||
| 		size = m_samples.size(); // Valgrind optim (2)
 | ||||
| 
 | ||||
| 		while (b < 0) | ||||
| 		{ | ||||
| 		while (b < 0) { | ||||
| 			b += size; | ||||
| 		} | ||||
| 
 | ||||
| @ -71,15 +82,13 @@ public: | ||||
| 			acc += (m_samples[a] + m_samples[b]) * m_taps[i]; | ||||
| 			a++; | ||||
| 
 | ||||
| 			while (a >= size) | ||||
| 			{ | ||||
| 			while (a >= size) { | ||||
| 				a -= size; | ||||
| 			} | ||||
| 
 | ||||
| 			b--; | ||||
| 
 | ||||
| 			while(b < 0) | ||||
| 			{ | ||||
| 			while(b < 0) { | ||||
| 				b += size; | ||||
| 			} | ||||
| 		} | ||||
| @ -87,8 +96,7 @@ public: | ||||
| 		acc += m_samples[a] * m_taps[i]; | ||||
| 		m_ptr++; | ||||
| 
 | ||||
| 		while(m_ptr >= size) | ||||
| 		{ | ||||
| 		while(m_ptr >= size) { | ||||
| 			m_ptr -= size; | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user