The thing was working sooner than expected, and performance went beyond my expectations. It can handle 2400 baud with a 1800Hz carrier, like faster modems used to do. It can currently handle 7 bits per symbol, which translates to 16800bps. Going beyond this will demand improvements in symbol detection, which is currently the same as V2 (which is suboptimal).
V3 modem is basically the same as V2, except by decodification of QAM into complex samples, which V2 did in a "classical" fashion (demodulation + FIR filtering), and V3 does by direct analysis of QAM signal. So, I will list only the relevant V3 RX part:
# Proof that we don't need exact carrier frequency
CARRIER += random.random() * 20 - 10
# Proof that we don't need exact carrier phase
ra = random.random() * 2 * math.pi
symbols = []
f = CARRIER * 2 * math.pi / SAMPLE_RATE
carrier_90 = SAMPLE_RATE / CARRIER / 4.0
carrier_90 = int(carrier_90)
phase_error = 2 * math.pi * CARRIER / SAMPLE_RATE / 2.0
recovered = []
for t in range(0, len(qam) - carrier_90 - 2):
# Take derivatives of now and 90 degrees in future
d = (qam[t+1] - qam[t]) / f
d90 = (qam[t + carrier_90 + 1] - qam[t + carrier_90]) / f
st = math.sin(f * t + ra)
ct = math.cos(f * t + ra)
a = d90 * ct + d * st
b = d90 * st - d * ct
try:
tphase = -b / a
phase = math.atan(tphase)
except ZeroDivisionError:
phase = math.pi / 2
if (-b * a) < 0:
phase = -phase
if (abs(d) > abs(d90)):
amplitude = -d / (st * math.cos(phase) + ct * math.sin(phase))
else:
amplitude = -d90 / (-st * math.sin(phase) + ct * math.cos(phase))
if amplitude < 0:
amplitude = -amplitude
phase += math.pi
phase += math.pi * 2
phase %= math.pi * 2
cpx = crect(amplitude, phase)
# print t, int(phase * 180 / math.pi) % 360, cpx
recovered.append(cpx)
This technique is based on the fact that QAM signal is generated by a very simple formula:
s(t) = m . cos(2πft + p)
where "m" and "p" are the polar coordinates of constellation symbol being currently transmitted. The derivative of that is also a simple formula:
s'(t) = 2πf.m.sin(2πft + p)
The QAM decoding problem is: given s(t), find the unknown variables "m" and "p". We need two samples of s'(t) which are near enough to belong to the same symbol, to make an equation system and solve for "m" and "p".
That's exactly what the piece of code listed above does. The samples are taken 90 degrees apart because the equations would simplify very nicely.
I chose the s'(t) equation instead of s(t) because the QAM signal may not be centered at zero; that is, it may have some offset, or DC component. But the difference between each sample and the next is unaffected by the offset. "Difference" in a discrete signal is equivalent to "derivative" in a continous signal.
It is important to measure samples EXACTLY 90 degrees apart, which means that the "distance" between samples must be an integer number. This implies that WAV must be a multiple of 1800 / 4 = 450 Hz. Using a WAV of 43200 Hz works beautifully, while a WAV of 45000 Hz, which is better in theory and matches carrier, will not bear more than 4 bits/symbol. 44100 Hz won't work perfectly even for 3 bits/symbol.
Maybe I have "cheated" by choosing a "perfect" WAV sampling rate, but I suspect that a real-world modem does just that. Anyway, this technique of mine is not intended to be the best in town, it is just an exercise to try to go beyond "classical" QAM. Certainly there are ways to compensate for non-perfect alignment of carrier and sampling rate,

2 comentários:
Elvis,
estou gostando muito destes seus posts recentes sobre sinais e gostaria de saber qual a bibliografia que você está usando/consultando.
Agradeço a atenção!
Minha principal fonte sobre o assunto específico é o velho livro "Modem e Transmissão de Dados", de Fábio Montoro, um dos poucos livros técnicos escritos em língua portuguesa que vale a pena ler. Em relação a processamento digital de sinais, tenho o do Proakis, Manolakis (não aconselho, é para iniciados, demorei 13 anos para começar a "tirar" alguma coisa do livro), e o "Fast Fourier Transform and Its Applications", de Brigham, um livro de encadernação muito feia, porém muito bem escrito (desse eu felizmente entendi bastante coisa).
Tem um livro novo, disponível gratuitamente na Internet mas que pretendo comprar a edição impressa por ser o melhor que já vi para explicar assuntos difíceis a não-iniciados: http://www.dspguide.com/. Pena que é um livro caro, terei de esperar um pouco para reservar parte da mesada e comprá-lo...
Especificamente sobre numpy e DSP para QAM, não encontrei praticamente nada na Internet. DSP para QAM deve ser algo que só está na cabeça dos engenheiros que já trabalham para fabricantes de modems... agora eles devem estar quebrando a cabeça com modems DSL, é claro :)
Postar um comentário