Regarding the FIR filter in the RTL-SDR dongle, from the librtlsdr.c file that obj linked to above, I guess in order to change the filter coefficients (taps) you would just change the following:
static const int fir_default[FIR_LEN] = {
-54, -36, -41, -40, -32, -14, 14, 53, /* 8 bit signed */
101, 156, 215, 273, 327, 372, 404, 421 /* 12 bit signed */
};
Note that FIR_LEN is 16 and is half the filter length (32) as it says in the comment. The filter is symmetrical (even number of taps).
The freq response shows a gain of approximately 70 dB at DC. The gain at DC is just the sum of the taps which is 4238 or 72.5 dB. I would think that is normalized somewhere in the RTL-SDR implementation.
It took me a while to work out how to compile stream1090 on macOS - for anyone else doing this, you need to edit CMakeLists.txt and add full paths to the compilers before the project line.
@JRG1956 No it will never stop. You will get some indicator that it has closed down by looking at the bounds.
# ==================== END OF RUN ====================
# Time: 2026-01-21 22:13:51
# Instance: ../../samples/balcony_6M_5.raw
# FS: 6.0 MHz → FS_UP: 12.0 MHz
# Number of taps: 15
# Best params: [-0.3599117653819717, 1.235708371398938, -0.8997009318804052, 0.7212277112049269, -0.25219918068664177]
# Best ext-squitter count: 12070
# Best message count: 10564
# Current bounds:
# [-0.396989, -0.296989]
# [1.192245, 1.292245]
# [-0.940674, -0.840674]
# [0.664777, 0.764777]
# [-0.296020, -0.196020]
# Best taps:
-0.0019240524852648377
0.049912694841623306
0.037688665091991425
0.017241165041923523
0.03471251204609871
0.026454921811819077
0.2121589183807373
0.2475104182958603
0.2121589183807373
0.026454921811819077
0.03471251204609871
0.017241165041923523
0.037688665091991425
0.049912694841623306
-0.0019240524852648377
It is currently hard coded that the upper and lower bounds are 0.1 apart. The above example is one of those, where it has narrowed down things (the bounds have closed in). You can safely stop it or restart it by putting the best parameters into the python file:
The problem is with the compiler it uses - when I tried make I got errors:
jrg@MBPro2021 build % cmake ../ -DEND_STATS=ON
-- The C compiler identification is AppleClang 17.0.0.17000603
-- The CXX compiler identification is AppleClang 17.0.0.17000603
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Build type not specified: defaulting to release.
-- Configuring done (2.8s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/build
jrg@MBPro2021 build % make
[ 16%] Building CXX object CMakeFiles/stream1090.dir/main.cpp.o
clang++: warning: argument '-Ofast' is deprecated; use '-O3 -ffast-math' for the same behavior, or '-O3' to enable only conforming optimizations [-Wdeprecated-ofast]
In file included from /Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/main.cpp:12:
In file included from /Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/SampleStream.hpp:16:
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/DemodCore.hpp:491:31: error: non-constexpr declaration of 'currTimeTo12MhzTimeStamp' follows constexpr declaration
491 | inline uint64_t DemodCore<8>::currTimeTo12MhzTimeStamp() {
| ^
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/DemodCore.hpp:449:21: note: previous declaration is here
449 | constexpr uint64_t currTimeTo12MhzTimeStamp() {
| ^
I decided to try GCC. (Note I know very little about compilers, so this was just my usual trial and error approach tp problem solving.)
I pushed some fixes to the repo that hopefully fixes the issues with clang. Make sure that you do a proper rebuild with cmake ../ --fresh in the build directory.
Thanks - for each new version in the repository, I always rename the stream1090 directory and start from scratch. Just have to copy any files I have added to the new stream1090 directory.
Out of interest, was the problem that Apple’s gcc is version 17?
I saw that the raspberry pi was using gcc14 and the deprecated warning mode me think I needed an earlier version, so that led me to gcc15 in Homebrew.
While searching for the error in the console log I came across this:
jrg@MBPro2021 build % brew install gcc
✔︎ JSON API cask.jws.json Downloaded 15.3MB/ 15.3MB
✔︎ JSON API formula.jws.json Downloaded 32.0MB/ 32.0MB
Warning: gcc 15.2.0 is already installed and up-to-date.
To reinstall 15.2.0, run:
brew reinstall gcc
jrg@MBPro2021 build % gcc --version
Apple clang version 17.0.0 (clang-1700.6.3.2)
Target: arm64-apple-darwin25.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
I realise that I was wrongly thinking clang was a non gcc compiler, but it is.
Should I expect to see any change in results with the newer version?
Uhhh now i have to reactivate old brain cells. So i am trying not to spread misinformation. If i remember correctly, there is a gcc interface for clang/llvm. You can compile c++ code with clang by using a gcc like interface. The underlying compiler however is not gcc, it is clang with plenty of apple spice in there.
I was a bit sloppy with the rules of the c++ standard and clang complained while gcc did not. You can have a look if the clang code is quicker or not. Earlier versions of stream1090 were actually a bit quicker using clang on a raspberry pi 5 (which of course you can do).
I did some runs yesterday and give some feedback on the filter optimisation. Running on my Mac reduced the processing time per iteration, so I decided to use my 48G raw sample (72GB file size) for these tests too.
The optimised filter provides about a 0.5% improvement over the previous best result I’ve seen for the sample. Here is a summary including performance against the airspy_adsb benchmark.
The results seem to make sense to me. The objective function favours long messages, especially ADS-B. This will also pull up DF-11 messages, because stream1090 requires these besides DF-17 to keep entries alive. If you are able to use the big sample sets, well good for you. This will reflect better the behaviour of stream1090. Running something like 500MB with 10Msps will mostly ignore any timeouts in stream1090’s plane cache and stuff like that.
I forgot to add that I also tried using the seed from the optimised filter to do a further optimisation. This came up with a slightly better result on the 4th iteration, with no better result over 24 total iterations.
I’m happy to run large samples - as you say, they are more representative of real world performance. Now that I can test on the Mac, the time to test is much reduced and I can probably reduce it further by moving the tests to a Mac mini M4 that I only use view streamed material on my TV. It is the base model, but the single core performance of the M4 exceeds that of the M1 Pro chip in the MacBook, and it spends most of its time idle.
Once I get that set up, I will record some new large samples - that will let me test if relative performance remains the same across different samples with different traffic densities and distance/altitude distributions.
I haven’t had a chance to run the new make code yet. Will report when I do.
Apologies for bombarding you with messages this morning.
I’ve just tried compiling with the latest version - still one error:
jrg@MBPro2021 build % cmake ../ -DEND_STATS=ON
-- The C compiler identification is AppleClang 17.0.0.17000603
-- The CXX compiler identification is AppleClang 17.0.0.17000603
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Build type not specified: defaulting to release.
-- Configuring done (1.0s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/build
jrg@MBPro2021 build % make
[ 16%] Building CXX object CMakeFiles/stream1090.dir/main.cpp.o
In file included from /Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/main.cpp:12:
In file included from /Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/SampleStream.hpp:17:
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/MathUtils.hpp:38:25: error: constexpr variable 'iq_sqrt_table' must be initialized by a constant expression
38 | inline constexpr auto iq_sqrt_table{ fillSqrtTable() };
| ^ ~~~~~~~~~~~~~~~~~~~
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/MathUtils.hpp:18:4: note: constexpr evaluation hit maximum step limit; possible infinite loop?
18 | return (curr == prev) ? curr : constSqrtNR(x, 0.5 * (curr + x / curr), curr);
| ^
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/MathUtils.hpp:18:35: note: in call to 'constSqrtNR(7.762245e-01, 8.881123e-01, 7.762245e-01)'
18 | return (curr == prev) ? curr : constSqrtNR(x, 0.5 * (curr + x / curr), curr);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/MathUtils.hpp:31:85: note: in call to 'constSqrtNR(7.762245e-01, 7.762245e-01, 0.000000e+00)'
31 | table[(static_cast<std::array<float, 65536>::size_type>(i) << 8) | q] = (float)constSqrtNR(sq, sq, 0.0);
| ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/jrg/SynologyDrive/Scratch/Aircraft Tracking Notes/Stream1090_Dev/stream1090/include/MathUtils.hpp:38:40: note: in call to 'fillSqrtTable()'
38 | inline constexpr auto iq_sqrt_table{ fillSqrtTable() };
| ^~~~~~~~~~~~~~~
1 error generated.
make[2]: *** [CMakeFiles/stream1090.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/stream1090.dir/all] Error 2
make: *** [all] Error 2
I am always thankful for this feedback. I maintained some c++ library for some years for the apple eco system. And these are the annoying things. Since my rig is nvidia based, i had to retire OS X.
Edit: i hope the current repo version compiles now.
Thanks for continuing to share all of your work and especially the filter tools @mgrone ! I finally had a chance to toy with this a bit today, and I’m not sure I’m following the results or if I’m going about this the wrong way.
Ran my 15 minute example (yes, smaller sample file as a first choice would have been smarter) against the Python script and let it run for ~11 hours while I was at work. Got the taps from the output and created a filter file.
Then included my custom filter, but the results were actually slightly lower. Not sure if I’m missing something but expect a change in the stats to be higher and not lower?
Haha. You are unlucky. You are the only one in this forum thread who has to compete against a default filter in the repo that was exactly fitted for you. I optimized the default for you. Your instance gave me nightmares before, so it was a challenge to get results for your instance (that you provided to me) back on track. You should really not doing this filter optimization. I did that for you for multiple days and also fine tuned it.
If you want to plot your filter against the default, remove the colon “,” from the stuff in LowPass.hpp and all the c++ crap and paste it into a new textfile.
Ahh, I didn’t know that - thanks so much for doing this! The default filters are fantastic as they are now, even outperforming my airspy_adsb binary by quite a bit, but my nerd brain is always looking to push the envelope. I even toyed with the python script to make it run on all my cpu cores instead of just the one.
One curious, maybe remedial, question for you on this. My guess is that a hardware change in my ADS-B rig could affect the results here. Is that reasonable? My RTLSDR Triple Filter died a couple of weeks ago (there was a moment of silence, a burial in my backyard, and maybe even a tear lol) after years of faithful service. Now that I’m back up and running, could capturing a different sampleset produce different results? My guess is yes, but I’m fine if you answer with “Why not try it for yourself.”
Thank you again for all your work on this, mgrone!