sábado, 30 de marzo de 2019

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

La estrategia utilizada hasta ahora para ir implementando las distintas piezas es mas o menos repetitiva. Para la cadena receptora se comienza con las muestras que entrega un dongle RTL-SDR, el cual abarca un ancho de banda de mas o menos 600 KHz (podría hacerselo mas grande de ser necesario) y con distintos trucos para manipular la señal con bloques SDR se vá por un lado recortando el ancho de banda a unos pocos cientos de Hz o unos pocos KHz por un lado y se vá de modulando la señal que nos interesa. No tenemos por ahora una implementación tan general como es un receptor, pero estamos haciendo los distintos pedazos para que eventualmente podamos operar en cualquier modo, en cualquier frecuencia. Una vez que tenemos el equivalente a una señal de audio digitalizada la podemos mandar a un auricular (y escucharla) o mediante un cable virtual a otro programa (y decodificarla). Para los modos digitales en general se hará lo último. Para los modos digitales de baja señal en general se utilizará el programa WSJT-X y para los modos digitales mas convencionales el FLDIGI; pero nada impide con las adaptaciones del caso utilizar cualquier programa que pueda ser alimentado con la salida de una placa de sonido, como lo haríamos con un transceiver convencional. En ocasiones pienso que tener los distintos modos sueltos e irlos conectando para distintas implementaciones no es muy diferente a cuando construimos un transceiver físico, módulo por módulo y trabajándolo sobre la mesa de trabajo para asegurarnos que anda y poder hacer mediciones fáciles. Normalmente pasa bastante tiempo ante que ponemos todo en una caja bonita (o no tanto, depende de la habilidad de cada cual) y por supuesto nos olvidamos completamente del proyecto pues ya estamos en otro igual o mas divertido.
Para la cadena transmisora hacemos algo parecido, solo que recorremos la cadena en sentido opuesto; empezamos con algo que genera audio (o, siendo mas general, una señal a modular) digitalizado, lo capturamos con un cable virtual en otro programa y lo vamos tratando con distintos procesamientos de la señal hasta que tenemos una "banda base" modulada y la aplicamos entonces al programa rpitx.
Hasta ahora de la salida de rpitx se puede optar por salir directamente a la antena con un filtro pasabajos simple (10 mW aprox.), poner un filtrado mas robusto y algo de amplificador (100 mW aprox) o ya a partir de alli tratar de alimentar una cadena de transmisión mas potente. Como en todo proyecto interesante es casi imposible evitar que a cada paso que damos se abran ramas diferentes que son igualmente interesantes y que estamos seguros nos darían un enorme placer experimentar. Solo algunas para concretar el punto, estas técnicas básicas con muy pocas modificaciones pueden usarse para hacer un repetidor de FM, o un transponder lineal como el que utilizan los satélites, o balizas para globos, o emisores de TV analógica y digital, o trabajar en packet APRS, o ... bueno, creo que se entiende. Por otra parte la integración de hardware, tema que no tiene tanto interés para mi pues estoy mas inclinado a la experimentación basada en software; por ejemplo con una sola placa pequeña (una Raspberry Pi Zero, por ejemplo) se puede potenciar un emisor de FM o uno de SSB canalero para transformarlo en uno multimodo, multibanda, por ejemplo.
Como quiera que sea hasta ahora he mostrado como implementar una baliza WSPR, una baliza FT8 y una baliza en CW; le ha llegado el turno a otros modos. Empezando por PSK31.
Este modo es bastante popular, su comportamiento con señales bajas no supera al CW, pero si lo hace con el SSB por lo que a iguales potencias se puede comunicar mejor con igual propagación, su complejidad técnica para implementarlo es baja y puede hacerse con virtualmente cualquier transceiver de SSB con una PC relativamente modesta. Hay bastantes programas para generarlo pero los mas habituales son MixW, MMVARI y FLDIGI para el mundo Windows y en el mundo Linux FLDIGI tiene una implementación muy potente (que eventualmente sirve para Packet).
Este último puede construirse para la placa Raspberry Pi, como siempre la secuencia es larga y es necesario hacerla con cuidado y sin olvidarse nada por lo que es útil usar scripts para eso; en éste caso para los pre-requisitos, la bajada y la construcción propiamente dicha. Los pasos son:

Bajar los paquetes e instalar los pre-requisitos (link).
Construir fldigi (link)
Construir flrig (link).
Construir flxmlrpc (link).

Antes que nada hay que revisar si en el primer script se están bajando los paquetes del último nivel disponible pues cambian continuamente, si se detectan cambios hay que hacer los ajustes de nombres en los subsiguientes paquetes.
La ejecución puede hacerse con  la misma técnica utilizada hasta aquí para WSJT-X, es decir alimentarlo con un cable virtual, extraer su modulación con otro cable virtual y procesar ambas cadenas con bloques constructivos SDR. Detalles de implementación de lado las cadenas SDR a utilizar son idénticas a las ya vistas.
Esta configuración con FLDIGI es suficientemente robusta como para hacer QSO con ella; sin embargo no es práctico generar una señal de baliza utilizandola. Primero porque es pesado levantar y bajar la aplicación cada vez que se lo hace, en segundo lugar porque requiere una placa mas grande sin ningún propósito útil y finalmente por no es completamente sencillo automatizar todo el proceso. Una baliza lo que necesita es una forma simple de enviar un texto fijo, o al menos un texto que se pueda construir dinámicamente como se mostró en la entrada anterior para el caso de FT8 o CW.
Para lograrlo empezamos con un "transceiver de ssb genérico" virtualizado mediante el siguiente script ssb.sh (link).

