Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)

vhdl for qpsk modem

Altera_Forum
Honored Contributor II
2,337 Views

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..

0 Kudos
10 Replies
Altera_Forum
Honored Contributor II
1,318 Views

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
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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.

0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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!
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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..
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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)??
0 Kudos
Altera_Forum
Honored Contributor II
1,318 Views

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...
0 Kudos
Reply