Forum Discussion
Altera_Forum
Honored Contributor
11 years agoBPSK Demodulation
Hello again, I am still struggling with BPSK demodulation :)
OK, now I am trying to implement Costas Loop for carrier synchronization, which involves Inphase and Quadrature Phase paths. Inphase is looking good, and works as expected, however, the Q component looks awkward. Take a look at these waveforms: http://www.alteraforum.com/forum/attachment.php?attachmentid=10363&stc=1 I understand that multiplying sin * cos will produce a high frequency component, which is a sin modulated by half amplitude of the data signal. BPSK(t) * sin(2*pi*f*t) = 0.5 * [DATA(t) * sin(0) + DATA(t) * sin(2*pi*f*t)] => 0.5 * DATA(t) * sin(2*pi*f*t) => LPF{0.5 * DATA(t) * sin(2*pi*f*t)} = 0 I feel that problem is in my LPF. I used the same Matched RRC filter that I used in the in-phase arm. Papers I read didn't mention that these two filters should be different, that's why I used the same filter. (I think those are unpractical DSP writers, KAZ :D ) So, should I use a separate Loop Filter for Q component? How do I determine it's parameters?66 Replies
- Altera_Forum
Honored Contributor
I found out the reason behind that error... NCO_model produces the same sample value for a single sample of phase input, I need to pass a vector instead.
Code now is as follows:
phi_inc is a vector now, passed to NCO_model on each iteration, and produces new vectors for sin & cos. I only multiply with the index i of both sin_out & cos_out. However, as you stated... filtering is not correct.load LPF.mat N = length(rf_signal); phi_inc = zeros(1, N); bb_sig_I = zeros(1, N); bb_sig_Q = zeros(1, N); I_f = zeros(1, N); Q_f = zeros(1, N); error_sig = zeros(1, N); err = zeros(1, N); % NCO fs = 1.0E8; f = 5.0E6; phi_inc = ((2^32)*f/fs).*ones(1, N); for i = 1:N = NCO_model(phi_inc); % Downconverting to Baseband bb_sig_I(i) = rf_signal(i)*cos_out(i); bb_sig_Q(i) = rf_signal(i)*sin_out(i); % Filtering I_f(i) = filter(LPF, bb_sig_I(i)); I_f(i) = filter(LPF, I_f(i)); Q_f(i) = filter(LPF, bb_sig_Q(i)); Q_f(i) = filter(LPF, Q_f(i)); % Error error_sig(i) = I_f(i).*Q_f(i); % Loop Filter (Leaky Integrator) alpha = 0.1; err(i) = filter(alpha, , error_sig(i)); phi_inc = phi_inc - err(i); end - Altera_Forum
Honored Contributor
I solved it Kazem!
Here is the code:
I replaced my NCO with a cos & sin functions to speed up the execution. Filtering is done as you suggested. Error signal is calculated in a slightly different way I found online, but this doesn't require IIR or Loop Filter. https://www.alteraforum.com/forum/attachment.php?attachmentid=10382 https://www.alteraforum.com/forum/attachment.php?attachmentid=10383 Well, I think this is the desired result... but I don't understand error signal calculation. Can you please explain it a little bit and how different is it from the previous one? And I believe this is only theoretical, and can't be implemented in FPGA. Right? How should I modify it to simulate hardware?load LPF.mat N = length(rf_signal); cos_out = zeros(1, N); sin_out = zeros(1, N); phi_inc = zeros(1, N); bb_sig_I = zeros(1, N); bb_sig_Q = zeros(1, N); I_f = zeros(1, N); Q_f = zeros(1, N); error_sig = zeros(1, N); alpha = 0.1; t = 1:N; fs = 1.0E8; fc = 5.0E6; for i = 1:N cos_out(i) = cos(2*pi*fc*t(i)/fs + phi_inc(i)); sin_out(i) = sin(2*pi*fc*t(i)/fs + phi_inc(i)); % Downconverting to Baseband bb_sig_I(i) = rf_signal(i)*cos_out(i); bb_sig_Q(i) = rf_signal(i)*sin_out(i); % Filtering tmp = filter(LPF, filter(LPF, bb_sig_I(1:i))); I_f(i) = tmp(i); tmp = filter(LPF, filter(LPF, bb_sig_Q(1:i))); Q_f(i) = tmp(i); % Error error_sig(i) = (5*10^-5)*pi*sign(I_f(i)*Q_f(i)); phi_inc(i+1) = phi_inc(i) - error_sig(i); end - Altera_Forum
Honored Contributor
Hi Siraj,
I don't want to discourage you bu I think scaling your error till it is dead is no good. It looks like qpsk/QAM carrier tracking that I did years ago was based on different error circuitry involving slicing as well so we better ignore its details. I thought of your BPSK design and is practically new to me but it looks like it doesn't specifically apply to BPSK. It looks like a basic form of PLL. You might have to do matlab modelling to prove the concept in a simpler way away from BPSK as follows: 1)make your input a clean tone say at 0.1 Fs 2) apply NCO at -0.1 and do the rest as usual at the error detector I and Q should be dc (if all ok) and error should be zero (or settle to zero) repeat above with NCO initial freq set to -0.11 and repeat since we don't expect I and Q to be dc but rather at a negative offset we should have the loop push them back to dc repeat above with nco at -0.09 I and Q would be at positive offset and the loop should push them back to dc. the error should change orientation. Thus the whole issue is finding how to decide if a complex frequency(I/Q) is positive,0 or negative. The actual values of error is not that important but its sense on the NCO is You need to be aware of some other issues in modelling your loop but can do that later such as effect of filter delay (group delay) and actual design latency between error and nco update. But for now the crucial point is finding a way to have good error detection (don't worry about its scaling) I believe you need a lot more work to get this loop right and hopefully tell me. - Altera_Forum
Honored Contributor
how do I apply negative frequency to my nco? do you mean in regard to its sin & cos output?
- Altera_Forum
Honored Contributor
--- Quote Start --- how do I apply negative frequency to my nco? do you mean in regard to its sin & cos output? --- Quote End --- If you are using the nco model then just swap sin/cos (or use negative tuning word if supported) Alternatively you can use the following line: nco = exp(j*2*pi*i*freq); inside your loop set freq to any value +/- 0 ~ 0.5 and I suggest using -0.1, -0.11,-0.09 (not -1.1 that was typing error) you rf input can be just: rf = cos(2*pi*(0:N-1)*.1); fixed for all three tests - Altera_Forum
Honored Contributor
By the way, you can apply all positive frequencies due to mirroring of RF i.e. RF can be +0.1 and nco +0.1, +0.11,+0.09
- Altera_Forum
Honored Contributor
Alright... I just want to note that the second plots in the above posts are for the phase, NOT the error.
- Altera_Forum
Honored Contributor
Test fc = -0.09 Error signal:
https://www.alteraforum.com/forum/attachment.php?attachmentid=10391 I feel they are reversed from what you stated they should be. Should I invert the sign of imag(carrier) in code? - Altera_Forum
Honored Contributor
Looks like inverting the sign of imag(carrier) makes everything as you stated!
First, does that mean the model is a correct Costas Loop? Second, why multiply with -imag(carrier) rather than +imag(carrier)? - Altera_Forum
Honored Contributor
There is no indication of lock.
You have killed the error by /1e5 then (5*10^-5) , this adds almost nothing to nco tuning word whose range is 0 ~ +/-0.5 for .1 case error should settle zero and filtered signal should be dc (I think you got that because error is forced to nothing) for .09 and .11 case error should settle at .01 (either plus or minus) and filtered signal should be dc (not sine wave)