arecord -c1 -r48000 -D default -fS16_LE - | csdr convert_i16_f \
  | csdr fir_interpolate_cc 2 | csdr dsb_fc \
  | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff \
  | sudo /home/pi/rpitx/sendiq -i /dev/stdin -s 96000 -f "$1" -t float

Esta cadena ya se usó y explicó en entradas anteriores, pero básicamente se comienza por una señal de audio digitalizada y se la vá procesando para generar una señal de SSB por el método de rotación de fase para finalmente cuando están disponibles las señales I/Q respectivas emitirlas mediante rpitx. Nótese que éste script requiere ser ejecutado indicando la frecuencia en Hz de emisión (ej. ./ssb.sh 14097000").
Para generar la "banda base" con la señal de PSK31 ya modulada volvemos a recurrir al utilitario para SDR csdr quien tiene todas las funciones necesarias para hacerlo; el script correspondiente es PSK.sh (link).

#!/bin/sh
#*-----------------------------------------------------------------*
#* tx_PSK31
#* Experimental PSK31/SSB generator
#*
#* tx_PSK31.sh FREQ [in Hz] "MESSAGE"
#*-----------------------------------------------------------------*
#f="14097000"
echo "***********************************************"
echo "* PSK Generator                               "*
echo "***********************************************"
echo "Freq=$1 Message=$2"
f="$1"
echo "Starting SSB Generator at $f"
mkfifo pskfork || exit
/home/pi/whisper/ssb.sh $f 2> pskfork &
pid1=$!
while read line; do
  case $line in
    *high_cut*) echo "$line"; echo "found KEY=high_cut"; break;;
    *) echo "$line";;
  esac
done < pskfork

echo "Removing FIFO buffer"
rm -f pskfork  2>&1 > /dev/null

m="$2"
echo "Sending message frame($m)"

echo $(echo -n "$m") |
csdr psk31_varicode_encoder_u8_u8 | \
csdr differential_encoder_u8_u8 | \
csdr psk_modulator_u8_c 2 | \
csdr gain_ff 0.25 | \
csdr psk31_interpolate_sine_cc 256 | \
csdr shift_addition_cc 0.125 | \
csdr realpart_cf | \
csdr convert_f_s16 | \
mplayer -cache 1024 -quiet \
     -rawaudio samplesize=2:channels=1:rate=8000 -demuxer rawaudio - & 

echo "Waiting for termination"
sleep 20

echo "cleaning up processes"
sudo killall mplayer 2>&1 > /dev/null
sudo kill $pid1  2>&1 > /dev/null
sudo killall csdr  2>&1 > /dev/null
#sudo killall arecord  2>&1 > /dev/null
#sudo killall sendiq  2>&1 > /dev/null

exit 0

El script hace varias cosas y puede lucir confuso por lo que lo explico en partes; el segmento que genera PSK31 es el siguiente:

...
echo $(echo -n "$m") |
csdr psk31_varicode_encoder_u8_u8 | \
csdr differential_encoder_u8_u8 | \
csdr psk_modulator_u8_c 2 | \
csdr gain_ff 0.25 | \
csdr psk31_interpolate_sine_cc 256 | \
csdr shift_addition_cc 0.125 | \
csdr realpart_cf | \
csdr convert_f_s16 | \
mplayer -cache 1024 -quiet \
     -rawaudio samplesize=2:channels=1:rate=8000 -demuxer rawaudio - & 
...

El segmento empieza con la presentación de un texto a ser emitido el cual se entrega a una función de csdr llamada psk31_varicode_encoder_u8_u8 que como su nombre lo indica genera el patrón de bits a ser modulado, seguido de una función que hace la codificación diferencial (differential_encoder_u8_u8) y finalmente la modulación PSK propiamente dicha (psk_modulator_u8_c) que transforma la señal desde una codificación digital de 8 bits a una compleja de punto flotante ya modulada. El resto de los pasos se corresponden con el tratamiento de la señal en términos de su ganancia, las transiciones de potencia y la conversión al formato y tasa de muestreo final que requiere mplayer para generar el "sonido" final.
Notese que este segmento comienza con el texto y emite los sonidos "a la nada", estará de nuestra parte luego mediante pavucontrol conectar la salida del programa mplayer a uno de los extremos de un cable virtual (por ej. Virtual0) tal como, me repito, se hacía en WSJT-X en entregas anteriores.
Hay que hacer algunos trucos adicionales porque en los casos anteriores se conectaba la salida de un script con otra aplicación que estaba corriendo por separado y aquí, ambas aplicaciones parecen correr juntas... Eso es un poco la función del resto del script.
Al comenzar se llama al script ssb.sh y se lo ejecuta en el trasfondo (background), pero no es posible comenzar con la parte moduladora si el transmisor no está andando, basta una fracción de segundo de diferencia para que uno de los dos no funcione bien. Por eso el script genera un pipe (pskfork) donde se pone la salida que va emitiendo ssb.sh y mediante un loop redireccionado de ese pipe (a continuación) se controla que aparezca alguno de los mensajes que podemos esperar cuando ya está listo, tras lo cual borra el pipe y continúa invocando al segmento que genera PSK31.
Para que funcionen correctamente ambos pedazos (el transceptor y el generador PSK31) son lanzados como procesos en el background, por lo que a continuación el script se queda esperando un tiempo suficiente para que el mensaje sea emitido correctamente en PSK31, pasado el cual se eliminan todos los scripts que están corriendo antes de terminar. El tiempo de espera es suficiente para un texto cualquier de aproximadamente medio renglón, si fuera mas corto o mas largo puede reducirse o aumentarse en forma correspondiente el retardo.


No hay comentarios:

Publicar un comentario