⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 demod.vhd

📁 qam的vhdl程序
💻 VHD
字号:
-- demod.vhd  QAM demodulator design, intended to illustrate Tcl testbench
--
-- rev 1.0, 03 April 2002, Jonathan Bromley
--   first attempt
--
-- rev 1.1, 17 April 2002, Jonathan Bromley
--   added Costas loop for phase lock, improved resolution of LP filter
--   scaling (although I don't think it's really necessary as the I&D
--   filter does all that's needed).


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity iq_demod is

  generic (
    if_bits       : natural  := 4;  -- bit width of IF, digitised at Clk rate
    baseband_bits : natural  := 8;  -- bit width of I/Q outputs
    -- Numerically controlled oscillator for carrier:
    -- f(carrier) = f(Clk) * carrier_incr / (2**NCO_bits)
    NCO_bits      : positive := 8;  -- bit width of NCO phase accumulator
    carrier_incr  : positive := 32; -- NCO phase increment
    -- Output lowpass filter is a crude single-pole thing, no good!
    filter_shift  : natural  := 4;  -- left shift to scale output filter
    filter_rate   : natural  := 8   -- multiplier, filter A = rate/2**shift
  );

  port (
    Clk, Rst  : in  std_logic;
    if_signal : in  signed(if_bits-1 downto 0);
    I, Q      : out signed(baseband_bits-1 downto 0)
  );

end;

-----------------------------------------------------------------------------

architecture RTL of iq_demod is


  signal refI, refQ, dump : std_logic;
  signal prodI, prodQ     : signed(if_bits-1 downto 0);
  signal filterI, filterQ : signed(baseband_bits-1 downto 0);
  signal carrier_delta    : unsigned(NCO_bits-1 downto 0);
  signal idumpI, idumpQ   : signed(baseband_bits-1 downto 0);

begin

  ------------------------------------------------------------------- NCO ---
  -- Numerically controlled oscillator
  --
  NCO: process (Clk, Rst)

    variable PhaseAcc: unsigned(NCO_bits-1 downto 0);

  begin

    if Rst = '1' then
      PhaseAcc := (others => '0');
      refI <= '0';
      refQ <= '0';
      dump <= '0';
    elsif rising_edge(Clk) then
      refI <= PhaseAcc(NCO_bits-1);                           -- cosine
      refQ <= PhaseAcc(NCO_bits-1) xnor PhaseAcc(NCO_bits-2); -- sine
      -- generate a pulse once per carrier cycle for I&D filter
      if (refI = '1') and (PhaseAcc(NCO_bits-1) = '0') then
        dump <= '1';
      else
        dump <= '0';
      end if;
      PhaseAcc := PhaseAcc + carrier_delta;
    end if;

  end process;


  ----------------------------------------------------------------- DEMOD ---
  -- Synchronous quadrature demodulator (binary multiplier)
  --
  demod: process (refI, refQ, if_signal)
  begin

    if refI = '0' then
      prodI <= -if_signal;
    else
      prodI <= if_signal;
    end if;

    if refQ = '0' then
      prodQ <= -if_signal;
    else
      prodQ <= if_signal;
    end if;

  end process;


  ------------------------------------------------------------------- PLL ---
  -- Costas loop for phase lock
  --
  PLL: process (Clk, Rst)

    variable absI : signed(idumpI'RANGE);
    variable absQ : signed(idumpQ'RANGE);
    variable error, reverse: BOOLEAN;

  begin
    if Rst = '1' then
      -- reset actions
      carrier_delta <= to_unsigned(carrier_incr, NCO_bits);
    elsif rising_edge(Clk) then
      if dump = '1' then -- Sample time
        -- Calculate absolute values of I, q
        if idumpI < 0 then
          absI := not idumpI;  -- cut price negation, nearly right!
        else
          absI := idumpI;
        end if;
        if idumpQ < 0 then
          absQ := not idumpQ;  -- cut price negation, nearly right!
        else
          absQ := idumpQ;
        end if;
        -- Determine quadrant
        reverse := (idumpI < 0) xor (idumpQ < 0);
        -- Determine direction of error
        error := reverse xor (absI > absQ);
        -- Determine whether in deadband?
        -- Make correction
        if error then
          carrier_delta <= to_unsigned(carrier_incr+1, NCO_bits);
        else
          carrier_delta <= to_unsigned(carrier_incr-1, NCO_bits);
        end if;
      end if;
    end if;
  end process;


  ------------------------------------------------------------------- LPF ---
  -- Output lowpass filter
  --
  LPF: process (Clk, Rst)
    variable sumI, sumQ: signed(baseband_bits-1 downto 0);

    function "sra"(x: signed; n: natural) return signed is
      variable xx: signed(x'length-1 downto 0) := x;
    begin
      for i in 1 to n loop
        xx := xx(xx'left) & xx(xx'left downto 1);
      end loop;
      return xx;
    end;

  begin

    if Rst = '1' then
      filterI <= (others => '0');
      filterq <= (others => '0');
      sumI    := (others => '0');
      sumQ    := (others => '0');
          idumpI  <= (others => '0');
          idumpQ  <= (others => '0');
    elsif rising_edge(Clk) then
      if dump = '1' then -- Dump integrator, generate output
        -- Output lowpass
        filterI <= resize(
                     filterI  + ((signed'((sumI - filterI) * filter_rate)) sra filter_shift),
                     filterI'length);
        filterQ <= resize(
                     filterQ  + ((signed'((sumQ - filterQ) * filter_rate)) sra filter_shift),
                     filterQ'length);
        -- dump the integrator
        sumI := (others => '0');
        sumQ := (others => '0');
      end if;
      -- Integrate (or initialise, if it's the dump cycle)
      sumI := sumI + prodI;
      sumQ := sumQ + prodQ;
      idumpI <= sumI;
      idumpQ <= sumQ;
    end if;

  end process;


  -- Produce the output
  --
  I <= filterI;
  Q <= filterQ;

end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -