Hello people,
in some experiments with my RTL2832 stick, I managed to find out how the FIR filter works. The FIR filter is running at the XTAL frequency (typically 28.8MHz). In the SDR mode, the filter is a symmetric FIR filter with 32 real-number-valued taps. Using the symmetry, only 16 coefficients need to be specified. The coefficients are stored in the 20 bytes written to the FIR register. The first coefficient describes the outermost tap, the last one the tap 0.5 taps away from the symmetry axis. The first 8 values are 8-bit numbers, the second 8 values are 12 bit numbers, resulting in 64 + 96 = 160 bits (20 bytes).
The first 8 bytes written to the chip are the first 8 coefficients. The 12-bit coefficients are stored like this pairwise in three bytes: In the byte sequence "12 34 56", the first coefficient is 0x123 and the second coefficient is 0x456. Both the 8-bit and the 12-bit numbers are to be interpreted as two's complement signed numbers (thus the 8-bit coefficients range from -128 to +127, while the 12-bit coefficients range from -2048 to +2047). The resolution of all 16 coefficients is the same.
I furthermore found out that this is not the only filtering going on in the RTL2832 chip in SDR mode. There seems to be a second anti-aliasing filter before the DAC, making signals disappear that are at frequencies above 0.7 times the sample rate (in the baseband), even if the programmable FIR filter lets them pass.
As an example, I provide the decoded default coefficients:
-54 -36 -41 -40 -32 -14 14 53 101 156 215 273 327 372 404 421 421 404 372 327 273 215 156 101 53 14 -14 -32 -40 -41 -36 -54
This filter has a quite flat passband in the interesting range for DAB (-768kHz..+768kHz) but by far not enough attenuation at 1280kHz (which will alias to 768kHz at a sampling rate of 2048kHz) to get satisfactory adjacent channel rejection. The experimentally observed alias rejection is good enough, which lead to the conclusion that there is another low-pass filter, which might be part of the resampling unit.
Regards, Michael Karcher
Hi Michael,
On Sat, Jul 14, 2012 at 09:23:20PM +0200, Michael Karcher wrote:
in some experiments with my RTL2832 stick, I managed to find out how the FIR filter works. [...]
congratulations, it's really great to see that this has been figured out. Thanks for sharing your results.
... and seeing that you're from a fu-berlin.de address: Did you consider joining our Osmocom Berlin User Group meetings at some point? (http://openbsc.osmocom.org/trac/wiki/OsmoUserGroup/Berlin)
[my apologies if you've already been there and I don't remember the name...]
Regards, Harald
2012/7/14 Michael Karcher osmosdr@mkarcher.dialup.fu-berlin.de:
I furthermore found out that this is not the only filtering going on in the RTL2832 chip in SDR mode. There seems to be a second anti-aliasing filter before the DAC, making signals disappear that are at frequencies above 0.7 times the sample rate (in the baseband), even if the programmable FIR filter lets them pass.
That's probably an effect of the E4000 output filter. You can see the filter bandwidth being set in the tuner initalization code.
Am Sonntag, den 15.07.2012, 01:22 +0200 schrieb Francesco Gugliuzza:
2012/7/14 Michael Karcher osmosdr@mkarcher.dialup.fu-berlin.de:
I furthermore found out that this is not the only filtering going on in the RTL2832 chip in SDR mode. There seems to be a second anti-aliasing filter before the DAC, making signals disappear that are at frequencies above 0.7 times the sample rate (in the baseband), even if the programmable FIR filter lets them pass.
That's probably an effect of the E4000 output filter. You can see the filter bandwidth being set in the tuner initalization code.
Good point, but actually, I am sure it is not an effect of the tuner output filter. My USB stick contains a fc0012 tuner, which is always set to 6MHz bandwidth. The bandwidth of the suspected anti-alias filter changes clearly when I change the sample rate, though, on the other hand, if I manipulate the FIR coefficients to contain sharp dips in the range of hundred kHz, the dip position does not change when I change the sample rate. This makes me cofident that the suspected anti-alias filter has to be located in or after the resampling unit.
Regards, Michael Karcher
2012/7/15 Michael Karcher osmosdr@mkarcher.dialup.fu-berlin.de:
Good point, but actually, I am sure it is not an effect of the tuner output filter. My USB stick contains a fc0012 tuner, which is always set to 6MHz bandwidth. The bandwidth of the suspected anti-alias filter changes clearly when I change the sample rate, though, on the other hand, if I manipulate the FIR coefficients to contain sharp dips in the range of hundred kHz, the dip position does not change when I change the sample rate. This makes me cofident that the suspected anti-alias filter has to be located in or after the resampling unit.
The only thing I can think of now is the raised cosine filter used in digital modulation receivers, but IMHO that should be implemented in the FIR filter.
Hello Michael,
Am 14.07.2012 21:23, schrieb Michael Karcher:
This filter has a quite flat passband in the interesting range for DAB (-768kHz..+768kHz) but by far not enough attenuation at 1280kHz (which will alias to 768kHz at a sampling rate of 2048kHz) to get satisfactory adjacent channel rejection. The experimentally observed alias rejection is good enough, which lead to the conclusion that there is another low-pass filter, which might be part of the resampling unit.
I've got a passband of nearly 2MHz with the original coefficients. Did I miss a factor 2 somewhere? I tried to construct a narrower filter using the gnuradio function.
Here is a python script to construct the FIR register and plot the frequency response. Maybe the script is also helpful to you.
Regards, Stefan
Am Sonntag, den 15.07.2012, 01:59 +0200 schrieb Stefan Sydow:
Hello Michael,
This filter has a quite flat passband in the interesting range for DAB (-768kHz..+768kHz) but by far not enough attenuation at 1280kHz (which will alias to 768kHz at a sampling rate of 2048kHz) to get satisfactory adjacent channel rejection. The experimentally observed alias rejection is good enough, which lead to the conclusion that there is another low-pass filter, which might be part of the resampling unit.
I've got a passband of nearly 2MHz with the original coefficients. Did I miss a factor 2 somewhere? I tried to construct a narrower filter using the gnuradio function.
No, I don't think you missed a factor of 2. I get a -3dB bandwidth of 1.2MHz, and the stopband rejection of -35dB indeed starts at around 2MHz. The actual required DAB range (768kHz) has a flatness of 0.55dB, if I calculated all the stuff correctly.
Here is a python script to construct the FIR register and plot the frequency response. Maybe the script is also helpful to you.
Thanks for the script, just some minor notes: SAMP_RATE should be 28.8e6, not 28e6. Also you don't seem to do any overflow checking on the conversion. If you are trying to build narrow filters, I expect you might hit the 1/16 limit on the outer 8 coefficients, so the filter coefficients might need to be shrunk (reducing the filter gain, of course) before converting to integers.
I'm afraid that constructing a filter using gnuradio firdes and then truncating it to 32 coefficients is likely not resulting in a good filter. In my oppinion (not backed by math knowledge in that area, though), the filter length should already be considered during coefficient generation.
It looks like your plot uses the convention that 10dB is a factor of 10. As the filter affects amplitude values and not power values, you should use 20dB for a factor of 10, if I understand the dB scale correctly.
Regards, Michael Karcher
Hi Michael,
Thanks for the script, just some minor notes: SAMP_RATE should be 28.8e6, not 28e6. Also you don't seem to do any overflow checking on the conversion. If you are trying to build narrow filters, I expect you might hit the 1/16 limit on the outer 8 coefficients, so the filter coefficients might need to be shrunk (reducing the filter gain, of course) before converting to integers.
Good point. Thanks
I'm afraid that constructing a filter using gnuradio firdes and then truncating it to 32 coefficients is likely not resulting in a good filter. In my oppinion (not backed by math knowledge in that area, though), the filter length should already be considered during coefficient generation.
Yes that's right. Using gnuradio firdes was a first hack with acceptable error as the fft shows. A better way is to use sinc() and a window function. Had a look into my "Signale and Systeme" script.
There is also a software called winfilter if you want a 'classic' filter. It works well under wine. http://www.winfilter.20m.com/
It looks like your plot uses the convention that 10dB is a factor of 10. As the filter affects amplitude values and not power values, you should use 20dB for a factor of 10, if I understand the dB scale correctly.
I missed that too. A fix version is attached.
Regards, Stefan