Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
17 years ago

vhdl for qpsk modem

hi.. i'm a beginner and currently working on qpsk modem using cyclone II, . I'm really need vhdl code for qpsk modulator and demodulator. I will use it and implement into fpga. Any help on it are most welcome.Plezz..

10 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    Have you tried a search in altera/xilinx site or google(free core).

    You can write for a simple qpsk by having some binary stream then map every pair into one symbol(i.e. pick up pairs sequentially and allocate to each a signal value.You will need two channels of this signal(call them I,Q)

    Mapping is arbitrary (though predetermined for certain schemes) e.g. you can map as follows(for 8 bits):

    00 => I=127,Q=127

    01 => I=127,Q=-127

    10=> I=-127,-127

    11=> I=-127,127

    After mapping, you need to shape the pulses, a common filter used is rrcos(root raised cosine in comms, or gaussian in mobile industry).

    After shaping you need to pass the signals I,Q to a carrier(upconversion). This is done in a complex multiplier that takes in I/Q and sin/cos of your chosen carrier frequency.

    Next you convert the upconverted symbols to analogue(some DACs do the above complex mult as well), if DAC's input speed is more than symbol rate(and this is common)then you need to upsampe the symbols i.e. use interpolation to lift up your signal to DAC speed.

    So, there is a lot of learning here. The domodulator is more difficult and has to filter noise,lock to carrier then to clock then reverse the mapping.

    kaz
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    hi..thanx for your quick responds. I'm just wondering.. is there any example of vhdl code for qpsk modem?? i've made some search before on this topic and i have found lots of theory. But i really have no idea how to write it in vhdl since i'm only the beginner and still study about it.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    First, use a language that you know well to simulate your QPSK modem in floating point.

    Move from that point into a fixed point domain (simulating the ADC with fixed dynamic range, etc).

    From there, partition the design into independent blocks.

    Finally, write those blocks into Verilog or VHDL.

    At the end, you should have a good synthesizable modem!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    www.opencores.org

    have plenty of cores. I haven't used them but may be useful source for some of us.

    I know they got ofdm modulator but not sure about basic qpsk.

    kaz
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    sir..

    i've been able to create vhdl code for each block in qpsk modulator part.

    But, there are 1 block that have an error.

    it is for unipolar to bipolar.. i need to the incoming data for both I-channel and Q-channel which consist of logic 1 or logic 0. i want to change logic 1 to 1 and logic 0 to -1.

    here are the code that i have write for unipolar to bipolar converter.

    ----------------UNIPOLAR TO BIPOLAR---------------[LOGIC 0=-1, LOGIC 1=1]-------

    LIBRARY ieee;

    USE ieee.std_logic_1164.all;

    USE ieee.std_logic_unsigned.all;

    USE ieee.std_logic_signed.all;

    USE ieee.numeric_std.all;

    ------------------defines two types: unsigned and signed

    ENTITY unipolar_bipolar IS

    PORT(

    in_i,in_q : IN std_logic_vector (3 downto 0); -------4 bit-------

    bI,bQ: OUT std_logic_vector (3 downto 0) -------4 bit-------

    );

    END unipolar_bipolar ;

    ARCHITECTURE beh OF unipolar_bipolar IS

    signal p: integer;------------out

    signal k: integer;-------------in

    signal n: std_logic_vector(3 downto 0);--------------out(final)

    signal i:integer; -----------------------for loop 0 until 3 (4 bit)-----------

    begin

    for i=> '0';

    LOOP

    i=n;

    when in_i(n)=> k & in_q(n)=> k then

    case k is

    when k ='0' then -----must invert to signed value---[-1]

    p <= '1'; -------in std_logic

    out_q(n)<= conv_integer(p);

    out_i(n) <= conv_integer(p); --------convert into integer(signed)

    end case;

    case k is

    when k ='1' then-----must invert to unsigned value--[1]

    p <= '1'; -------in std_logic

    out_q(n)<= conv_integer('0'& p);

    out_i(n) <= conv_integer('0' & p); --------convert into integer(unsigned)

    end case;

    n = i+1;

    when n='3' loop;

    end LOOP;

    end beh;

    hope you can help me as soon as possible..

    thank you so much..
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    I am afraid I don't see anything correct or synthesizable in your code.

    It is much simpler than that. If your data is a serial bit stream then you need to convert every two bits(every pair) into signed I and Q straightaway:

    First convert your stream from 1 bit serial to two bit parallel then use a basic construct to output I/Q(mapping):

    assuming you converted your one bit data to the two bit sub_data then:

    case sub_data is

    .........when "00" =>

    ...................... I <= std_logic_vector(to_signed(32767,16));

    ......................Q <= std_logic_vector(to_signed(32767,16));

    .........when "01" =>

    ...................... I <= std_logic_vector(to_signed(32767,16));

    ......................Q <= std_logic_vector(to_signed(-32767,16));

    .........when "10" =>

    ...................... I <= std_logic_vector(to_signed(-32767,16));

    ...................... <= std_logic_vector(to_signed(32767,16));

    .........when "11" =>

    ...................... I <= std_logic_vector(to_signed(-32767,16));

    ......................Q <= std_logic_vector(to_signed(-32767,16));

    end case;

    notice that I/Q are 16 bits each ready for DAC, use whatever resolution you want for your DAC. The maximum level of 32767 may be too high and you can go lower if you want.

    so in short think of serial-parallel converter module followed by mapping module(or do both in one module)

    Your serial-to-parallel is a bit more difficult than the mapper. The output pairs must be at half speed of the input data stream and you should pair-up correctly(it is quite easy but many experienced designers could go wrong on pairing boundaries)

    You better try it first then if you come up with more code like the one you posted you should get some help before your compiler loses patience.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    hi sir..

    thank you for your quick reply.

    i want to ask you about how to convert std_logic_vector to signed and unsigned...

    let say.. when input => '1' then

    output <= ---------?? (unsigned)

    what are the syntax that can be used to convert to unsigned..

    and when input => '0' then

    output <= ---------?? (signed)

    what are the syntax that can be used to convert to signed..

    and what are the library that need to be used.. is it use ieee.std_logic_unsigned and use ieee.std_logic_signed or is it enough to just use ieee.numeric_std.all??

    hope to hear from you soon.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    Your wording indicates some unclear thoughts. You only need signed thinking. You got nothing to do with unsigned. The value 32767 means +32767 and doesn't mean unsigned. In each case of positive or negative values the MSB is used as sign bit(0 for +, 1 for -).

    We are talking here about 2's complement as is the case with most fpga signed computations. Check your DAC number system...

    Anyway for conversion between std_logic_vector and signed or unsigned

    try numeric_std library.

    std_logic <=> signed, std_logic <=> unsigned

    just use direct cast e.g.

    d_signed <= signed(data); -- data is std_logic_vector

    d_unsigned <= unsigned(data); -- data is std_logic_vector

    d_std_logic <= std_logic_vector(data); -- data is signed

    d_std_logic <= std_logic_vector(data); -- data is unsigned

    for integer to signed/unsigned you need one stage conversion only,define bitwidth:

    I <= to_signed(32767,16); -- I being signed

    I <= to_unsigned(32767,16); -- I being unsigned

    for integer <=> std_logic_vector you need two stages(cast plus conversion, you need define bitwidth)

    I <= std_logic_vector(to_signed(32767,16)); -- 7FFF, 15 bits magnitude

    I <= std_logic_vector(to_signed(-32767,16)); -- 8001h, 15 bits magnitude

    I <= std_logic_vector(to_unsigned(32767,16)); -- 7FFF, 16 bits magnitude

    edit:

    some engineers feel that VHDL is too complicated and unfriendly at this type conversion and have raised concerns to ieee. There is certainly room for improvement and mercy.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    sir..

    my dac is 8 bit.

    what i'm try to say is...

    my input is 8 bit which can be either logic 0 or 1.

    when the data is logic 1... the output that i want is 1...

    when the data is logic 0.. the output is -1..

    so..i think.. first i need to declare that each output gonna be 1 but it is either unsigned(+ve number) or signed (-ve number)...to get the value of 1 or -1.

    if my input is in std_logic_vector.. how can i compare this by 1 bit (std_logic)??
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I already stated in plain language that:

    --- Quote Start ---

    Your wording indicates some unclear thoughts. You only need signed thinking.

    --- Quote End ---

    You cannot think of signed/unsigned at the same time, it is not just terminology but two different number systems.

    Your DAC range is +127 and not +1. You cannot send symbols to a satellite using +1 levels, you need good power signal to get through. Some people talk about +1 in a symbolic(logic) sense.

    your input is 8 bits wide. You have to think of communications as one serial bit because you can't(normally) send parallel data buses in sky. so you convert it to serial stream one after the other(starting with MSB or LSB or anywhere you like as long as your receiver knows how to reconstruct your 8 bit values.

    So your tasks are:

    1) convert 8 bit input to a serial one bit stream

    2) convert every two successive bits into a set of IQ values

    steps 1 & 2 can be combined like this: at every input sample(valid clk)

    think: bit(7) and bit(6) as pair 1, bit(5)& bit(4) as pair 2, bit(3) &bit(2) as pair 3, bit(1) & bit(0) as pair 4.

    action:convert each above pair to IQ pair of values as below and send IQ pair 1,IQ pair 2, IQ pair 3, IQ pair 4 sequentially to DAC(now in the form of +127).

    your new mapping code can be like this

    case sub_data is

    .........when "00" =>

    ...................... I <= std_logic_vector(to_signed(127,8));

    ......................Q <= std_logic_vector(to_signed(127,8));

    .........when "01" =>

    ...................... I <= std_logic_vector(to_signed(127,8));

    ......................Q <= std_logic_vector(to_signed(-127,8));

    .........when "10" =>

    ...................... I <= std_logic_vector(to_signed(-127,8));

    ......................Q <= std_logic_vector(to_signed(127,8));

    .........when "11" =>

    ...................... I <= std_logic_vector(to_signed(-127,8));

    ......................Q <= std_logic_vector(to_signed(-127,8));

    end case;

    At the DAC output your analogue signal will hopefully swing full scale voltage

    and that is what some call +1 or as you call it bipolar.

    The RF engineer will then do the rest. He will map your voltage swings to phase swings. He will generate a really fast frequency e.g. 500MHz sinusoid.(RF engineers live on these sinusoids).

    He will change the phase of his sinusoid through 90 degrees for every change of your DAC swing. The final carrier will be sent to power amplifier and into the aerial......In practice he will be very angry if you don't smooth those sharp corners of your +127 symbols in the digital domain. He can shape them in his analogue domain but they don't do that anymore...