Forum Discussion
Costas Loop oscillates in ModelSim while locks in MATLAB!
Hello again,
I have designed a Costas Loop in MATLAB and it simulates very well... locking and recovering the carrier. Here are the results: http://www.alteraforum.com/forum/attachment.php?attachmentid=10456&stc=1 I ported the design to FPGA in VHDL, and simulated in ModelSim... however, the loop has a kinda oscillating behaviour... take a look: http://www.alteraforum.com/forum/attachment.php?attachmentid=10457&stc=1 This is the Loop Filter output: http://www.alteraforum.com/forum/attachment.php?attachmentid=10458&stc=1 Why is it oscillating? Is it the loop filter?46 Replies
- Altera_Forum
Honored Contributor
here is copy:
"inc" can be chosen as Fo/Fs scaled by 2^32 but note there is bug for negative frequency, use positive increment and invert at output or avoid matlab mod function. Note also this nco is based on fixed lut resolution (no intermediate values calculated).%NCO bit true model clear all; close all; %example NCO parameters n = 20000; %number of test samples A = 2^15 - 1; %max amplitude, amplitude resolution 16 bit signed M = 2^32; %NCO accumulator phase resolution inc = round(M*.001); %NCO accumulator phase increment k = 2^12; %lut phase resolution (lut size) lsb = log2(M) - log2(k); %LSBs discarded when addressing lut = round(A*exp(j*2*pi*(0:k-1)/k)); %lut, one cycle sine data ptr = 0; addr = 0; for i = 1:n y(i) = lut(addr+1); %add 1 for matlab LUT ptr = mod(ptr + inc, M); %phase accumulator(ramp) addr = round(ptr/2^lsb); %discard LSBs addr(addr >= k) = addr - k; %check address overflow end - Altera_Forum
Honored Contributor
No I don't want to revert to matlab... as you said, modelsim has proper loop and delays. I am gonna focus on it. I was just making a comparison in behaviour.... But is my analysis right?
Thanks for the code... I might need it. - Altera_Forum
Honored Contributor
That is good path since modelling in matlab for feedback loops needs to be dead accurate match of rtl. Yes your analysis is right if you mean your matlab model which I haven't seen its final format. The nco statement has control over phase just like rtl and this phase is used to control frequency by different jumps over sin/cos functions (luts) so it will have very high floating resolution. but you need to write as y = exp(j*2*pi*linspace(0+offset:N-1+offset,N)*.1); in order to step phase in fractions.
- Altera_Forum
Honored Contributor
Come on Mr Kazem! The model that we spent days discussing it! We finally said yuppie remember?! Anyway here its is:
OK, that's great... let's stick to modelsim now. so I should expect oscillations in the loop filter output. I believe convergence time may be long and ModelSim is going to consume even longer time to complete simulation. I will carry on tests tomorrow and let you know... thanks for help Mr Kazem, I am so grateful to you.% Siraj Muhammad % 25/3/2015 % BPSK Demodulator %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% load RRC.mat fc = 0.05000001; phase_offset = pi/7; N = length(rf_signal); bb = zeros(1, N); bb_f = zeros(1, N); I_f = zeros(1, N); Q_f = zeros(1, N); I_r = zeros(1, N); Q_r = zeros(1, N); error = zeros(1, N); PhErr = zeros(1, N); error_integral = zeros(1, N); % Loop Filter Coefficients % BW = 200; % Hz % loop_theta = 2*pi*BW; % C1 = 4*(loop_theta)^2/(1+sqrt(2)*loop_theta+loop_theta^2); % C2 = 2*sqrt(2)*loop_theta/(1+sqrt(2)*loop_theta+loop_theta^2); C1 = 2^2; C2 = 1/2^8; for i = 2:N % Downconverting to Baseband bb(i) = rf_signal(i).*exp(j*2*pi*fc*i+j*phase_offset).*exp(-j*PhErr(i-1)); % Filtering bb_f = filter(RRC, bb(1:i)); I_f = real(bb_f); Q_f = imag(bb_f); % Error error(i) = I_f(i).*Q_f(i); % Loop Filter error_integral(i) = error(i).*C1 + error_integral(i-1); PhErr(i) = error(i).*C2 + error_integral(i); end figure; subplot 321; plot(real(bb)); title('I Channel') subplot 322; plot(imag(bb)); title('Q Channel') subplot 323; plot(I_f); title('I Channel Filter') subplot 324; plot(Q_f); title('Q Channel Filter') subplot 325; plot(error); title('Phase Error'); subplot 326; plot(PhErr); title('Loop Filter'); - Altera_Forum
Honored Contributor
The above code should prove the concept.
The feedback point is at this equation below bb(i) = rf_signal(i).*exp(j*2*pi*fc*i+j*phase_offset).*exp(-j*PhErr(i-1)); The expression exp(-j*err) means rotate phase 90 degrees *err clockwise while frequency is unchanged. This may suit software based dsp but in rtl the nco is controlled via inc value which controls both phase and frequency. So keep on modelsim - Altera_Forum
Honored Contributor
--- Quote Start --- The above code should prove the concept. The feedback point is at this equation below bb(i) = rf_signal(i).*exp(j*2*pi*fc*i+j*phase_offset).*exp(-j*PhErr(i-1)); The expression exp(-j*err) means rotate phase 90 degrees *err clockwise while frequency is unchanged. This may suit software based dsp but in rtl the nco is controlled via inc value which controls both phase and frequency. So keep on modelsim --- Quote End --- Wonderful! This qualifies my previous analysis. Here is the result of a test with the loop activated and a small phase offset. Output from loop filter is shifted right by 7 and fed to NCO word. https://www.alteraforum.com/forum/attachment.php?attachmentid=10467 https://www.alteraforum.com/forum/attachment.php?attachmentid=10468 As I shift the output with a smaller number i.e. as I divide by a smaller number, meanders increase in the specified period of time (400 microseconds), but it keeps rising. I don't know if this will lock and settle. What do you think? I am thinking of programming the FPGA with this design and capture signals using SignalTap, if it locks eventually, I should see the same input pattern... do you recommend doing that? - Altera_Forum
Honored Contributor
I suggest you try:
1) single clean tone e.g. @ 0.01Fs by just setting your symbols to +1 only. This should lock first. 2)Next try single tone but add to it +1/-1 jitter (representing +1,-1,+1,-1 train of pulses) by setting symbols to +1/-1 Does it still lock? 3)Then move to full random symbols. I have doubts that fully random BPSK will lock easily. You may need to extract a tone eventually through bandpass filter and target it for lock but let us see. - Altera_Forum
Honored Contributor
I am doing some tests... I will do yours as well and let you know.
- Altera_Forum
Honored Contributor
Hello Mr Kazem,
I did the test you suggested... maybe results are disappointing. These are all with a single tone input. With a small amount of scaling... loop takes some time: http://www.alteraforum.com/forum/attachment.php?attachmentid=10470&stc=1 Without scaling: http://www.alteraforum.com/forum/attachment.php?attachmentid=10471&stc=1 http://www.alteraforum.com/forum/attachment.php?attachmentid=10472&stc=1 I don't know if the latter gonna lock eventually. What to do now? By the way, I found a bug in my code... the loop filter is clocked by a 50 MHz, and its input is the phase detector (multiplier) which in turn has RRCs as input, the RRCs produce a sample every several clock cycles of the 50 MHz... I thought it would be the problem. I made an enable port for the Loop Filter so it only works when a new sample comes out of the RRCs. However, nothing changed... but I think this is how it should be. ** UPDATE ** This is the output of the loop filter for 1 ms. http://www.alteraforum.com/forum/attachment.php?attachmentid=10473&stc=1 I and Q are sinusoidal signals!! This never gonna lock!! :'( - Altera_Forum
Honored Contributor
when I suggested testing the tx/rx chain with the feedback loop deactivated I wanted a sanity check of your chain. Ideally you should have testbench for every module by reading reference outputs from matlab into testbench and check for bit true comparison. That is what we do in the industry. Moreover you need to scale the outputs of each module to some practical resolution e.g 16 bits signed yet I see your dynamic range too high.
Repeat the chain sanity test by checking that what you send from Tx as random symbols is recovered by Rx and check that at symbol rate. I mean your overall rx chain should decimate until reaching symbol rate then pass it through a simple slicer and check pattern. I did some experiments on this design in matlab running 1 Msamples and it locks for all cases nicely (symbols at +1 all = single tone, symbols at +1/-1 = single tone with jitter and random data. Though I used complex I/Q RF to avoid extra filter (for speed). So I am convinced it should lock eventually). It does not lock if I changed input to QPSK or 16QAM. The main point I noticed was that I have to update the NCO word once only every say 10 error updates (ignore 9) and revert back to initial nco word. The scaling is essential to match your phase resolution word of nco. You will get a nice oscillation that converges to perfect result or so (I got zero jitter at .01Fs). I did not use proportional term. Remember what aplies to software dsp does not apply to FPGA nco. DSP engineers do not know about fpga and are only orientated to their platform. Our nco has one control over phase and frequency (nco increment value).