GNU Radio Glowgraph on dedispersion


📡 GNU Radio Dedispersion Flowgraph (ASCII)

+----------------------+
| Signal/File Source   |
| (SDR or IQ file)     |
+----------+-----------+
           |
           v
+------------------------------+
| Frequency Xlating FIR Filter |
| (tune + decimate)            |
+--------------+---------------+
               |
               v
+------------------------------+
| PFB Channelizer              |
| (split into N channels)      |
+--------------+---------------+
               |
               v
+------------------------------+
| Stream to Vector             |
| (length = N channels)        |
+--------------+---------------+
               |
               v
+------------------------------+
| Dedispersion Block           |
| (Python: per-channel delay)  |
+--------------+---------------+
               |
               v
+------------------------------+
| Vector to Stream             |
+--------------+---------------+
               |
               v
+------------------------------+
| Channel Sum (Adder)          |
| (collapse to time series)    |
+--------------+---------------+
               |
        +------+-+
        |        |
        v        v
+-----------+  +----------------+
| QT Scope  |  | File Sink      |
| (visual)  |  | (save output)  |
+-----------+  +----------------+

🧠 Dedispersion Core Idea (ASCII)

Dispersion delay:

delta_t = 4.15e3 * DM * (f^-2 - f_ref^-2)   [ms]

Convert to samples:

delay_samples = delta_t * sample_rate

Each channel is delayed differently, then aligned and summed.


🧩 Key Block Notes

Signal Source

- SDR (Osmocom / SDRplay)
OR
- File Source (complex64)

Frequency Xlating FIR

Purpose:
- Shift desired band to baseband
- Reduce sample rate

Typical:
- Decimation: 2–10
- LPF cutoff: ~bandwidth/2

PFB Channelizer

Block: pfb.channelizer_ccf

Splits wideband signal into:

[ f1 ][ f2 ][ f3 ] ... [ fN ]

Typical N:
- 64
- 128
- 256

Stream to Vector

Input: scalar stream
Output: vectors of length N

Each vector = one time sample across all frequencies

Dedispersion Block (core logic)

Pseudo-ASCII logic:

for each time sample:
    for each channel:
        delayed_sample = buffer[channel][delay[channel]]
    output aligned vector

Channel Sum

sum = ch1 + ch2 + ch3 + ... + chN

Result:
- Dedispersed time series

⚙️ Parameters

Channels (N):        64–256
Bandwidth:           1–10 MHz
Sample rate:         depends on SDR
DM range:            0–500 pc/cm^3
Time resolution:     ms scale

🧪 Usage Notes

1. Frequency Array

Must match channelizer:

freqs = linspace(f_low, f_high, N)

2. Tradeoffs

More channels:
    + Better dedispersion
    - More CPU load

3. Real-Time vs Offline

Real-time:
    - Fewer channels
    - Smaller bandwidth

Offline:
    + More accurate
    + Easier debugging

4. DM Search

for DM in range(0, 500):
    run dedispersion
    check for peaks

5. Performance Tips

- Precompute delays
- Use NumPy arrays
- Keep buffers fixed size

6. With Interferometry (your setup)

Two approaches:

Option A:
    correlate -> dedisperse

Option B (advanced):
    dedisperse per channel -> correlate

🚀 Minimal Working Order

1. Record IQ data
2. Channelize
3. Apply dedispersion
4. Sum channels
5. Look for pulses


🧩 1. GNU Radio Companion (.grc) Flowgraph (text you can import)

Save this as dedispersion_flowgraph.grc and open in GNU Radio Companion.

<?xml version="1.0"?>
<flow_graph>
  <block>
    <key>options</key>
    <param><key>id</key><value>dedispersion_flowgraph</value></param>
  </block>

  <!-- VARIABLES -->
  <block>
    <key>variable</key>
    <param><key>id</key><value>samp_rate</value></param>
    <param><key>value</key><value>2e6</value></param>
  </block>

  <block>
    <key>variable</key>
    <param><key>id</key><value>nchan</value></param>
    <param><key>value</key><value>128</value></param>
  </block>

  <!-- FILE SOURCE -->
  <block>
    <key>blocks_file_source</key>
    <param><key>file</key><value>/path/to/iq_data.c64</value></param>
    <param><key>type</key><value>complex</value></param>
    <param><key>repeat</key><value>False</value></param>
  </block>

  <!-- THROTTLE (for file playback) -->
  <block>
    <key>blocks_throttle</key>
    <param><key>sample_rate</key><value>samp_rate</value></param>
  </block>

  <!-- CHANNELIZER -->
  <block>
    <key>pfb_channelizer_ccf</key>
    <param><key>numchans</key><value>nchan</value></param>
  </block>

  <!-- STREAM TO VECTOR -->
  <block>
    <key>blocks_stream_to_vector</key>
    <param><key>num_items</key><value>nchan</value></param>
    <param><key>type</key><value>float</value></param>
  </block>

  <!-- PYTHON DEDISPERSION BLOCK -->
  <block>
    <key>embedded_python_block</key>
    <param>
      <key>source_code</key>
      <value>
