# Unable to stabilize 8-PSK signal with self designed costas loop

I am trying to make a signal processing block which implements the costas loop to stabilize an 8-PSK signal. Here is the flowgraph with "costas_loop" being my block.

My workflow is the following -

in0 = input_items[0]
out = output_items[0]
# <+signal processing here+>
feedback = np.ones(in0.shape, dtype=np.complex64)
on_first_mul = np.ones(in0.shape, dtype=np.complex64)
op_thresh_imag = np.ones(in0.shape, dtype=np.float64)
op_thresh_real = np.ones(in0.shape, dtype=np.float64)
a = np.array([op_thresh_imag])
b = np.array([op_thresh_real])
in_iir = np.zeros(in0.shape, dtype=np.float64)
out_iir = np.ones(in0.shape, dtype=np.float64)
out_vco = np.ones(in0.shape, dtype=np.complex64)
in0 = in0/math.sqrt(2)

for i in xrange(0,self.iter):

# Multiply input signal with feedback of that iteration
on_first_mul = in0*feedback
# Phase error detector
real = on_first_mul.real
imag = on_first_mul.imag
a = self.threshold(imag)
b = self.threshold(real)
in_iir = np.arcsin(imag*b - real*a)

# IIR filter implementing (1.0001 - z)/(1 - z) (old style)
# self.prev_input[i] contains last input value from previous in0 chunk
in_iir_delay = np.concatenate([[self.prev_input[i]],in_iir[0:-1]])
# Update this for next in0 chunk
self.prev_input[i] = in_iir[-1]
out_temp = in_iir*1.0001 - in_iir_delay
out_temp[0] += self.prev_output[i]
out_iir = np.cumsum(out_temp)
self.prev_output[i] = out_iir[-1]

# VCO implementation 1/(1 - z) (old style)
out_iir[0] += self.prev_phase[i]
in_vco = np.cumsum(out_iir)
self.prev_phase[i] = in_vco[-1]
real_part = np.cos(self.k_factor*in_vco)
imag_part = np.sin(self.k_factor*in_vco)
out_vco = real_part + 1j*imag_part
feedback = out_vco


Also, here is the rest of the code -

def __init__(self, samp_rate, iter):
gr.sync_block.__init__(self,
name="costas_loop",
in_sig=[np.complex64],
out_sig=[np.complex64])
self.samp_rate = samp_rate;
self.iter = iter;
self.call = 0

self.prev_input = np.zeros(self.iter, dtype=np.float64)
self.prev_output = np.zeros(self.iter, dtype=np.float64)
self.prev_phase = np.zeros(self.iter, dtype=np.float64)

self.k_factor = -5/samp_rate

def threshold(self, in0):
output = 0
if in0 <= math.cos(7*math.pi/8):
output = -1
elif in0 > math.cos(7*math.pi/8) and in0 <= math.cos(5*math.pi/8):
output = -1/(2**0.5)
elif in0 > math.cos(5*math.pi/8) and in0 <= math.cos(3*math.pi/8):
output = 0
elif in0 > math.cos(3*math.pi/8) and in0 <= math.cos(math.pi/8):
output = 1/(2**0.5)
elif in0 > math.cos(math.pi/8):
output = 1
return output


This code unfortunately "almost" works. I get a stabilized 8-PSK output in the beginning,

Unfortunately, after about 160 calls to the costas_loop's work(), the 8-PSK output starts to move and destabilizes. What could be going wrong?

• I'll be happy to provide more information, but unfortunately I don't know what information will be crucial here – martianwars Nov 2 '16 at 15:56
• It looks like you're using a root raised cosine matched filter. Are you using a root raised cosine pulse shape to transmit? (It isn't clear in the figure). – MBaz Nov 2 '16 at 16:23
• Yes, it's a part of the Polyphase Arbitrary Resampler – martianwars Nov 2 '16 at 16:28
• Can you double-check the frequency of the sine carrier? I don't have gnuradio-companion access right now but I seem to recall that 'm' stands for 1e-3 and 'M' for 1e6. Also, why are you multiplying the signal by this carrier? – MBaz Nov 2 '16 at 17:06
• It's supposed to represent "milli". I'm doing that to begin rotating the constellation at a frequency of 0.1 Hz. The goal of the costas loop is to stabilise the constellation output. – martianwars Nov 2 '16 at 19:16