I just finished a costas loop for QPSK signal,I transmit the baseband signal and sent it into the costas loop, which worked well, but when I filter the baseband signal with root raised cosine filter during modulation, the original costas loop did not work properly. I probably know why it did not work properly, but I could not solve it.The detail are list below: Transmit-receive model first, as the picture generate QPSK signal,carrier frequency = 2M,sample rate = 20M,symbol rate = 10k(every symbol 2000 samples),in the code I generate 32 symbols.Then symbols get through a root raised cosine filter, loaded waves, and transmit the real part.It should be noted that when SRRC doesn't exist,the expression of Tx is: $Tx = I(t)cos((w+w_d)t+theta)-Q(t)sin((w+w_d)t+theta)$
$w$ is exact angle frequence and $w_d$ is offset of frequency because of channel,$theta$ is offset of phase angle,$I(t)$ and $Q(t)$ are In-phase components and orthogonal components.

In the receiver, it is assumed that time synchronization has been completed, only carrier synchronization is considered, and the $Tx$ is passed into the costas loop,according to linker1 my phase detector is:
$\delta = Q_{out} \cdot sign(I_{out}) - I_{out} \cdot sign(Q_{out})$
as for loop filter I use average directly instead of low-pass filter and it work well.The demodulation result and $w$ convergence result are listed follow: Before and after demodulation (assuming noiseless channel)
Gradual frequency locking

But when I add root raised cosine filter(SRRC) in system, things are screwed up.Now the expression Tx is: $Tx = I(t)*g(t)cos((w+w_d)t+theta)-Q(t)*g(t)sin((w+w_d)t+theta)$
g(t) is time domain impulse response of SRRC(Rolloff factor = 0.5,Number of symbols = 1),and now The demodulation result and $w$ convergence result are listed follow:
The demodulation result with SRRC
convergence result of angle frequency with SRRC I guess this is because unlike the original rectangular pulse, the gain of SRRC at different positions in the 2000 points of a symbol is different, which leads to the same phase discriminator calculating the value sign is correct (that is, costas loop can feedback in the right direction), but the size of the specific feedback is extremely uneven. From the figure below, it can be seen that the frequency always has a big jump when it is about to lock. The above is my personal guess, and this is the problem I want to ask for help: what causes the normal phase locking after the addition of SRRC and how to solve it.
In fact,I refer to many papers and manuals, but to my surprise, almost no one thinks that SRRC has any effect on carrier-frequency synchronization, nor does it seem that the phase and frequency offset caused by SRRC are taken into account when constructing the costas loop of the system,for example this manuals QPSK receiver manual is a good reference,in page 17,the manual consider SRRC in system, however in page 21 it build costas loop normally seem SRRC have little effect on costas phase detector.This puzzled me.
My matlab code is here,I think it will help, there are 3 files, the first is how QPSK generate(if two lines of comment are added, SRRC is considered; if not, SRRC is not considered),the second is my QPSK costas loop,I pass the signal into the loop in chunks (dozens of points each, that is, dozens of sampling times to calculate a feedback amount once).And last is main function,clicking should work directly.
This is how signal generate:

% % generate QPSK signal(with carrier freq),signal format is :
% % I = Di*cos((w+wd)t+theta)-Dq*sin((w+wd)t+theta)
% % sig is qpsk transmation signal(real signal)
% % sig is input for QPSK_carrier_trace_demod_realtime.m file
function [Z,Iin,Qin,data,Di,Dq] = qpsk_sig_gene(fc,wd,theta,fs,Rb,Nsymb)
format long;
w =  2*pi*fc;
Tsym = fs/Rb;
data_org = randi([0 1],1,N_bits);

Di = (real(data))';
Dq = (imag(data))';
xlabel("In-phase symbol")

a = rcosdesign(0.5,1,2000,"sqrt");
Di_rcosine_tmp = conv(Di,a);
Dq_rcosine_tmp = conv(Dq,a);
length_a = length(a);
%% if want to remove SRRC,remove this segment
Di = Di_rcosine_tmp(length_a/2+1:length(Di)+length_a/2);
Dq = Dq_rcosine_tmp(length_a/2+1:length(Dq)+length_a/2);
t = 0:1/fs:(length(data)-1)/fs;
Iin = Di.*cos((w+wd).*t+theta)-Dq.*sin((w+wd).*t+theta);
Qin = Di.*sin((w+wd).*t+theta)+Dq.*cos((w+wd).*t+theta);

