{"id":4302,"date":"2025-10-29T00:13:17","date_gmt":"2025-10-29T00:13:17","guid":{"rendered":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/?p=4302"},"modified":"2025-10-29T00:18:14","modified_gmt":"2025-10-29T00:18:14","slug":"fft-only-vs-learned-spectral-proxies-for-rapid-rf-triage","status":"publish","type":"post","link":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/?p=4302","title":{"rendered":"FFT-Only vs Learned Spectral Proxies for Rapid RF Triage"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/172-234-197-23.ip.linodeusercontent.com\/?page_id=4296\"><img data-opt-id=755548062  fetchpriority=\"high\" decoding=\"async\" width=\"474\" height=\"285\" src=\"https:\/\/ml6vmqguit1n.i.optimole.com\/w:auto\/h:auto\/q:mauto\/f:best\/https:\/\/172-234-197-23.ip.linodeusercontent.com\/wp-content\/uploads\/2025\/10\/image-39.png\" alt=\"\" class=\"wp-image-4305\" style=\"width:675px;height:auto\" srcset=\"https:\/\/ml6vmqguit1n.i.optimole.com\/w:474\/h:285\/q:mauto\/f:best\/https:\/\/172-234-197-23.ip.linodeusercontent.com\/wp-content\/uploads\/2025\/10\/image-39.png 474w, https:\/\/ml6vmqguit1n.i.optimole.com\/w:300\/h:180\/q:mauto\/f:best\/https:\/\/172-234-197-23.ip.linodeusercontent.com\/wp-content\/uploads\/2025\/10\/image-39.png 300w\" sizes=\"(max-width: 474px) 100vw, 474px\" \/><\/a><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>FFT-Only vs Tiny CNNs: Who Wins at Rapid RF Triage?<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><em>A 48\u00d7 compute win with zero deep learning \u2014 and a hybrid trick for the edge cases<\/em><\/h3>\n\n\n\n<p><strong>By Benjamin J. Gilbert<\/strong><br><em>Spectrcyde RF Quantum SCYTHE<\/em><br><a href=\"mailto:bgilbert2@com.edu\">bgilbert2@com.edu<\/a><br><a href=\"https:\/\/github.com\/bgilbert1984\/rf-triage-benchmark\">GitHub Repo + Reproducible Harness<\/a> <em>(coming soon)<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Mission: Yes\/No in Milliseconds<\/h2>\n\n\n\n<p>In spectrum monitoring, <strong>every millisecond counts<\/strong>.<br>You get a burst of IQ samples.<br>You need to answer: <strong>\u201cIs this digital or analog?\u201d<\/strong> \u2014 <em>fast<\/em>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Digital<\/strong>: BPSK, QPSK, 8PSK, 16QAM<\/li>\n\n\n\n<li><strong>Analog<\/strong>: AM, FM<\/li>\n<\/ul>\n\n\n\n<p>No time for heavy models.<br>No room for high tail latency.<\/p>\n\n\n\n<p>So we asked a heretical question:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Do we even <em>need<\/em> a neural net?<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Contenders<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Pipeline<\/th><th>Description<\/th><th>FLOPs<\/th><th>p99 Latency @ 0 dB<\/th><\/tr><\/thead><tbody><tr><td><strong>FFT + Light Filters<\/strong><\/td><td>1024-pt FFT \u2192 normalize \u2192 band energy, peak spacing, priors<\/td><td><strong>~250,000<\/strong><\/td><td><strong>~1.5 ms<\/strong><\/td><\/tr><tr><td><strong>Tiny 1D CNN<\/strong><\/td><td>3 conv layers over spectrum<\/td><td><strong>12,000,000<\/strong><\/td><td><strong>~6.0 ms<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>48\u00d7 fewer FLOPs. 4\u00d7 lower tail latency.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Results (SNR Sweep: \u201310 to +20 dB)<\/h2>\n\n\n\n<p><img data-opt-id=357116413  fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/i.imgur.com\/placeholder1.png\" alt=\"AUROC vs FLOPs\"><br>*Fig 1: FFT+filters beats the CNN in AUROC *and* compute.*<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>SNR<\/th><th>FFT+Filter AUROC<\/th><th>CNN AUROC<\/th><\/tr><\/thead><tbody><tr><td>\u201310 dB<\/td><td>0.586<\/td><td>0.529<\/td><\/tr><tr><td>0 dB<\/td><td>0.651<\/td><td>0.582<\/td><\/tr><tr><td>+20 dB<\/td><td><strong>0.754<\/strong><\/td><td><strong>0.671<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>FFT wins at every SNR.<\/strong><br>And it\u2019s <em>orders of magnitude<\/em> cheaper.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Latency: The Real Bottleneck<\/h2>\n\n\n\n<p><img data-opt-id=1203945659  data-opt-src=\"https:\/\/i.imgur.com\/placeholder2.png\"  decoding=\"async\" src=\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20100%%20100%%22%20width%3D%22100%%22%20height%3D%22100%%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22100%%22%20height%3D%22100%%22%20fill%3D%22transparent%22%2F%3E%3C%2Fsvg%3E\" alt=\"Latency vs SNR\"><br><em>Fig 2: FFT p99 stays under 1.5 ms even at 0 dB. CNN balloons.<\/em><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>At 0 dB SNR<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>FFT p99: <strong>1.5 ms<\/strong><\/li>\n\n\n\n<li>CNN p99: <strong>6.0 ms<\/strong><\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<p>In real-time triage, <strong>p99 is what kills you<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Hybrid Gate: Best of Both Worlds<\/h2>\n\n\n\n<p>What if we <strong>only use the CNN when the FFT isn\u2019t sure<\/strong>?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if fft_confidence &gt; 0.9:\n    return fft_result          # 1.5 ms, 0.25M FLOPs\nelse:\n    return cnn_result          # 6.0 ms, 12M FLOPs<\/code><\/pre>\n\n\n\n<p>Let $ f $ = fraction of samples sent to CNN.<\/p>\n\n\n\n<p>$$<br>\\boxed{<br>C_{\\text{hybrid}} = (1-f) \\cdot 0.25M + f \\cdot 12M<br>}<br>$$<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Gate Rate $ f $<\/th><th>Avg FLOPs<\/th><th>Savings vs Pure CNN<\/th><th>p99 Latency<\/th><\/tr><\/thead><tbody><tr><td>0% (FFT only)<\/td><td>0.25M<\/td><td><strong>48\u00d7<\/strong><\/td><td>1.5 ms<\/td><\/tr><tr><td><strong>20%<\/strong><\/td><td><strong>2.6M<\/strong><\/td><td><strong>4.6\u00d7<\/strong><\/td><td>~1.5 ms<\/td><\/tr><tr><td>100% (CNN only)<\/td><td>12M<\/td><td>1\u00d7<\/td><td>6.0 ms<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Even a 20% gate rate saves 4.6\u00d7 compute \u2014 and tail latency stays fast.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p><img data-opt-id=747191400  data-opt-src=\"https:\/\/i.imgur.com\/placeholder3.png\"  decoding=\"async\" src=\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20100%%20100%%22%20width%3D%22100%%22%20height%3D%22100%%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22100%%22%20height%3D%22100%%22%20fill%3D%22transparent%22%2F%3E%3C%2Fsvg%3E\" alt=\"Latency-Utility Frontier\"><br><em>Fig 5: Hybrid dominates the Pareto front.<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Confusion Matrices @ 10 dB<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>FFT+Filter (near-perfect)<\/th><th>Tiny CNN (more confused)<\/th><\/tr><\/thead><tbody><tr><td><img data-opt-id=645386278  data-opt-src=\"https:\/\/i.imgur.com\/fft-confusion.png\"  decoding=\"async\" src=\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20100%%20100%%22%20width%3D%22100%%22%20height%3D%22100%%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22100%%22%20height%3D%22100%%22%20fill%3D%22transparent%22%2F%3E%3C%2Fsvg%3E\" alt=\"FFT Confusion\"><\/td><td><img data-opt-id=1626231411  data-opt-src=\"https:\/\/i.imgur.com\/cnn-confusion.png\"  decoding=\"async\" src=\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%20100%%20100%%22%20width%3D%22100%%22%20height%3D%22100%%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22100%%22%20height%3D%22100%%22%20fill%3D%22transparent%22%2F%3E%3C%2Fsvg%3E\" alt=\"CNN Confusion\"><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>FFT misclassifies <strong>1\u20132 samples per class<\/strong>.<br>CNN leaks 8PSK \u2192 16QAM, QPSK \u2192 others.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why This Matters<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Edge SDRs<\/strong> (e.g., USRP, LimeSDR) have <strong>&lt;100 mW compute budgets<\/strong>.<\/li>\n\n\n\n<li><strong>Tail latency<\/strong> kills real-time spectrum enforcement.<\/li>\n\n\n\n<li><strong>FFT is already in your pipeline<\/strong> \u2014 it\u2019s <em>free<\/em> if you have IQ.<\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Use the FFT as your fast-path. Gate to CNN only when needed.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Reproducible. Today.<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>git clone https:\/\/github.com\/bgilbert1984\/rf-triage-benchmark\ncd rf-triage-benchmark\nmake all<\/code><\/pre>\n\n\n\n<p>Generates:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>metrics\/triage_runs.csv<\/code><\/li>\n\n\n\n<li>All figures<\/li>\n\n\n\n<li><code>paper.pdf<\/code><\/li>\n<\/ul>\n\n\n\n<p>Zero setup. Pure Python + NumPy + PyTorch.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Limitations (We\u2019re Honest)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Synthetic data<\/strong> (Rician fading, calibrated SNR).<\/li>\n\n\n\n<li><strong>Latency modeled<\/strong>, not measured on real SDR.<\/li>\n\n\n\n<li><strong>Next step<\/strong>: Validate on field IQ (Ettus X410, real clocks).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">TL;DR<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Method<\/th><th>AUROC<\/th><th>FLOPs<\/th><th>p99 @ 0 dB<\/th><th>Verdict<\/th><\/tr><\/thead><tbody><tr><td>Tiny CNN<\/td><td>0.671<\/td><td>12M<\/td><td>6.0 ms<\/td><td>Overkill<\/td><\/tr><tr><td><strong>FFT+Filters<\/strong><\/td><td><strong>0.754<\/strong><\/td><td><strong>0.25M<\/strong><\/td><td><strong>1.5 ms<\/strong><\/td><td><strong>Winner<\/strong><\/td><\/tr><tr><td><strong>Hybrid (20% gate)<\/strong><\/td><td><strong>\u22650.75<\/strong><\/td><td><strong>2.6M<\/strong><\/td><td><strong>1.5 ms<\/strong><\/td><td><strong>Best in practice<\/strong><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Want to Try It?<\/h2>\n\n\n\n<p>Star the repo. Run <code>make all<\/code>. Beat our AUROC with &lt;1M FLOPs.<\/p>\n\n\n\n<p>We dare you.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Paper<\/strong>: <a href=\"https:\/\/gilbert1984.com\/papers\/rf-triage-rev2.pdf\">FFT-Only vs Learned Spectral Proxies for Rapid RF Triage (PDF)<\/a><br><strong>Code<\/strong>: <a href=\"https:\/\/github.com\/bgilbert1984\/rf-triage-benchmark\">github.com\/bgilbert1984\/rf-triage-benchmark<\/a><br><strong>Author<\/strong>: Benjamin J. Gilbert \u2014 <em>RF heretic, latency minimalist<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><em>Originally published October 29, 2025<\/em><br><em>Follow for more edge RF + ML content.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>FFT-Only vs Tiny CNNs: Who Wins at Rapid RF Triage? A 48\u00d7 compute win with zero deep learning \u2014 and a hybrid trick for the edge cases By Benjamin J. GilbertSpectrcyde RF Quantum SCYTHEbgilbert2@com.eduGitHub Repo + Reproducible Harness (coming soon) The Mission: Yes\/No in Milliseconds In spectrum monitoring, every millisecond counts.You get a burst of&hellip;&nbsp;<a href=\"https:\/\/172-234-197-23.ip.linodeusercontent.com\/?p=4302\" rel=\"bookmark\"><span class=\"screen-reader-text\">FFT-Only vs Learned Spectral Proxies for Rapid RF Triage<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":4298,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[6,10],"tags":[],"class_list":["post-4302","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-signal-science","category-signal_scythe"],"_links":{"self":[{"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/posts\/4302","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4302"}],"version-history":[{"count":3,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/posts\/4302\/revisions"}],"predecessor-version":[{"id":4308,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/posts\/4302\/revisions\/4308"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=\/wp\/v2\/media\/4298"}],"wp:attachment":[{"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4302"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4302"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/172-234-197-23.ip.linodeusercontent.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4302"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}