import numpy as np
from gnuradio import gr

class blk(gr.sync_block):
    def __init__(self, dm=50.0, nchan=128, samp_rate=2e6):
        gr.sync_block.__init__(self,
            name="dedisperse",
            in_sig=[(np.float32, nchan)],
            out_sig=[(np.float32, nchan)])

        freqs = np.linspace(1400e6, 1420e6, nchan)
        f_ref = np.max(freqs)

        k = 4.15e3
        delays = k * dm * (freqs**-2 - f_ref**-2)
        self.delays = np.round(delays * 1e-3 * samp_rate).astype(int)

        self.buffers = [np.zeros(abs(d)+1) for d in self.delays]

    def work(self, input_items, output_items):
        inp = input_items[0]
        out = output_items[0]

        for i in range(len(inp)):
            vec = inp[i]
            aligned = np.zeros_like(vec)

            for ch in range(len(vec)):
                buf = self.buffers[ch]
                buf = np.append(buf, vec[ch])
                aligned[ch] = buf[-self.delays[ch]]
                self.buffers[ch] = buf[-len(buf):]

            out[i] = aligned

        return len(out)
      </value>
    </param>
  </block>

  <!-- VECTOR TO STREAM -->
  <block>
    <key>blocks_vector_to_stream</key>
    <param><key>num_items</key><value>nchan</value></param>
    <param><key>type</key><value>float</value></param>
  </block>

  <!-- ADDER -->
  <block>
    <key>blocks_add_xx</key>
    <param><key>type</key><value>float</value></param>
    <param><key>num_inputs</key><value>nchan</value></param>
  </block>

  <!-- QT TIME SINK -->
  <block>
    <key>qtgui_time_sink_f</key>
    <param><key>size</key><value>1024</value></param>
    <param><key>samp_rate</key><value>samp_rate</value></param>
  </block>

</flow_graph>

🚀 2. Extended FRB / Pulse Detection Pipeline

Here’s a more complete search pipeline built on top of that flowgraph.


📡 Full Signal Chain (ASCII)

[ IQ Source ]
      |
      v
[ Channelizer ]
      |
      v
[ Dedispersion ]
      |
      v
[ Channel Sum ]
      |
      v
[ Moving Average ]
      |
      v
[ Threshold Detector ]
      |
      +------> [ Trigger Log ]
      |
      v
[ Waterfall Display ]

🧠 Additional Blocks to Add

1. Moving Average (Noise Reduction)

Block: blocks.moving_average_ff
Length: 10–100 samples

Purpose:

  • Smooth noise
  • Improve SNR

2. Power Detection

If needed:

complex → magnitude^2

Block:

blocks.complex_to_mag_squared

3. Threshold Detector

Simple approach:

if signal > mean + N*sigma → trigger

GNU Radio option:

blocks.threshold_ff

Typical:

low  = 0.5
high = 2.0   (tune experimentally)

4. Event Logger (Python Block)

if sample > threshold:
    print("Pulse detected at time:", n)

Better:

  • Write timestamps to file
  • Save short data snippet

5. Waterfall (Frequency-Time)

Add:

QT GUI Waterfall Sink

Before dedispersion:

  • See dispersion sweep

After:

  • Verify alignment

🔍 DM Search Extension

To detect unknown sources:

Option A: Manual Sweep

Run flowgraph multiple times with different DM

Option B: Parallel Dedispersion

[Channelizer]
     |
     +--> [DM=10] \
     +--> [DM=20]  >--> compare outputs
     +--> [DM=30] /

⚡ Performance Scaling

For your kind of setup:

Small test

Channels: 64
BW: 1 MHz

Serious FRB hunting

Channels: 256–1024
BW: 5–20 MHz
GPU recommended

🧪 Practical Workflow

1. Record IQ (wideband)
2. Visualise waterfall (confirm dispersion)
3. Tune DM manually
4. Enable detection threshold
5. Log candidates

🛰️ Nice Upgrade Paths

If you want to push this further:

  • ✅ Coherent dedispersion (phase correction)
  • ✅ GPU dedispersion (CuPy / CUDA)
  • ✅ Real-time candidate clustering
  • ✅ Multi-DM heatmap display
  • ✅ Integration with your interferometer baseline

By Admin

Leave a Reply

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.