Site menu AGC no modem Python
e-mail icon
Site menu

AGC no modem Python

e-mail icon

Implementei o último bloco faltante do modem QAM escrito em Python: controle automático de ganho (AGC). Os fontes podem ser encontrados em https://epxx.co/artigos/modulation, arquivos m3*.py e gray.py. A utilidade do AGC pode ser testada e.g. mudando o volume do arquivo qam.wav usando um software como o Audacity.

O controle automático de ganho (AGC) permite ao modem adaptar-se a diferentes níveis de potência de recepção. Até agora, o modem V3 não adaptava-se ao "volume" do áudio contido no arquivo WAV; simplesmente assumia que o sinal ocupava 90% da faixa dinâmica.

A versão V2 já utilizava um medidor de amplitude extremamente primitivo, que só considerava a seqüência de cabeçalho no início da recepção. Mas um AGC de verdade adapta-se a mudanças no meio do caminho.

Isso é mais fácil de falar do que de fazer. O maior problema é que o AGC precisa descobrir qual é a faixa dinâmica, isto é, qual seria a amplitude do símbolo mais "forte" da constelação, e determinar a amplitude dos demais a partir desse máximo. Mas não há garantia nenhuma que os símbolos mais fortes vão realmente aparecer no sinal QAM. E se aparecerem, como o AGC "sabe" que são eles?

Uma solução primitiva seria mandar a seqüência de treinamento com a amplitude máxima a cada poucos segundos, o que é facilmente detectável como um trecho sem símbolos. Mas isto desperdiça largura de banda, e não é assim que funciona um modem de verdade.

A solução de verdade é trabalhar com a média móvel da amplitude absoluta recebida. É trivial calcular a amplitude média de uma constelação. Relacionando as duas médias, expressando a amplitude em termos relativos, conseguimos decodificar os símbolos.

A versão V3 utiliza uma média móvel de 1 segundo, que é rápida o suficiente para aprender com a seqüência de treinamento inicial, e adapta-se rápido o suficiente enquanto os dados estão sendo recebidos. O transmissor também foi modificado para enviar uma seqüência de treinamento na amplitude média da constelação, em vez da amplitude máxima, desta forma o AGC não precisa nem distinguir entre a fase de treinamento e a fase de dados.

Agora nós temos outro problema: será que a amplitude média de um sinal real, na saída do TX, vai coincidir com a média teórica da constelação? A teoria diz que isso vai acontecer se todos os símbolos forem igualmente prováveis. Mas os símbolos não são igualmente prováveis (o símbolo 0000...0, "tudo zero" será quase sempre o mais provável). Para resolver isso, os modems do mundo real aplicam um randomizador à seqüência de bits.

Eu fui otimista e achei que o AGC encontraria uma boa média sem randomizador, mas estva errado. O AGC simplesmente não funciona se a seqüência de bits não for embaralhada! Uma seqüência de dados típica como um arquivo-texto é extremamente monótona do ponto de vista do modem.

Assim "não por boniteza mas por precisão" implementei um randomizador bem simples para o modem V3, com um "polinomial de quarta ordem". Esta é uma forma bem pedante de afirmar que o randomizador leva em conta os últimos 4 bits para calcular o próximo bit, usando apenas o operador lógico XOR.

Para ser ainda mais pedante, até empreguei uma boa prática de programação: um teste unitário executado à guisa de auto-teste.

# Randomizer: 1 + x**-3 + x **-4

def randomize(b0):
    global b1, b2, b3, b4
    bs = b0 ^ (b3 ^ b4)
    b1, b2, b3, b4 = bs, b1, b2, b3
    return bs

def derandomize(b0):
    global b1, b2, b3, b4
    bt = b0 ^ (b3 ^ b4)
    b1, b2, b3, b4 = b0, b1, b2, b3
    return bt

rseq = [ int(random.random() * 2) for x in range(0, 25) ]
b1, b2, b3, b4 = (0, 0, 0, 0)
rseqS = [ randomize(b) for b in rseq ]
b1, b2, b3, b4 = (0, 0, 0, 0)
rseqT = [ derandomize(b) for b in rseqS ]
b1, b2, b3, b4 = (0, 0, 0, 0)

if rseqT != rseq:
    print "Randomizer is broken"
    print rseq
    print rseqS
    print rseqT
    sys.exit(1)

Este algoritmo de randomização foi copiado diretamente do livro "Modem e transmissão de dados" de Fábio Montoro. Foi engraçado constatar na prática quão importante é o randomizador na presença do AGC, mesmo sendo um randomizador primitivo (modems V.32 usam randomizadores de "grau 15").

Determinar a amplitude com base em médias, mesmo com a presença do randomizador, não é algo perfeitamente exato. Isto se traduz numa redução do número de bits que cada símbolo pode carregar. A versão V3 tinha atingido 16 bits por símbolo. Com o AGC, o máximo confiável é 12 bits.

AGC foi o último recurso previsto para a versão V3. O próximo objetivo, versão 4, adicionará recursos de resistência ao ruído.

e-mail icon