Tôi cho rằng đây có lẽ là quá muộn để giúp bạn (những gì đã bạn kết thúc làm gì?), Nhưng nó có thể giúp các chàng bên cạnh.
Dưới đây là một ví dụ golfed của một phần mềm loop phase-locked tôi chỉ viết trong một dòng của C, mà sẽ hát cùng với bạn:
main(a,b){for(;;)a+=((b+=16+a/1024)&256?1:-1)*getchar()-a/512,putchar(b);}
tôi trình bày phiên bản golfed nhỏ này đầu tiên để thuyết phục bạn vòng lặp phần mềm bị khóa thực sự khá đơn giản, khi phần mềm đi, mặc dù chúng có thể phức tạp.
Nếu bạn nạp mẫu tuyến tính 8 bit trên stdin, nó sẽ tạo ra các mẫu 8 bit của sóng sawtooth cố gắng theo dõi một octave cao hơn trên stdout. Với 8000 mẫu mỗi giây, nó theo dõi tần số trong vùng lân cận là 250Hz, ngay trên B dưới trung bình C. Trên Linux, bạn có thể thực hiện điều này bằng cách gõ arecord | ./pll | aplay
. 9 bit thấp của b
là bộ dao động (có thể là VCO trong phần cứng), tạo ra một sóng vuông (1 hoặc -1) được nhân với dạng sóng đầu vào (getchar()
) để tạo ra đầu ra của pha máy dò. Đầu ra đó sau đó được lọc thấp thành a
để tạo ra tín hiệu lỗi pha trơn được sử dụng để điều chỉnh tần số dao động của b
để đẩy a
về phía 0. Tần số tự nhiên của sóng vuông, khi a == 0
, là dành cho b
để tăng thêm 16 mỗi mẫu, tăng lên 512 (một chu kỳ đầy đủ) mỗi 32 mẫu. 32 mẫu ở 8000 mẫu mỗi giây là 1/250 giây, đó là lý do tại sao tần số tự nhiên là 250Hz.
Sau đó, putchar()
mất 8 bit thấp của b
, tạo nên sóng xung quanh 500Hz hoặc hơn và phát ra chúng dưới dạng luồng âm thanh đầu ra.
Có một vài điều mất tích từ ví dụ đơn giản này:
Nó không có cách tốt để phát hiện khóa. Nếu bạn có im lặng, tiếng ồn, hoặc một giai điệu đầu vào 250Hz tinh khiết mạnh, một sẽ là khoảng 0 và b sẽ dao động ở tần số mặc định của nó. Tùy thuộc vào ứng dụng của bạn, bạn có thể muốn biết liệu bạn đã tìm thấy tín hiệu hay chưa! Lời đề nghị của Camenzind trong chương 12 của Designing Analog Chips là nạp một "máy dò pha" thứ hai ra khỏi pha từ máy dò pha thực; đầu ra mượt mà của nó mang lại cho bạn biên độ của tín hiệu bạn đã khóa về mặt lý thuyết.
Tần số tự nhiên của bộ dao động được cố định và không quét. Phạm vi chụp của một PLL, khoảng thời gian tần số mà trong đó nó sẽ nhận thấy một dao động nếu nó hiện không bị khóa trên một, là khá hẹp; Phạm vi khóa của nó, mà trên đó nó sẽ có phạm vi để theo dõi tín hiệu khi nó bị khóa, lớn hơn nhiều. Bởi vì điều này, nó phổ biến để quét tần số của PLL trên phạm vi mà bạn mong đợi để tìm một tín hiệu cho đến khi bạn nhận được một khóa, và sau đó ngừng quét.
Phiên bản được đánh gôn ở trên được giảm từ much more readable example of a software phase-locked loop in C mà tôi đã viết hôm nay, không phát hiện khóa nhưng không quét. Nó cần khoảng 100 chu kỳ CPU trên mỗi mẫu đầu vào cho mỗi PLL trên CPU Atom trong netbook của tôi.
Tôi nghĩ rằng nếu tôi ở trong tình huống của bạn, tôi sẽ làm như sau (ngoài những điều hiển nhiên như tìm người biết nhiều hơn về xử lý tín hiệu hơn tôi và tạo dữ liệu thử nghiệm). Tôi có lẽ sẽ không lọc và downconvert tín hiệu trong một kết thúc trước, kể từ khi nó ở một tần số thấp như vậy đã. Downconverting đến một ban nhạc 200Hz-400Hz hầu như không cần thiết. Tôi nghi ngờ rằng PSK sẽ mang đến một số vấn đề mới, vì nếu tín hiệu đột nhiên chuyển pha 90 ° hoặc hơn, bạn sẽ mất khóa pha; nhưng tôi nghi ngờ rằng những vấn đề đó sẽ dễ giải quyết, và nó khó có thể xảy ra.
Tôi đã hỏi một câu hỏi có liên quan tại http://dsp.stackexchange.com/questions/8456/how-to-perform-carrier-phase-recovery-in-software – Keith