Decodificando RDS do rádio FM

Decodificando RDS do rádio FM

Este artigo é uma continuação do texto "Ouvindo rádio com Python" e aborda um recurso que ainda estava faltando para um receptor de rádio 100% completo: decodificação RDS (Radio Data System).

RDS é responsável por carregar aquelas mensagens que alguns receptores FM, principalmente automotivos, exibem na tela. O RDS também carrega outros tipos de mensagem, inclusive data/hora, que o receptor pode usar para acertar o relógio local.

Recapitulando

No artigo anterior, descrevemos em detalhe como o sinal de rádio FM é demodulado. O sinal de áudio "cru" FM tem grande largura de banda, e contém muito mais que simples áudio:

Figura 1: Espectro do áudio cru de uma estação FM típica, com estéreo e RDS

O tom piloto de 19kHz é utilizado para gerar a portadora de 38kHz, na fase correta, que vai demodular o sinal estéreo.

O tom piloto também pode ajudar a decodificar o RDS, embora não seja obrigatório.

TL;DR e Claude

Para quem só quem quer o resultado final, este repositório possui tudo que é necessário para fazer RDS funcionar:

Sim, ao contrário dos artigos anteriores sobre DSP, neste eu joguei a toalha e pedi para o Claude escrever o decoder RDS, a partir de um esboço que eu tinha feito mas não estava conseguindo terminar. O esforço necessário estava além do que eu estava disposto a empregar na modalidade "just for fun".

E o Claude fez um bom trabalho: não só produziu um decoder RDS funcional, como respeitou o estilo do meu esboço, que imitava a linha do decoder FM estéreo.

Figura 2: Decodificação offline de áudio cru FM.

O script não detecta se o sinal RDS está presente ou se é forte o suficiente para ser decodificado. Um sintoma de falta de sinal RDS é a "detecção" de números PI aleatórios, sendo que PI é a identificação da estação e deveria ser sempre o mesmo.

Figura 3: Decodificação online de estação FM, aparentemente sem RDS ou com sinal muito fraco.

Modulação RDS

Na camada física, RDS é um sinal digital Manchester diferencial de 1187.5bps ou 2375 chirps/s. Os níveis de sinal são +1 e -1, portanto sempre há energia no sinal, não precisamos detectar o nível de ruído de fundo, apenas precisamos detectar se o sinal é positivo ou negativo.

O sinal de banda-base é modulado por uma portadora de 57kHz. Isto faz do RDS um código BPSK, onde a portadora é modulada em apenas dois ângulos: 0º e 180º. A taxa de bits é exatamente 1187.5bps, propositadamente igual a 57000/48 ou 19000/16. Cada bit corresponde a exatamente 16 ciclos do tom piloto.

O primeiro passo para decodificar RDS é gerar uma portadora de 57kHz no receptor. Isso pode ser feito de duas formas, e implementamos ambas:

Em qualquer caso, a portadora RDS tem de ser exatamente o triplo da frequência do tom piloto. Não basta gerar a portadora localmente e torcer que dê certo. É preciso usar o próprio sinal recebido como referência, pois cada estação e cada receptor possui um "relógio" ligeiramente diferente.

Não é requerido que a portadora RDS esteja em fase com o tom piloto. Apenas se requer que a diferença de fase seja estável. Este foi o ponto em que eu "caí do cavalo", gerando uma portadora RDS com a função cos(3t), como se fosse demodular AM-SC, quando o certo é usar uma portadora complexa cmath.exp(-3j * t).

Multiplicando o sinal RDS pela portadora complexa, temos um sinal complexo I/Q que contém a) o sinal de banda-base deslocado de uma certa fase, e b) uma cópia de alta frequência centrada em 114kHz, o resíduo indesejável de toda demodulação AM.

O decoder faz um downsampling inicial de 256000 para 19000 amostras por segundo, uma por ciclo do tom piloto. simplesmente somando as amostras de banda-base RDS ao longo de cada ciclo completo do tom piloto. Isto não borra o sinal (cujo bitrate é muito menor que 19000) mas elimina o resíduo de alta frequência de forma simples e barata, sem ter de aplicar mais um filtro.

Neste ponto, temos um sinal de banda-base complexo, idealmente com apenas dois valores distintos, um 180º defasado do outro. Por ser modulação BPSK, só importa a fase, não importa o valor absoluto, o que torna tudo mais simples. (Decodificação PSK é conceitualmente semelhante à demodulação FM analógica.)

Se o sinal estivesse em fase com a nossa portadora de 57kHz, esses valores seriam +1 e -1. Porém, não está. Se, por exemplo, o deslocamento for de 90º, os valores observados seriam +i e -i. Precisamos detectar o deslocamento de fase e descontar seu efeito, a fim de converter o sinal para valores reais +1 e -1.

