Criei um bloco Python que recebe cinco entradas do usuário e gera um arquivo .txt contendo registros de data e hora na coluna 1 e dados de desvio Doppler na coluna 2 com base nas entradas.
As duas primeiras entradas são elementos de duas linhas, a terceira é a frequência de um CubeSat, a quarta é um registro de data e hora e a última especifica o destino do arquivo onde o arquivo .txt será armazenado, semelhante ao bloco "File Sink".
Por exemplo, no bloco padrão "File Sink" do GNU Radio, clicar nos três pontos abre uma janela para navegar e selecionar o destino final do arquivo. No entanto, não consegui replicar esse comportamento no meu código.
Além disso, é possível executar este bloco antes que todo o fluxograma comece ao clicar em "Executar o fluxograma"?
Exemplo: Etapa 1. Entrada 1: "1 49263U 21088D 24308.92471420 .00079255 00000+0 26750-2 0 9998"
Entrada 2: "2 49263 97.4796 14.7363 0010511 313.1417 46.8944 15.30328253170926"
Entrada 3: 437.250e6
Entrada 4: 1730713098
Entrada 5: ---clique nos três pontos para abrir o navegador de arquivos e salvar o arquivo---
Etapa 2. Clique em "Executar o fluxograma" ---executa o bloco python antes do fluxograma principal---
import scipy.constants
import skyfield.api
from skyfield.api import wgs84, EarthSatellite
import numpy as np
import datetime
from tkinter import filedialog
import tkinter as tk
from gnuradio import gr
class DopplerBlock(gr.sync_block):
def __init__(self, tle_line1='', tle_line2='', frequency=0, timestamp=0):
gr.sync_block.__init__(
self,
name='Doppler Shift Generator',
in_sig=None,
out_sig=None
)
self.tle_line1 = tle_line1
self.tle_line2 = tle_line2
self.frequency = frequency
self.timestamp = timestamp # User-provided timestamp
self.ts = skyfield.api.load.timescale()
self.groundstation = wgs84.latlon(53.1111, 8.8583, 0) # ESTEC ground station
self.output_file_path = self.get_file_path()
def get_file_path(self):
"""Opens a file dialog to let the user choose a file."""
root = tk.Tk()
root.withdraw() # Hide the root window
file_path = filedialog.asksaveasfilename(title="Select file to save data")
return file_path if file_path else None
def compute_doppler(self):
if not self.tle_line1 or not self.tle_line2:
raise RuntimeError("Both TLE lines must be provided.")
satellite = EarthSatellite(self.tle_line1, self.tle_line2, 'satellite', self.ts)
unix_epoch = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
t0 = unix_epoch + datetime.timedelta(seconds=self.timestamp)
t0 = self.ts.from_datetime(t0)
# Generate time steps
duration_s = 25 * 60 # 25 minutes in seconds
time_steps = np.arange(0, duration_s, 0.1) # Every 0.1 sec
t = t0 + time_steps / (24 * 3600) # Convert seconds to fractional days
# Compute Doppler shift
topocentric = satellite.at(t).observe(self.groundstation)
_, _, range_rate = topocentric.apparent().velocity.km_per_s
range_rate *= 1e3 # Convert to m/s
doppler_shift = -range_rate / scipy.constants.c * self.frequency
# Save to file if path is provided
if self.output_file_path:
with open(self.output_file_path, 'w') as output_file:
for time, shift in zip(time_steps, doppler_shift):
output_file.write(f'{self.timestamp + time}\t{shift}\n')
def work(self, input_items, output_items):
"""This block does not process streaming signals, so work does nothing."""
return 0
Esse não é o comportamento do seu código python, mas é especificado no arquivo YAML que define o bloco; tutorial explicando isso . Se você ainda não fez isso, vale a pena ler os tutoriais em https://tutorials.gnuradio.org de "O que é GNU Radio" a "Criando um OOT (exemplo de bloco Python)" em ordem linear; escrevemos tudo isso pensando em usuários como você :)
Você pode encontrar o arquivo YAML "Definição de bloco" do File Sink no link abaixo da página de documentação do bloco ; procure
dtype:
no primeiro elemento deparameters:
.Acho que já mencionei isso antes, mas você definitivamente não quer uma subclasse real de
gr.block
se não estiver fazendo processamento de sinal. E, novamente, nenhuma criação de interface gráfica de usuário em seus próprios blocos :)Para executar um código python antes de começar, uma maneira fácil é usar o bloco Python Snippet no GNU radio. Selecione
section of Flow graph
paraAfter Init
ouAfter Start
conforme necessário. Coloque o código paraCode Snippet
https://wiki.gnuradio.org/index.php/Python_Snippet