I created a GNU Radio block called "Doppler File Generator" following the Python OOT tutorial and the previous question I asked back in April. This block generates a .txt file containing two columns: timestamp and Doppler frequency correction. The file is intended to be read by another block—Doppler Correction—which applies the necessary frequency shift correction to the signal. This Doppler Correction block is part of the main flowgraph. The flowgraph structure is as follows: Osmocom Source → Doppler Correction Block (reads the generated .txt file) → Frequency Xlating FIR Filter → QT GUI Sink Ideally, when the flowgraph is executed, the Doppler File Generator block (my block) should run first to produce the .txt file, after which the rest of the flowgraph processes the signal using that file. However, this is not happening. Instead, GNU Radio executes the main flowgraph first, before the .txt file is generated. As a result, the Doppler Correction block throws an error stating that it cannot find the .txt file because the file was not generated. In the YAML configuration file, I set the init_before_blocks parameter as shown in the Python Snippet YAML example, but this still doesn't force the Doppler File Generator block to execute first. I tested the Doppler File Generator block independently in a separate flowgraph and it works correctly. So, I believe the issue lies in the flowgraph hierarchy or execution order. Below are my codes: YAML: id: customModule_DopplerFileGenerator label: Doppler File Generator category: '[customModule]' flags: [python] templates: imports: from gnuradio.customModule import DopplerFileGenerator make: DopplerFileGenerator( ${tle_line1}, ${tle_line2}, ${frequency}, ${timestamp}, ${output_file_path}) callbacks: - open(${output_file_path}) parameters: - id: section label: Section of Flowgraph dtype: string options: ['main_after_init', 'main_after_start', 'main_after_stop', 'init_before_blocks'] option_labels: ['Main - After Init', 'Main - After Start', 'Main - After Stop', 'Init - Before Blocks'] default: 'init_before_blocks' - id: priority label: Priority dtype: int default: 0 hide: ${'part' if priority <= 0 else 'none'} - id: tle_line1 label: TLE Line 1 dtype: string default: '' - id: tle_line2 label: TLE Line 2 dtype: string default: '' - id: frequency label: Frequency (Hz) dtype: float default: 0 - id: timestamp label: Timestamp (Unix Epoch) dtype: float default: 0 - id: output_file_path label: Output File Path dtype: file_save inputs: [] outputs: [] file_format: 1 The python code which generates the .txt file: #!/usr/bin/env python # -*- coding: utf-8 -*- # # SPDX-License-Identifier: GPL-3.0-or-later import scipy.constants import skyfield.api from skyfield.api import wgs84, EarthSatellite import numpy as np import datetime import os class DopplerFileGenerator: def __init__(self, tle_line1='', tle_line2='', frequency=0.0, timestamp=0.0, output_file_path=''): print("[DopplerFileGenerator] Initializing and generating Doppler file...") self.tle_line1 = tle_line1 self.tle_line2 = tle_line2 self.frequency = frequency self.timestamp = timestamp self.output_file_path = output_file_path self.compute_doppler() def compute_doppler(self): try: ts = skyfield.api.load.timescale() groundstation = wgs84.latlon(53.1111, 8.8583, 0) satellite = EarthSatellite(self.tle_line1, self.tle_line2, 'satellite', ts) unix_epoch = datetime.datetime(1970, 1, 1, tzinfo=skyfield.api.utc) t0 = unix_epoch + datetime.timedelta(seconds=float(self.timestamp)) t0 = ts.from_datetime(t0.replace(tzinfo=skyfield.api.utc)) DAY_S = 24 * 3600 t = t0 + np.arange(0, (25 * 60 + 0.1) / DAY_S, 0.1 / DAY_S) t = ts.tai_jd([s.tai for s in t]) topocentric = (satellite - groundstation).at(t) range_rate = topocentric.frame_latlon_and_rates(groundstation)[5].km_per_s * 1e3 doppler = -range_rate / scipy.constants.c * float(self.frequency) os.makedirs(os.path.dirname(self.output_file_path), exist_ok=True) with open(self.output_file_path, 'w') as output_file: for s, f in zip(t, doppler): s = (s.utc_datetime() - unix_epoch).total_seconds() output_file.write(f'{s:.3f}\t{f:.3f}\n') print(f"[DopplerFileGenerator] Output saved to {self.output_file_path}") except Exception as e: print(f"[DopplerFileGenerator] Error: {e}") So far, I have tried the following: Modified the YAML file to ensure my block executes first by setting the init_before_blocks parameter, similar to the Python Snippet block. Deleted the GNU Radio subclass from my Python code. Tried placing raw code in the python/customModule/init.py file. This works partially, but I have to enter the data manually in the code instead of configuring it through GNU Radio. Any suggestions? It works with Python Snipped block but I had to use tkinter to make the interface. I want to make it as OOT Block so it can be installed as part of GNU Radio. I am experimenting. Continue reading...