Usar o valor absoluto das amostras complexas não funcionaria aqui, pois ao fazer isso perderíamos a informação de fase (tudo viraria +1, não haveria mais -1). Extrair valor absoluto é análogo a um detector de diodo, que só pode ser empregado onde a fase não importa, como em rádio AM comercial e demodulação OOK.

O Claude implementou esta parte de fora muito elegante, usando um truque matemático para detectar a fase. É possível que a deteção de fase cometa um erro de 180º, produzindo amostras -1 que deveriam ser +1 e vice-versa, mas isto não é problema pois Manchester diferencial é imune a inversão de polaridade.

Além disso, aproveitando o fato que a fase do RDS é estável, o deslocamento de fase é determinado por uma média móvel, para que ruídos espúrios não façam o decoder perder a fase de vista.

Banda-base RDS

Neste ponto, temos um sinal +1/-1 com uma taxa de 19000 amostras por segundo. Isto dá 16 amostras por bit, ou 8 bits de amostra por "chirp" Manchester. Precisamos recuperar o clock, ou seja, descobrir onde cada bit começa e termina.

...---++++++++--------++++++++----------------+++++++++++...
      | chirp | chirp | chirp | chirp | chirp | chirp |
      |     bit 0     |     bit 1     |     bit 2     |

Na codificação Manchester, cada bit é codificado como dois "chirps", +1/-1 ou -1/+1. Como temos 16 amostras por bit, significa que temos (idealmente) 8 amostras positivas e 8 amostras negativas por bit. Dentro de um bit, a soma aritmética de todas as amostras tende a zero.

Desta forma, o algoritmo básico de recuperação de clock é determinar em que ponto a soma aritmética de 16 amostras produz o menor resultado possível.

O algoritmo poderia ser enganado por chirps de bits adjacentes. No exemplo acima, a soma do segundo chirp do bit 0 com o primeiro chirp do bit 1 também é zero. Porém, somar dois chirps de bits diferentes só resulta zero em 50% das vezes, enquanto somar dois chirps do mesmo bit sempre dá zero, 100% das vezes.

Para esta heurística 50%/100% funcionar, é importante que os bits 0 e 1 sejam igualmente prováveis. O fato de quase metade de cada bloco RDS ser composto por bits CRC (vide adiante) ajuda a garantir isso.

Agora sabemos onde começa cada bit, e podemos fazer novo downsample para 2 amostras por bit:

... | +1 -1 | +1 -1 | -1 +1 | ...
    | bit 0 | bit 1 | bit 2 | 

Como se trata de um sinal Manchester diferencial, sabemos que o bit é 1 quando seu código chirp é diferente do bit anterior. Então, no exemplo acima, o bit 1 é igual a 0, enquanto o bit 2 é igual a 1. Não podemos determinar o bit 0 pois, no exemplo, não sabemos o que havia antes dele.

O bloco RDS

Cada quadro ou bloco RDS é composto de 26 bits, sendo 16 bits úteis e 10 bits CRC. A detecção do início do bloco é feita com base no checksum CRC, de forma semelhante ao protocolo ATM.

Se o CRC estiver correto em determinado ponto da sequência de bits, temos sincronismo provisório. Se continuar correto nos blocos seguintes, o sincronismo é confirmado. O sincronismo é considerado perdido quando o CRC estiver errado em "n" blocos seguidos (na nossa implementação, 10).

O código CRC pode ser usado para correção de erros, porém muitas implementações usam-no exclusivamente para detectar erros e blocos.

O RDS possui quatro tipos de bloco: A, B, C e D. Eles são transmitidos em sequência, formando um grupo. Além do CRC correto, o sincronismo testa se os blocos estão aparecendo na sequência esperada.

O grupo RDS

Como dito, um conjunto de quatro blocos A+B+C+D forma um grupo. O bloco A sempre identifica a estação. O bloco B sempre identifica o tipo de grupo. Os blocos C e D costumam carregar o "payload" e seu formato varia conforme o tipo de grupo.

Devido à enorme redundância do protocolo RDS, sua capacidade de transmissão de textos gira em torno de 50 caracteres por segundo, ainda menos do que sugere a taxa de 1187.5bps. Além disso, a transmissão de uma simples palavra pode consumir diversos grupos RDS, pois cabem apenas 2 ou 4 caracteres por grupo, a depender do tipo.

Existem inúmeros tipos de grupos RDS, há inclusive alguns cuja informação é encriptada e depende de pagamento de assinatura para ser interpretável.

Fora isso, a estação FM transmite um subconjunto arbitrário de grupos, e seu receptor FM sabe interpretar outro subconjunto arbitrário. Mesmo que seu receptor acerte a hora do relógio em função do RDS, não quer dizer que sua rádio predileta transmita essa informação. (Deveria transmitir, mas não é o caso.)