discuss-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Discuss-gnuradio] Decimation questions


From: Brian Padalino
Subject: Re: [Discuss-gnuradio] Decimation questions
Date: Tue, 12 Aug 2008 08:27:39 -0400

On Tue, Aug 12, 2008 at 8:03 AM, Sebastiaan Heunis <address@hidden> wrote:
> Brian
>
> Thanks for the help so far.  I've really figured out a lot of the
> decimation stuff so far.  I plan on simulating the decimation scheme
> in Matlab/C++ to see exactly what happens and where unwanted effects
> might be introduced.  I'm supposed to investigate the current scheme
> to see if it meets our needs and maybe implement another scheme if
> necessary.  This is a part of the master's degree that I am doing.  I
> will make the decimation info available to anyone interested in it.

I suggest just writing a testbench in Verilog, stimulating the input
using whatever stimulus you want and writing the results out to a
file.  This will give bit-accurate, fixed-point precision without the
need for strange MATLAB/C++ conventions.  You also get the exact
bit-widths that are used within the FPGA.

Writing Verilog for simulation is significantly easier than writing
for synthesis - have fun with it!  There are a lot of resources out
there if you need help.

> The value FR_RX_PHASE_0 is 0.  When the USRP is initialized,
> FR_RX_PHASE_0 - 3 all get the value 0 and I don't see them being set
> anywhere else when a normal downconversion is performed.
> FR_DECIM_RATE gets set to decim/2 -1 when the FPGA has a halfband
> filter in it.  The -1 is probably due to zero indexing as you
> mentioned.
>
> FR_RX_FREQ_0 - 3 still confuses me a little.  When a 7901 tv tuner
> module is used, the second IF is at 20MHz.  I followed the code in
> db_tv_rx.py and usrp.py and saw that in this case we have
> set_rx_freq(0,-20e6).  In usrp_standard.cc we have the following code
> in set_rx_freq:
>
> compute_freq_control_word_fpga (double master_freq, double target_freq,
>                                double *actual_freq, bool verbose)
> {
>  static const int NBITS = 14;
>
>  int   v = (int) rint (target_freq / master_freq * pow (2.0, 32.0));
>
>  if (0)
>    v = (v >> (32 - NBITS)) << (32 - NBITS);    // keep only top NBITS
>
>  *actual_freq = v * master_freq / pow (2.0, 32.0);
>
>  if (verbose)
>    fprintf (stderr,
>             "compute_freq_control_word_fpga: target = %g  actual = %g  delta 
> = %g\n",
>             target_freq, *actual_freq, *actual_freq - target_freq);
>
>  return (unsigned int) v;
> }
>
> v then gets written to FR_RX_FREQ_0 for channel 0.  I still need to
> figure out how this frequency value is used in the FPGA to generate
> the sine and cosine waves used in the cordic algorithm since somehow a
> 20MHz signal is generated from v.  From what I understand, our I and Q
> signals are multiplied by a sine and cosine and then passed to the cic
> filter.  This leaves only the components centered at 0Hz, since the
> cic low pass filters and decimates it.  The hbf also lowpass filters
> and decimates by a further factor of 2.

The ratio being computed here is the delta phase for each tick of a
64MHz clock for the desired frequency.  It is then scaled to be a
signed 32-bit number, where 2^32 = 2*pi.

> So I understand most of the Python->C++->Verilog code.  It's just the
> Verilog itself that I'm still stuck at.  I did some VHDL last year, so
> I'm not totally lost.  What I would like to know is the following.  We
> have this in the rx_chain part:
>
> phase_acc #(FREQADDR,PHASEADDR,32) rx_phase_acc
>     (.clk(clock),.reset(reset),.enable(enable),
>      
> .serial_addr(serial_addr),.serial_data(serial_data),.serial_strobe(serial_strobe),
>      .strobe(sample_strobe),.phase(phase) );
>
> and this in the phase_acc part:
>
> setting_reg #(FREQADDR)
> sr_rxfreq0(.clock(clk),.reset(1'b0),.strobe(serial_strobe),.addr(serial_addr),.in(serial_data),.out(freq));
>
>   always @(posedge clk)
>     if(reset)
>       phase <= #1 32'b0;
>     else if(serial_strobe & (serial_addr == PHASEADDR))
>       phase <= #1 serial_data;
>     else if(enable & strobe)
>       phase <= #1 phase + freq;
>
> From the VHDL that I know, my guess is that serial_strobe gets
> asserted whenever the FX2 chip writes to the FPGA, serial_addr is an
> address that the FX2 sends to the FPGA and serial_data is the value
> that gets written to that address.  Is this correct?

It's just a standard SPI bus.  The address gets clocked in with the
serial strobe along with the data.

There should be a distinction between the interfaces with the FX2.
There is a SPI interface which connects to the serial pins and
controls registers that are written only a few times during operation,
as well as the main parallel interface which transfers the samples
that are transmitted over USB.

> So, the setting_reg#... line above drives the freq wire with the value
> that the FX2 writes to FREQADDR?  This only happens once when we tune
> to the desired frequency, so we just keep adding the same freq value
> to phase every 1/64MHz?

Since you know VHDL, the FREQADDR is just a generic value which is
passed into the settings register module.  It basically looks to see
if it is the addressed peripheral and, if it is, latches the data in.
Just a simple serial register that is configurable through a generic,
compile time value passed into the module.

Phase is the initial phase offset, and freq is the phase accumulation
delta which, I believe, is fed into the CORDIC and is used as a basic
NCO.

Hope this helps.

Brian




reply via email to

[Prev in Thread] Current Thread [Next in Thread]