Z = Iin +1i*Qin;  

And this is how costas work:

function [I_filter,Q_filter] = qpsk_costas(Iin,fs,fc,Nsymb)
phase = 50; %initlize phase(receiver)
Kvco = 200; %feedback parameter
w = 2*pi*fc;
Tsym = 40;  %how much time(Tsym/fs)feedback once
base = 0:1:(Tsym-1);
W=zeros(1,nsymb);U=zeros(1,nsymb);U1 = zeros(1,nsymb*Tsym);
I_filter = [];
Q_filter = [];
a = rcosdesign(0.5,1,2000,"sqrt");
length_a = length(a);
for n_trace = 1:nsymb
    data_select = (n_trace - 1)*Tsym + base;
    cos_t = cos(w*t_n_trace/fs+phase); %generate cosine wave
    sin_t = sin(w*t_n_trace/fs+phase);

    Iout = Iin(1,data_select+1).*cos_t; 
    Qout = Iin(1,data_select+1).*sin_t;
    Di_rcosine_tmp = conv(Iout,a);     %pass matched filter(still SRRC)
    Dq_rcosine_tmp = conv(Qout,a);
    Iout = Di_rcosine_tmp(floor(length_a/2)+1:length(Iout)+floor(length_a/2));
    Qout = Dq_rcosine_tmp(floor(length_a/2)+1:length(Iout)+floor(length_a/2));
    I_filter = [I_filter Iout];
    Q_filter = [Q_filter Qout];

    derta = sign(Qout).*Iout-sign(Iout).*Qout;   %calcu derta(error)
    u = sum(derta);
    w = w + Kvco*u;
    phase = phase + w*Tsym/fs;
    U(n_trace) = u;
    W(n_trace) = w;
    U1(1,t_n_trace+1) = derta; 
xlabel("In-phase after demodulation")

And this is main function,you can run the system by run it:

fc = 2e6;  %carrier wave freqency 
fs = 20e6; %sample rate
theta = 0; %initlize phase
wd = 1000; %error angular frequency
Rb = 10e3; %symbol rate
Nsymb = 32;%symbol number

[Z,Iin,Qin,data,Di,Dq] = qpsk_sig_gene(fc,wd,theta,fs,Rb,Nsymb);
[I_filter,Q_filter] = qpsk_costas(Iin,fs,fc,Nsymb);  

I can't solve it, Thank you for helping.

  • $\begingroup$ Some quick comments as I didn't have a chance to read through your code: If time synch has been completed, did you pass the waveform through a 2nd RRC filter and then down sample to one sample per symbol? This should then be the ideal constellation with only a carrier offset, so one sample per symbol and spinning. This would be the case where the pulse shaping has no impact (since there is only one sample per symbol) and the Costa's loop's purpose is to stop the spinning and stabilize the constellation. $\endgroup$ Commented Mar 13 at 14:45
  • $\begingroup$ Thank you for comment,I did not pay attention to the downsampling problem you mentioned.But at the same time I found that there seems to be another problem in my system, I did not take into account the filter delay introduced by SRRC. Since I am not clear about the relevant knowledge, I will spend time on perfecting my system and then report the results $\endgroup$ Commented Mar 14 at 3:01
  • $\begingroup$ It turns out that you are right, I have been spending time on irrelevant problems, and finally found that the problem is that you say downsampling, I must keep only one sample point per symbol based on the original sample point (that is, the subsequent decision time) and set the remaining points to zero, so that I can correctly lock the phase $\endgroup$ Commented Mar 19 at 12:17
  • $\begingroup$ thanks for letting me know and glad it helped. If that resolved your issue I will copy the comment to an answer so that we can close this out $\endgroup$ Commented Mar 19 at 18:23

1 Answer 1


If time synch has been completed, confirm that the waveform has been put through a 2nd RRC filter and then down sampled to one sample per symbol. This should then be the ideal constellation with only a carrier offset, so one sample per symbol and spinning. This would be the case where the pulse shaping has no impact (since there is only one sample per symbol) and the Costa's loop's purpose is to stop the spinning and stabilize the constellation.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.