viernes, 8 de marzo de 2019

Transceptor de señales débiles, bit a bit (Parte 4)

A poco de operar wsjtx con la configuración que se viene discutiendo se hacen obvios algunos
problemas. El primero es que la "ganancia" del receptor implementado con rtl_fm no parece ser mucha, el segundo es que no se ha implementado una forma de transmitir con wsjtx y al intentar hacerlo con la baliza basada en WsprryPi que se discutiera previamente aparecen problemas prácticos y de protocolo.
Un truco útil a ésta altura es poder probar si el dongle RTL-SDR es correctamente reconocido por la placa, normalmente podemos ver cuando todo está funcionando un patrón de recepción de señales bien distintivo en el "waterfall" de wsjt-x, pero como en todo sistema que tiene muchos componentes es bueno tener alguna forma de ir partiendo el problema en pedazos manejables, aqui se puede usar el comando "rtl_test" el cual revisa que el dongle funciona correctamente, es bueno hacerlo antes de seguir experimentando.

Usando rtl_sdr (método #2)

El método recomendado por el artículo ya referenciado "Tutorial: Setting up a Low Cost QRP (FT8, JT9, WSPR etc) Monitoring Station with an RTL-SDR V3 and Raspberry Pi 3" [link] usa un método de recepción diferente, usando diferentes programas, y uno empieza a sospechar que quizás hay algún motivo por el cual lo hace así.
Este método involucra varios programas nuevos que la configuración anterior no usaba, ncat ("network cat") y en particular una pequeña joya llamada csdr.
El enfoque es un poco diferente, empieza por otro programa disponible en el paquete rtl-sdr (no hay que bajar ni compilar el paquete de vuelta) que se llama rtl_sdr justamente (notar que es con guion bajo "_" en lugar de alto "-") y opera en forma mas primitiva si se quiere que rtl_fm, de hecho no realiza ningún intento de demodular la señal. Básicamente entrega las muestras "crudas" tal como salen del dongle RTL-SDR, las que tienen que ser procesadas para que, finalmente, puedan ser digeridas por wsjtx. Entonces todo lo que antes "rtl_fm" hacía por dentro hay que hacerlo por fuera.
Los scripts, son dos ahora y  lucen asi:

El "receptor" propiamente dicho

#!/bin/sh
rtl_sdr -s 1200000 -f 14100000 -D 2 - \
    | csdr convert_u8_f  \
    | ncat -4l 4952 -k --send-only --allow 127.0.0.1  &

El decodificador SSB será:

#!/bin/sh
FX=$(python -c "print float(14100000-14095600)/1200000")
ncat -v 127.0.0.1 4952 \
     | csdr shift_addition_cc $FX \
     | csdr fir_decimate_cc 25 0.05 HAMMING \
     | csdr bandpass_fir_fft_cc 0 0.5 0.05 \
     | csdr realpart_cf \
     | csdr agc_ff \
     | csdr limit_ff \
     |csdr convert_f_s16 \
    | mplayer -nocache -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio - &

exit 0

Es interesante entender la estructura de éstos dos scripts y su rol en la operación como receptor.
Hay que empezar diciendo que el paquete csdr es un procesador DSP simplificado (pero extremadamente potente) escrito Andras Retzler (HA7ILM) como parte de su tesis de grado/maestría [link] donde cada operación puede ser implementada por conversiones simples donde el "flujo" de entrada viene por "standard input", la operación a realizar indicada por el argumento con que se llama a csdr y el resultado puesto en "standard output". De esa manera opera con una filosofía similar a la de los procesadores DSP nativos, donde el flujo de señal digitalizada fluye en forma continua y es sometida a distintos procesamientos en respectivas colas de entrada/salida.
El primer script "lee" desde el dongle con una tasa de muestreo de 1200000 muestras/segundo y los entrega al siguiente paso donde csdr convierte las muestras I/Q (en formato 8 bits unsigned) a punto flotante para poder aplicar sobre los mismos algoritmos de procesamiento digital, a continuación coloca el resultado en una cola implementada con un socket TCP/IP por medio del utilitario ncat. La especificación dada a ncat hace que éste sea en una dirección y puerto de modo que solo otro proceso en la misma máquina pueda leerlo. El símbolo "&" al final del comando comanda que el mismo quede ejecutando en el background en forma permanente.
En otro script separado ocurre el resto del procesamiento, como se dijo, debe correr en la misma placa (dirección IP 127.0.0.1). Primero se lee la corriente de datos de punto flotante generados en el paso anterior, lo que vuelve a hacer el programa ncat. Luego la señal es sujeta a varias manipulaciones, que para cualquier familiarizado con el proceso digital de señales rápidamente identifica como los necesarios para demodular SSB por el método de la rotación de fase. La señal es desplazada, diezmada, filtrada, limitada en su amplitud por un sistema AGC y finalmente convertida de vuelta desde formato de punto flotante a 16 bits con signo, que es como los "stream" de audio son representados.
Al final del proceso, y como se hacía en el script anterior, es el reproductor multimedia mplayer el encargado de reproducir el audio demodulado. Como en el caso anterior el comando se lanza a ejecutar en el "background" mediante la indicación "&".
Hay algunos elementos a considerar. El primero es que la recepción no se hace en la frecuencia que deseo escuchar sino un poco desplazado (en éste caso 14.100 MHz), eso es para que la señal que queremos escuchar no caiga justo en el "cero" del cálculo digital, en el demulador se corrige ese efecto por la diferencia entre el primero y la frecuencia que se desea escuchar (14.0956 MHz en el ejemplo, frecuencia de WSPR). Para tomar en otra frecuencia (dentro de +/- 24 KHz del oscilador local del RTL-SDR) solo hay que alterar el 2do script. En el script están marcados con distintos colores los números que están relacionados y deben cambiarse en forma conjunta.
Hay varias otras particularidades que vale la pena detenerse. La primera es porque canalizar todo el flujo de datos por un socket mediante ncat, en definitiva se graba y lee en la misma máquina, porque no hacer "ducto" (piping) desde un procesamiento de csdr al otro sin pasar por ncat, y hacerlo todo en un solo script. Hay buenas razones para hacerlo así; he encontrado al menos dos, y es posible que existan mas.
La primera es que, como expliqué en el caso de mplayer, hay una acción de "buffer" que suaviza el flujo de multimedia y lo hace mas parejo. El segundo, mas importante, es que para que los algoritmos de la segunda parte funcionen necesitan datos. Y el programa "rtl_sdr" tarda un par de segundos (una eternidad) en comenzar a funcionar, de esa forma el segundo script termina "anormalmente" por "broken pipe" (ducto roto) por no tener datos si se lo arranca demasiado rápido. La forma de trabajar es lanzar el primer script y luego que éste comenzó a operar hacerlo con el segundo.
Si bien ambos script tienen "&" al final y se lanzan el el background para las pruebas es quizás útil arrancarlos y detenerlos, o que es muy facil con Ctl-C si están en una sesión normal pero que requiere un par de comandos para hacerlo si están en el background como por ejemplo sudo pkill o "pgrep | kill".  Por eso mientras se prueba puede ser conveniente abrir sendas ventanas de un procesador bash (terminal) y lanzar cada script en la suya.
Esta sincronización en el arranque, trivial de hacer a mano pero que no es tan trivial hacerla en forma automática puede automatizarse mediante un script receiver  el que usa un truco mediante una pipe para lanzar el primer script y quedarse observando su salida hasta que aparece en ella un texto que indica que completó su arranque para solo entonces lanzar el segundo.
Una vez lanzados ambos script puede observarse en el panel de pavucontrol que está disponible mplayer como fuente de una corriente (stream) de datos multimedia, el cual, como en el caso anterior, se puede asociar a un extremo del cable virtual, pudiendo asociar el otro extremo a wsjt-x.
Integración feliz, sistema estable. consumo de CPU y memoria es muy modesto, en un RBPi de 4 núcleos típicamente habrá uno de ellos usado al 25-35% en la máquina que corre wsjt-x. Es necesario monitorear la temperatura y quizás sea conveniente disponer de un pequeño ventilador, el conjunto entre el procesador haciendo cálculos continuamente y el calor mismo del dongle RTL-SDR hace que la temperatura de la placa RBPi opere entre 65 y 75 °C, dentro de limites seguros, pero si la temperatura ambiente no coopera puede fácilmente superar los 80-85 °C que si ya representan un problema.La configuración es estable, efectiva, se mantiene operando si no existen inconvenientes con buena disponibilidad y el consumo de CPU es modesto tanto en recepción como en transmisión. Es posible automatizar el lanzamiento de todo el conjunto cuando se arranca la máquina de forma que cada vez que se lance el GUI también se lance el script "receiver" y al programa wsjtx.
Voila!! wsjtx estará recibiendo señales WSPR! O en FT8 cambiando donde dice 14095600 por 14074000.

No hay comentarios:

Publicar un comentario