Simulated effects of IF filter bandwidth.
This commit is contained in:
		
							parent
							
								
									13219ed6ba
								
							
						
					
					
						commit
						4619295d9a
					
				
							
								
								
									
										35
									
								
								NOTES.txt
								
								
								
								
							
							
						
						
									
										35
									
								
								NOTES.txt
								
								
								
								
							|  | @ -8,8 +8,9 @@ Valid sample rates | ||||||
| 
 | 
 | ||||||
| Sample rates between 300001 Hz and 900000 Hz (inclusive) are not supported. | Sample rates between 300001 Hz and 900000 Hz (inclusive) are not supported. | ||||||
| They cause an invalid configuration of the RTL chip. | They cause an invalid configuration of the RTL chip. | ||||||
|   rsamp_ratio = 28.8 MHz * 2**22 / sample_rate | 
 | ||||||
|   If bit 27 and bit 28 of rsamp_ratio are different, the RTL chip malfunctions. | rsamp_ratio = 28.8 MHz * 2**22 / sample_rate | ||||||
|  | If bit 27 and bit 28 of rsamp_ratio are different, the RTL chip malfunctions. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Behaviour of RTL and Elonics tuner | Behaviour of RTL and Elonics tuner | ||||||
|  | @ -54,6 +55,36 @@ Elonics IF filters: matched to sample rate (note this may not be optimal) | ||||||
| RTL AGC mode off | RTL AGC mode off | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | Effect of IF signal filtering | ||||||
|  | ----------------------------- | ||||||
|  | 
 | ||||||
|  | Carson bandwidth rule: | ||||||
|  |   IF_half_bandwidth = peak_freq_devation + modulating_freq | ||||||
|  | 
 | ||||||
|  | In case of broadcast FM, this is | ||||||
|  |   75 kHz + 53 kHz = 128 kHz  (worst case) | ||||||
|  |   19 kHz + 53 kHz =  72 kHz  (typical case) | ||||||
|  | 
 | ||||||
|  | Simulations of IF filtering show: | ||||||
|  |  * narrow IF filter reduces noise in the baseband | ||||||
|  |  * narrow IF filter causes gain roll-off for high modulating frequencies | ||||||
|  |  * narrow IF filter causes harmonic distortion at high modulating deviation | ||||||
|  | 
 | ||||||
|  | IF filter with 100 kHz half-bandwidth: | ||||||
|  |  * baseband gain >= -1 dB up to 75 kHz | ||||||
|  |  * less than 0.1% distortion of modulating signal at 19 kHz peak deviation | ||||||
|  |  * ~ 2% distortion of modulating signal at 75 kHz peak devation | ||||||
|  | 
 | ||||||
|  | IF filter with 75 kHz half-bandwidth: | ||||||
|  |  * baseband gain ~ -3 dB at 60 kHz, ~ -8 dB at 75 kHz | ||||||
|  |  * ~ 1% distortion of modulating signal at 19 kHz peak deviation | ||||||
|  | 
 | ||||||
|  | Optimal IF bandwidth is probably somewhere between 75 and 100 kHz, with | ||||||
|  | roll-off not too steep. | ||||||
|  | Weak stations benefit from a narrow IF filter to reduce noise. | ||||||
|  | Strong stations benefit from a wider IF filter to reduce harmonics. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| Effect of settings on baseband SNR | Effect of settings on baseband SNR | ||||||
| ---------------------------------- | ---------------------------------- | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								TODO.txt
								
								
								
								
							
							
						
						
									
										3
									
								
								TODO.txt
								
								
								
								
							|  | @ -1,4 +1,4 @@ | ||||||
| * (experiment) make nice plot of baseband distortion due to IF filtering | * (experiment) consider reducing IF filter bandwidth to ~ 80 kHz | ||||||
| * (experiment) consider downsampling IF signal before FM detection | * (experiment) consider downsampling IF signal before FM detection | ||||||
| * (experiment) measure effect of IF gain on baseband SNR | * (experiment) measure effect of IF gain on baseband SNR | ||||||
| * (experiment) measure effect of IF gain linearity on baseband SNR | * (experiment) measure effect of IF gain linearity on baseband SNR | ||||||
|  | @ -6,7 +6,6 @@ | ||||||
| * (experiment) try if RTL AGC mode improves FM decoding | * (experiment) try if RTL AGC mode improves FM decoding | ||||||
| 
 | 
 | ||||||
| * (feature) support 'M' 'k' suffixes for sample rates and tuning frequency | * (feature) support 'M' 'k' suffixes for sample rates and tuning frequency | ||||||
| * (feature) implement off-line FM decoder in Python for experimentation |  | ||||||
| * (feature) implement stereo pilot pulse-per-second | * (feature) implement stereo pilot pulse-per-second | ||||||
| * (speedup) maybe replace high-order FIR downsampling filter with 2nd order butterworth followed by lower order FIR filter | * (speedup) maybe replace high-order FIR downsampling filter with 2nd order butterworth followed by lower order FIR filter | ||||||
| * figure out why we sometimes lose stereo lock | * figure out why we sometimes lose stereo lock | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								pyfm.py
								
								
								
								
							
							
						
						
									
										19
									
								
								pyfm.py
								
								
								
								
							|  | @ -295,7 +295,7 @@ def pilotLevel(d, fs, freqshift, nfft=None, bw=150.0e3): | ||||||
