Я предполагаю, что это, вероятно, слишком поздно, чтобы помочь вам (то, что вы в конечном итоге делает?), Но это может помочь следующий парень.
Вот golfed пример цикла программного обеспечения фазовой автоподстройки я просто писал в одной строке C, который будет петь вместе с вами:
main(a,b){for(;;)a+=((b+=16+a/1024)&256?1:-1)*getchar()-a/512,putchar(b);}
я представляю эту крошечную golfed версию первого, чтобы убедить вас что программные фазовые блокировки на самом деле довольно просты, поскольку программное обеспечение идет, хотя они могут быть сложными.
Если вы подаете 8-битные линейные образцы на stdin, он будет производить 8-битные образцы пилообразной волны, пытающиеся отслеживать одну октаву выше на stdout. При 8000 выборок в секунду он отслеживает частоты в районе 250 Гц, чуть выше B ниже среднего C. В Linux вы можете сделать это, набрав arecord | ./pll | aplay
. Низкие 9 бит b
являются осциллятором (что может быть VCO в аппаратной реализации), которое генерирует квадратную волну (1 или -1), которая умножается на входную форму волны (getchar()
), чтобы получить выход фазы детектор. Этот выход затем фильтруется в нижнем проходе в a
для получения сигнала сглаженной фазовой ошибки, который используется для регулировки частоты колебаний b
для нажатия a
в направлении 0. Собственная частота прямоугольной волны, когда a == 0
, равна b
для увеличения на 16 каждый образец, который увеличивает его на 512 (полный цикл) каждые 32 выборки. 32 образца со скоростью 8000 выборок в секунду составляют 1/250 секунды, поэтому собственная частота составляет 250 Гц.
Затем putchar()
принимает низкие 8 бит b
, которые составляют пилообразную волну с частотой 500 Гц или около того, и извергает их как выходной аудиопоток.
Есть несколько вещей, которые отсутствуют в этом простом примере:
Это не имеет хороший способа обнаружения блокировки. Если у вас есть тишина, шум или сильный чистый входной сигнал 250 Гц, a будет примерно равным нулю, а b будет колебаться со своей частотой по умолчанию. В зависимости от вашего приложения вы можете узнать, нашли ли вы сигнал или нет! Предложение Camenzind в главе 12 из Designing Analog Chips состоит в том, чтобы подавать второй «фазовый детектор» на 90 ° вне фазы от реального детектора фазы; его сглаженный выход дает вам амплитуду сигнала, на который вы теоретически заблокировали.
Собственная частота генератора фиксирована и не подметает. Диапазон захвата PLL, интервал частот, в пределах которого он заметит колебания, если он в настоящий момент не заблокирован, довольно узкий; его диапазон , над которым он будет располагаться, чтобы следить за сигналом после его блокировки, намного больше. Из-за этого, обычная частота развертки PLL во всем диапазоне, где вы ожидаете найти сигнал, пока не получите блокировку, а затем прекратите подметание.
golfed версия выше снижается из much more readable example of a software phase-locked loop in C, что я написал сегодня, что действительно делает обнаружение блокировки, но не подметать. Ему нужно около 100 циклов процессора на каждый образец ввода на PLL на процессоре Atom в моем нетбуке.
Я думаю, что если бы я был в вашей ситуации, я бы сделал следующее (помимо очевидных вещей, таких как поиск кого-то, кто знает больше об обработке сигналов, чем я, и генерации тестовых данных). Я, вероятно, не буду фильтровать и понижать преобразование сигнала в интерфейсе, так как он уже на такой низкой частоте. Сдвиговое преобразование в полосу 200 Гц-400 Гц вряд ли представляется необходимым. Я подозреваю, что PSK вызовет некоторые новые проблемы, поскольку, если сигнал внезапно сдвигает фазу на 90 ° или более, вы теряете фазовую блокировку; но я подозреваю, что эти проблемы будут легко разрешаться, и это вряд ли будет необоснованной территорией.
Я задал соответствующий вопрос по адресу http://dsp.stackexchange.com/questions/8456/how-to-perform-carrier-phase-recovery-in-software – Keith 2013-04-02 02:05:24