Costas Loop implemented on FPGA?

Hey all,

I’m looking at using the FPGA on the USRP to improve the performance in
some of
what my lab is doing. To learn about the Verilog code already written
for the
FPGA, I’m trying to do phase recovery with the Costas loop at the end of
the
rx_chain. First of all, is this a good project? It may not be good to
have it
in the codebase for general purpose gnuradio since it’s only relevant
for
certain protocols, but is there anything wrong with this approach that
makes it
brain dead? I’ve read that the FPGA is using 90% of its logic cells
with it’s
current implementation, and that turning off a tx_chain or an rx_chain
could
solve that problem, but I’m not there yet.

I’ve been hacking at it for a bit, and I drafted up a simple vlog file
here:
http://web.mit.edu/~rnk/www/costas_loop.v
and a slightly modified rx_chain here:
http://web.mit.edu/~rnk/www/rx_chain.v
I’m new to FPGAs and signals (So why am I working on this? To learn.),
so I
have a few questions.

  1. I need to store the phase shift somewhere as I correct the guess with
    the
    error term. I assume that the phase accumulator in phase_acc.v needs to
    do
    something similar, but I don’t understand how it stores its information.

  2. The original C implementation of costas loop has two error terms you
    can
    choose from:
    ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
    (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
    and:
    (sample.real()*sample.imag());
    I chose the simpler because it involved one less multiply, and I didn’t
    understand what the other was doing. The point of software radio is to
    allow
    you to make these decisions in software, but if I had to hardcode one in
    the
    FPGA, which would it be? I’m definitely not complicating this further
    by
    trying to get that info via USB.

  3. For alpha and beta, I was just going to use a bitshift to scale the
    error
    term. That’d also be hardcoded in the vlog code, but what would
    reasonable
    constants be? I’ve seen this question asked before, and I looked at the
    paper
    here:
    http://i.cmpnet.com/chipcenter/dsp/images/dspsourced/DSP010531F1.pdf
    and it said alpha is around 0.01 or less, so I figure a bitshift by
    seven places
    makes alpha about 1/128, or 0.0078125, and the paper doesn’t mention
    beta, so I
    said eight places.

  4. What’s the difference between the code in
    gr_pll_carriertracking_cc.cc and
    gr_costas_loop_cc.cc? They seem to do the same stuff, but maybe they’re
    subtly
    different?

That’s all.

Cheers,
Reid

Reid N Kleckner wrote:

solve that problem, but I’m not there yet.
something similar, but I don’t understand how it stores its information.

  1. The original C implementation of costas loop has two error terms you can
    choose from:
    ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
    (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
    and:
    (sample.real()*sample.imag());
    I chose the simpler because it involved one less multiply,
    You could actually implement the other one without any multiplies.
    multiplying with 1.0 is just oding nothing.
    multiplying with -1 is just negating the value
    you could rewrite the code in C like:
    float val1,val2;

if(sample.real()>0)
val1 = sample.imag();
else
val1 = -sample.imag();

if(sample.imag()>0)
val2 = -sample.imag();
else
val2 = sample.imag();

output=val1+val2;

and I didn’t

http://i.cmpnet.com/chipcenter/dsp/images/dspsourced/DSP010531F1.pdf
and it said alpha is around 0.01 or less, so I figure a bitshift by seven places
makes alpha about 1/128, or 0.0078125, and the paper doesn’t mention beta, so I
said eight places.
You really want to get the values right. If the values are off your
costas loop will have weird behaviour.
I also had trouble finding the right values.
If anybody has a good clue please let us know.
In the meantime I would not hardcode the values but make them
configurable.
Just use one of the user registers to store the bitshift values.