supongo que esto es probablemente demasiado tarde para ayudar a usted (lo que acabaste haciendo arriba?) Pero puede ayudar al individuo siguiente.
Aquí está un ejemplo golfed de un bucle de software de sincronización de fase que acabo de escribir en una línea de C, que cantará junto con usted:
main(a,b){for(;;)a+=((b+=16+a/1024)&256?1:-1)*getchar()-a/512,putchar(b);}
presento esta pequeña versión golfed primero con el fin de convencer a usted que los bucles de fase de bloqueo de software son en realidad bastante simples, como dice el software, aunque pueden ser complicados.
Si alimenta muestras lineales de 8 bits en stdin, producirá muestras de 8 bits de una onda de diente de sierra que intente seguir una octava más alta en stdout. A 8000 muestras por segundo, rastrea las frecuencias en el vecindario de 250Hz, justo por encima de B por debajo de la mitad C. En Linux puede hacer esto escribiendo arecord | ./pll | aplay
. Los 9 bits bajos de b
son el oscilador (lo que podría ser un VCO en una implementación de hardware), que genera una onda cuadrada (1 o -1) que se multiplica por la forma de onda de entrada (getchar()
) para producir la salida de la fase detector. Esa salida se filtra paso bajo en a
para producir la señal de error de fase suavizada que se usa para ajustar la frecuencia de oscilación de b
para empujar a
hacia 0. La frecuencia natural de la onda cuadrada, cuando a == 0
, es para b
aumentar 16 cada muestra, que lo incrementa en 512 (un ciclo completo) cada 32 muestras. 32 muestras a 8000 muestras por segundo son 1/250 de segundo, por lo que la frecuencia natural es de 250Hz.
Luego putchar()
toma los 8 bits bajos de b
, que conforman una onda de diente de sierra a 500Hz aproximadamente, y los arroja como salida de audio.
hay varias cosas que faltan en este sencillo ejemplo:
No tiene buena manera de detectar el bloqueo. Si tiene silencio, ruido o un tono fuerte de entrada de 250Hz, a será aproximadamente cero yb oscilará a su frecuencia predeterminada. Dependiendo de su aplicación, es posible que desee saber si ha encontrado una señal o no. La sugerencia de Camenzind en el capítulo 12 de Designing Analog Chips es alimentar un segundo detector de fase 90 ° fuera de fase del detector de fase real; su salida suavizada te da la amplitud de la señal teóricamente bloqueada.
La frecuencia natural del oscilador es fija y no barre. El rango de captura de un PLL, el intervalo de frecuencias dentro del cual notará una oscilación si no está actualmente bloqueado en uno, es bastante estrecho; su rango de bloqueo , sobre el que se extenderá para seguir la señal una vez que está bloqueado, es mucho más grande. Debido a esto, es común barrer la frecuencia del PLL en todo el rango donde espera encontrar una señal hasta que obtenga un bloqueo, y luego deje de barrer.
La versión golfed anterior se le deduce de una much more readable example of a software phase-locked loop in C que escribí hoy, que sí hace la detección de bloqueo pero no barrer. Necesita alrededor de 100 ciclos de CPU por muestra de entrada por PLL en la CPU Atom en mi netbook.
Creo que si estuviera en su situación, haría lo siguiente (aparte de cosas obvias como buscar a alguien que sepa más sobre procesamiento de señal que yo y generar datos de prueba). Probablemente no filtre y reduzca la señal en una interfaz, ya que ya está en una frecuencia tan baja. La conversión descendente a una banda de 200Hz-400Hz apenas parece necesaria. Sospecho que PSK traerá algunos problemas nuevos, ya que si la señal cambia repentinamente de fase en 90 ° o más, pierde el bloqueo de fase; pero sospecho que esos problemas serán fáciles de resolver, y es territorio poco conocido.
He hecho una pregunta relacionada en http://dsp.stackexchange.com/questions/8456/how-to-perform-carrier-phase-recovery-in-software – Keith