|     return (p19db, guarddb, guarddb - p19db) |     return (p19db, guarddb, guarddb - p19db) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def modulateAndReconstruct(sigfreq, sigampl, nsampl, fs, noisebw=None, ifbw=None, ifnoise=0): | def modulateAndReconstruct(sigfreq, sigampl, nsampl, fs, noisebw=None, ifbw=None, ifnoise=0, ifdownsamp=1): | ||||||
|     """Create a pure sine wave, modulate to FM, add noise, filter, demodulate. |     """Create a pure sine wave, modulate to FM, add noise, filter, demodulate. | ||||||
| 
 | 
 | ||||||
|     sigfreq     :: frequency of sine wave in Hz |     sigfreq     :: frequency of sine wave in Hz | ||||||
|  | @ -305,6 +305,7 @@ def modulateAndReconstruct(sigfreq, sigampl, nsampl, fs, noisebw=None, ifbw=None | ||||||
|     noisebw     :: calculate noise after demodulation over this bandwidth |     noisebw     :: calculate noise after demodulation over this bandwidth | ||||||
|     ifbw        :: IF filter bandwidth in Hz, or None for no filtering |     ifbw        :: IF filter bandwidth in Hz, or None for no filtering | ||||||
|     ifnoise     :: IF noise level |     ifnoise     :: IF noise level | ||||||
|  |     ifdownsamp  :: downsample factor before demodulation | ||||||
| 
 | 
 | ||||||
|     Return (ampl, phase, noise) |     Return (ampl, phase, noise) | ||||||
|     where ampl  is the amplitude of the reconstructed sine wave (~ sigampl) |     where ampl  is the amplitude of the reconstructed sine wave (~ sigampl) | ||||||
|  | @ -325,18 +326,24 @@ def modulateAndReconstruct(sigfreq, sigampl, nsampl, fs, noisebw=None, ifbw=None | ||||||
| 
 | 
 | ||||||
|     # Filter IF. |     # Filter IF. | ||||||
|     if ifbw is not None: |     if ifbw is not None: | ||||||
|         b  = scipy.signal.firwin(61, 2.0 * ifbw / fs, window='nuttall') |         b  = scipy.signal.firwin(101, 2.0 * ifbw / fs, window='nuttall') | ||||||
|         fm = scipy.signal.lfilter(b, 1, fm) |         fm = scipy.signal.lfilter(b, 1, fm) | ||||||
|         fm = fm[61:] |         fm = fm[61:] | ||||||
| 
 | 
 | ||||||
|  |     # Downsample IF. | ||||||
|  |     fs1 = fs | ||||||
|  |     if ifdownsamp != 1: | ||||||
|  |         fm = fm[::ifdownsamp] | ||||||
|  |         fs1 = fs / ifdownsamp | ||||||
|  | 
 | ||||||
|     # Demodulate. |     # Demodulate. | ||||||
|     sig1 = quadratureDetector(fm, fs=fs) |     sig1 = quadratureDetector(fm, fs=fs1) | ||||||
| 
 | 
 | ||||||
|     # Fit original sine wave. |     # Fit original sine wave. | ||||||
|     k = len(sig1) |     k = len(sig1) | ||||||
|     m = numpy.zeros((k, 3)) |     m = numpy.zeros((k, 3)) | ||||||
|     m[:,0] = numpy.sin(2*numpy.pi*sigfreq/fs * (numpy.arange(k) + nsampl - k)) |     m[:,0] = numpy.sin(2*numpy.pi*sigfreq/fs1 * (numpy.arange(k) + nsampl - k)) | ||||||
|     m[:,1] = numpy.cos(2*numpy.pi*sigfreq/fs * (numpy.arange(k) + nsampl - k)) |     m[:,1] = numpy.cos(2*numpy.pi*sigfreq/fs1 * (numpy.arange(k) + nsampl - k)) | ||||||
|     m[:,2] = 1 |     m[:,2] = 1 | ||||||
|     fit = numpy.linalg.lstsq(m, sig1) |     fit = numpy.linalg.lstsq(m, sig1) | ||||||
|     csin, ccos, coffset = fit[0] |     csin, ccos, coffset = fit[0] | ||||||
|  | @ -350,7 +357,7 @@ def modulateAndReconstruct(sigfreq, sigampl, nsampl, fs, noisebw=None, ifbw=None | ||||||
|     res1   = sig1 - m[:,0] * csin - m[:,1] * ccos |     res1   = sig1 - m[:,0] * csin - m[:,1] * ccos | ||||||
| 
 | 
 | ||||||
|     if noisebw is not None: |     if noisebw is not None: | ||||||
|         b  = scipy.signal.firwin(61, 2.0 * noisebw / fs, window='nuttall') |         b  = scipy.signal.firwin(101, 2.0 * noisebw / fs1, window='nuttall') | ||||||
|         res1 = scipy.signal.lfilter(b, 1, res1) |         res1 = scipy.signal.lfilter(b, 1, res1) | ||||||
| 
 | 
 | ||||||
|     noise1 = numpy.sqrt(numpy.mean(res1 ** 2)) |     noise1 = numpy.sqrt(numpy.mean(res1 ** 2)) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue