QPSK调制的C实现

592 篇文章 7 订阅 ¥99.90 ¥299.90
13 篇文章 0 订阅

正交相移键控qpsk



正交相移键控(Quadrature Phase Shift Keyin,QPSK)是一种数字调制方式。它分为绝对相移和相对相移两种。由于绝对相移方式存在相位模糊问题,所以在实际中主要采用相对移相方式DQPSK。目前已经广泛应用于无线通信中,成为现代通信中一种十分重要的调制解调方式。
外文名 Quadrature Phase Shift Keying 简    介 卫星数字信号调制方式 原    理 实际的调谐解调电路 -特点 信号分布与调制数字比特之间映射 简    称 QPSK
目录
1 QPSK-简介
2 QPSK-原理
3 QPSK-特点
4 QPSK-OQPSK
5 QPSK-应用
QPSK-简介


  在数字信号的调制方式中QPSK是最常用的一种卫星数字信号调制方式,它具有较高的频谱利用率、较强的抗干扰性、在电路上实现也较为简单。偏移四相相移键控信号简称“O-QPSK”。全称为offset QPSK,也就是相对移相方式OQPSK。
相关:在HFC网络架构中,从用户线缆调制解调器发往上行通方式调制,并用TDMA方式复用到上行通道。
相关:在基于DVB-S的卫星通信电视系统中,卫星输出的电磁波信号就是使用QPSK调制方式的[1] 
QPSK-原理
QPSK数字解调包括:模数转换、抽取或插值、匹配滤波、时钟和载波恢复等。
在实际的调谐解调电路中,采用的是非相干载波解调,本振信号与发射端的载波信号存在频率偏差和相位抖动,因而解调出来的模拟I、Q基带信号是带有载波误差的信号。这样的模拟基带信号即使采用定时准确的时钟进行取样判决,得到的数字信号也不是原来发射端的调制信号,误差的积累将导致抽样判决后的误码率增大,因此数字QPSK解调电路要对载波误差进行补偿,减少非相干载波解调带来的影响。此外,ADC的取样时钟也不是从信号中提取的,当取样时钟与输入的数据不同步时,取样将不在最佳取样时刻进行所得到的取样值的统计信噪比就不是最高,误码率就高,因此,在电路中还需要恢复出一个与输入符号率同步的时钟,来校正固定取样带来的样点误差,并且准确的位定时信息可为数字解调后的信道纠错解码提供正确的时钟。校正办法是由定时恢复和载波恢复模块通过某种算法产生定时和载波误差,插值或抽取器在定时和载波误差信号的控制下,对A/D转换后的取样值进行抽取或插值滤波,得到信号在最佳取样点的值,不同芯片采用的算法不尽相同,例如可以采用据辅助法(DA)载波相位和定时相位联合估计的最大似然算法。
QPSK-特点
数字调制用“星座图”来描述,星座图中定义了一种调制技术的两个基本参数:
(1)信号分布;(2)与调制数字比特之间的映射关系
星座图中规定了星座点与传输比特间的对应关系,这种关系称为“映射”,一种调制技术的特性可由信号分布和映射完全定义,即可由星座图来完全定义。四相相移调制是利用载波的四种不同相位差来表征输入的数字信息,是四进制移相键控。QPSK是在M=4时的调相技术,它规定了四种载波相位,分别为45°,135°,225°,315°,调制器输入的数据是二进制数字序列,为了能和四进制的载波相位配合起来,则需要把二进制数据变换为四进制数据,这就是说需要把二进制数字序列中每两个比特分成一组,共有四种组合,即00,01,10,11,其中每一组称为双比特码元。每一个双比特码元是由两位二进制信息比特组成,它们分别代表四进制四个符号中的一个符号。QPSK中每次调制可传输2个信息比特,这些信息比特是通过载波的四种相位来传递的。解调器根据星座图及接收到的载波信号的相位来判断发送端发送的信息比特。
首先将输入的串行二进制信息序列经串-并变换,变成m=log2M个并行数据流,每一路的数据率是R/m,R是串行输入码的数据率。I/Q信号发生器将每一个m比特的字节转换成一对(pn,qn)数字,分成两路速率减半的序列,电平发生器分别产生双极性二电平信号I(t)和Q(t),然后对coswct和sinwct进行调制,相加后即得到QPSK信号。
QPSK是一种频谱利用率高、抗干扰性强的数调制方式, 它被广泛应用于各种通信系统中. 适合卫星广播。例如,数字卫星电视DVB-S2 标准中,信道噪声门限低至4. 5 dB,传输码率达到45M b[1] 


  实施
采用QPSK 调制方式,同时保证了信号传输的效率和误码性能。
一般的QPSK的实施,也表明高阶PSK的实施。在星座图中的正弦和余弦波用来传输方面的书面符号:
这就产生了四个阶段π/ 4,3π/ 4,5π/ 4和7π/ 4需要。
这个结果与单位的基础上功能在一个两维的信号空间被用作信号的同相分量和正交分量信号的第二首的基础功能。
因此,信号星座组成的信号空间4点,1/2的因素表明,两家运营商之间的分裂,同样的总功率。
这些基础功能,为BPSK比较清楚地表明如何观看可以作为两个独立的BPSK信号的QPSK。注意的BPSK信号空间分不需要分裂BPSK的星座图中显示的两家运营商在该计划的符号(位)能源的。
QPSK系统,可以实现在许多方面。发射机和接收机结构的主要组成部分的说明如下。
QPSK概念发射机结构。的二进制数据流分割成相和正交相的组成部分。这些都是再分别调制到两个正交的基函数。在此实现中,两个血窦。之后,这两个信号叠加,产生的信号是QPSK信号。注意:使用极不返回到零编码。可以摆在这些编码器的二进制数据源,但已放置后,说明涉及数字调制的数字和模拟信号之间的概念差异。
对于QPSK接收机结构。匹配的过滤器,可以与相关器代替。每个检测装置使用的参考阈值,以确定是否检测到1或0。
误码率
QPSK的,虽然可以作为解调看,这是比较容易看到它作为两个独立的调制正交载波。这种解释,偶数(或奇数)位用于调节承运人在相位分量,而奇数(或偶数)位被用来调制载波的正交相位分量。BPSK的两家航空公司,它们可以是独立的解调。
因此,QPSK的误码概率是相同的BPSK:
然而,为了达到相同的概率为BPSK的误码,QPSK的使用电源(因为两位同时传输)的两倍。
符号错误率计算公式如下:


  QPSK时域信号
如果信号信噪比高(实际QPSK系统是必要的)符号错误的概率可近似:
调制信号为一个随机的二进制数据流的短段如下。两个载波是一个余弦波和正弦波,通过信号空间分析上述表示。在这里,奇数位已被分配到同相分量和正交分量(以1号的第一个位)的偶数位。总的信号- 两个组成部分的总和- 显示在底部。可以看出,相位跳变的PSK改变了每个组件在每个位周期的开始阶段。仅最上面的波形匹配的BPSK上面给出的描述。
用于QPSK的时序图。时间轴下方所示的二进制数据流。两个组件用自己的位分配的信号显示的顶部和总,在底部的混合信号。注意:在第一阶段的一些位期间边界的突然变化。
这个波形传达的二进制数据是:1 1 0 0 0 1 1 0。
奇数位,在这里强调,在相分量:11000110
即使位,在这里强调,作出贡献的正交相位分量:11000110
QPSK-OQPSK
OQPSK是在QPSK基础上发展起来的一种恒包络数字调制技术。恒包络技术是指已调波的包络保持为恒定,它与多进制调制是从不同的两个角度来考虑调制技术的。恒包络技术所产生的已调波经过发送带限后,当通过非线性部件时,只产生很小的频谱扩展。这种形式的已调波具有两个主要特点,其一是包络恒定或起伏很小;其二是已调波频谱具有高频快速滚降特性,或者说已调波旁瓣很小,甚至几乎没有旁瓣。采用这种技术已实现了多种调制方式。OQPSK信号,它的频带利用率较高,理论值达1b/s/Hz。在QPSK中,当码组0011或0110时,产生180°的载波相位跳变。这种相位跳变引起包络起伏,当通过非线性部件后,使已经滤除的带外分量又被恢复出来,导致频谱扩展,增加对相邻波道的干扰。为了消除180°的相位跳变,在QPSK基础上提出了OQPSK。
一个已调波的频谱特性与其相位路径有着密切的关系,因此,为了控制已调波的频率特性,必须控制它的相位特性。恒包络调制技术的发展正是始终围绕着进一步改善已调波的相位路径这一中心进行的。
OQPSK也称为偏移四相相移键控,是QPSK的改进型。它与QPSK有同样的相位关系,也是把输入码流分成两路,然后进行正交调制。不同点在于它将同相和正交两支路的码流在时间上错开了半个码元周期。由于两支路码元半周期的偏移,每次只有一路可能发生极性翻转,不会发生两支路码元极性同时翻转的现象。因此,OQPSK信号相位只能跳变0°、±90°,不会出现180°的相位跳变。
QPSK-应用
QPSK数字电视调制器在对数据流的处理上采用能量扩散的随机化处理、RS编码、卷积交织、收缩卷积编码、调制前的基带成形处理等,保证了数据的传输性能。QPSK数字电视调制器采用了先进的数字信号处理技术,完全符合DVB-S标准,接收端可直接用数字卫星接收机进行接收。它不但能取得较高的频谱利用率,具有很强的抗干扰性和较高的性能价格比,而且和模拟FM微波设备也能很好的兼容。
性能特点:
1、进行原有的电视微波改造,可用30M带宽传送5至8套DVD效果的图像;
2、用调频微波的价格达到MMDS的效果,实现全向发射;
3、可进行数字加密,对图象绝无任何损伤。
中国的3G制式(CDMA2000,WCDMA,TD-SCDMA)均在下行链路上采用QPSK调制。
========

C语言实现QPSK

#include "math.h"
#include "stdlib.h"
#include "stdio.h"
#include  "time.h"
#include  "malloc.h"
#include  "string.h"
#include  "iostream.h"

#define source_length 1000000 
#define symbol_length source_length/2
#define SNR_start 1
#define SNR_end 10
#define SNR_step 1 
#define PI 3.1415926
#define Coderate 1

typedef struct {
	double Rpart;
	double Ipart;
}complex;

 int source[source_length];//message(),modulate(),error()
 int change[source_length];//modulate()
 int resource[source_length];    //demodulate(),error()
 complex modulatesym[symbol_length];   //demodulate(),channel(),moudulate()
 int snr;//channel(),error()
int errorbit, errorsym;//error()
 double BER,SER;//error()

void message();
void modulate(int source[source_length]);
void channel(complex modulatesym[symbol_length],int snr);
void demodulate();
void error();

//随机信号产生
void message()
{
	int i;
	//以当前时间作为时间种子
	srand((unsigned)time(NULL));
	//产生0,1随机信号
	for(i=0;i<source_length;i++)
	{ source[i]=rand()%2;
		//cout<<source[i];
	}
	//cout<<endl;
}

//调制
void modulate(int source[source_length])
{
	int i,j;
	//0->-1,1->1
  for(i=0;i<source_length;i++)
  {   
	change[i]=1-2*source[i];
	
  }		
	
   for(j=0;j<symbol_length;j++)
   {   
	   modulatesym[j].Rpart=change[2*j];//cout<<change[2*j];
       modulatesym[j].Ipart=change[2*j+1];//cout<<change[2*j+1];
   }
  // cout<<endl;
}

//调制信号通过信道
void channel(complex modulatesym[],int snr)
{
	long int j;
	double r1,r2;
	double amp,phase;
	double sn,SNR,noise[2];
	SNR=snr+10*log10((double)Coderate);
	sn=pow(10.0,SNR/10.0);
	for(j=0;j<symbol_length;j++)
	{
		r1=(double)rand()/RAND_MAX;
		r2=(double)rand()/RAND_MAX;
		if(r1<=1.0e-8) 	r1=1.0e-8; //防止出现log0的操作
		phase=2.0*PI*r2;
		amp=sqrt(-log(r1)/sn);
		noise[0]=amp*cos(phase);
		noise[1]=amp*sin(phase);
		modulatesym[j].Rpart=modulatesym[j].Rpart+noise[0];//cout<<modulatesym[j].Rpart;
    	modulatesym[j].Ipart=modulatesym[j].Ipart+noise[1];//cout<<modulatesym[j].Ipart;
		
	}
	//cout<<endl;
}

//解调
void demodulate()
{    
	for(int j=0;j<symbol_length;j++)
    {
	   if (modulatesym[j].Rpart>0)
	      resource[2*j]=0;
	   else //if(modulatesym[j].Rpart<=0)
		   resource[2*j]=1;
	}
	for(int i=0;i<symbol_length;i++)
	{
	   if (modulatesym[i].Ipart>0)
		   resource[2*i+1]=0;
	   else //if(modulatesym[j].Ipart<=0)
           resource[2*i+1]=1;
	   }
}

void error()
{
  long int i,j;
  errorbit=0;
  errorsym=0;

  for(i=0;i<source_length;i++)
  { if(resource[i]!=source[i])
        errorbit++;
  }
  for(j=0;j<=symbol_length;j++)
  {
	  if(resource[2*j]!=source[2*j]||resource[2*j+1]!=source[2*j+1])
		  errorsym++;
  }

  BER=(double)errorbit/source_length;
  SER=(double)errorsym/symbol_length;
cout<<"snr="<<snr<<endl;
cout<<"source_length="<<source_length<<endl;
cout<<"symbol_length="<<symbol_length<<endl;
cout<<"errorbit="<<errorbit<<endl;
cout<<"errorsym="<<errorsym<<endl;
cout<<"BER="<<BER<<endl;
cout<<"SER="<<SER<<endl;
}

void main()
{
	for(snr=SNR_start;snr<=SNR_end;snr+=SNR_step)
		
	{
		message();
		
		modulate(source);
		channel(modulatesym,snr);
		demodulate();
		/*for(int i=0;i<source_length;i++)
				{ 
					cout<<resource[i];
				}
		cout<<endl;*/
		error();
	}	
}


========

C++ 实现QPSK


#include<iostream>
#include<time.h>
using namespace std;

#define source_length 1000000 
#define symbol_length source_length/2
#define SNR_start 1
#define SNR_end 10
#define SNR_step 1 
#define PI 3.1415926
#define Coderate 1

typedef struct {
	double Rpart;
	double Ipart;
}complex;

int source[source_length];
int change[source_length];
int resource[source_length];  
complex modulatesym[symbol_length];   
int snr;
int errorbit, errorsym;
double BER, SER;

//随机信号产生
void message()
{
	int i;
	//以当前时间作为时间种子
	srand((unsigned)time(NULL));
	//产生0,1随机信号
	for (i = 0; i<source_length; i++)
	{
		source[i] = rand() % 2;
		//cout<<source[i];
	}
	//cout<<endl;
}

//调制
void modulate(int source[source_length])
{
	int i, j;
	//0->-1,1->1
	for (i = 0; i<source_length; i++)
	{
		change[i] = 1 - 2 * source[i];
	}

	for (j = 0; j<symbol_length; j++)
	{
		modulatesym[j].Rpart = change[2 * j];//cout<<change[2*j];
		modulatesym[j].Ipart = change[2 * j + 1];//cout<<change[2*j+1];
	}
	// cout<<endl;
}

//解调
void demodulate()
{
	for (int j = 0; j<symbol_length; j++)
	{
		if (modulatesym[j].Rpart>0)
			resource[2 * j] = 0;
		else //if(modulatesym[j].Rpart<=0)
			resource[2 * j] = 1;
	}
	for (int i = 0; i<symbol_length; i++)
	{
		if (modulatesym[i].Ipart>0)
			resource[2 * i + 1] = 0;
		else //if(modulatesym[j].Ipart<=0)
			resource[2 * i + 1] = 1;
	}
}

//调制信号通过信道
void channel(complex modulatesym[], int snr)
{
	long int j;
	double r1, r2;
	double amp, phase;
	double sn, SNR, noise[2];
	SNR = snr + 10 * log10((double)Coderate);
	sn = pow(10.0, SNR / 10.0);
	for (j = 0; j<symbol_length; j++)
	{
		r1 = (double)rand() / RAND_MAX;
		r2 = (double)rand() / RAND_MAX;
		if (r1 <= 1.0e-8) 	r1 = 1.0e-8; //防止出现log0的操作
		phase = 2.0*PI*r2;
		amp = sqrt(-log(r1) / sn);
		noise[0] = amp*cos(phase);
		noise[1] = amp*sin(phase);
		modulatesym[j].Rpart = modulatesym[j].Rpart + noise[0];//cout<<modulatesym[j].Rpart;
		modulatesym[j].Ipart = modulatesym[j].Ipart + noise[1];//cout<<modulatesym[j].Ipart;
	}
	//cout<<endl;
}

void error()
{
	long int i, j;
	errorbit = 0;
	errorsym = 0;

	for (i = 0; i<source_length; i++)
	{
		if (resource[i] != source[i])
			errorbit++;
	}
	for (j = 0; j <= symbol_length; j++)
	{
		if (resource[2 * j] != source[2 * j] || resource[2 * j + 1] != source[2 * j + 1])
			errorsym++;
	}

	BER = (double)errorbit / source_length;
	SER = (double)errorsym / symbol_length;
	cout << "snr=" << snr << endl;
	cout << "source_length=" << source_length << endl;
	cout << "symbol_length=" << symbol_length << endl;
	cout << "errorbit=" << errorbit << endl;
	cout << "errorsym=" << errorsym << endl;
	cout << "BER=" << BER << endl;
	cout << "SER=" << SER << endl;
}

int main()
{
	message();
	modulate(source);
	channel(modulatesym, snr);
	//cout << endl;
	demodulate();
	//for (int i = 0; i < source_length; i++)cout << resource[i];
	error();
	return 0;
}



========
  • 12
    点赞
  • 91
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: QPSK调制是一种常用的数字调制技术,可以在有限的频谱中传输两个比特的信息。下面是一个简单的在C语言实现QPSK调制的例子: ```c #include <stdio.h> #include <math.h> #define PI 3.14159265359 int main() { // 定义输入比特流 int inputBits[8] = {0, 1, 0, 1, 1, 0, 1, 0}; // 定义QPSK调制映射表 double qpskSymbolReal[4] = {-1/sqrt(2), 1/sqrt(2), 1/sqrt(2), -1/sqrt(2)}; double qpskSymbolImag[4] = {1/sqrt(2), 1/sqrt(2), -1/sqrt(2), -1/sqrt(2)}; // 定义输出复数序列 double outputI[4]; double outputQ[4]; // 进行QPSK调制 int i; for (i = 0; i < 8; i += 2) { int index = inputBits[i] * 2 + inputBits[i+1]; outputI[i/2] = qpskSymbolReal[index]; outputQ[i/2] = qpskSymbolImag[index]; } // 打印输出复数序列 printf("QPSK调制输出:\n"); for (i = 0; i < 4; i++) { printf("I: %f, Q: %f\n", outputI[i], outputQ[i]); } return 0; } ``` 以上代码实现了一个简单的QPSK调制过程,首先定义了一个输入比特流(此处为固定值),然后定义了QPSK调制映射表。通过遍历输入比特流,将每两个比特映射到对应的QPSK符号上,并将实部和虚部存储到输出复数序列中。最后,通过printf函数打印输出复数序列。 需要注意的是,以上代码仅实现QPSK调制的基本功能,实际应用中可能需要加入其他处理步骤,如码扰与滤波等。同时,代码中的QPSK映射表以及输出复数序列只是示例,实际应用中可能需要根据具体需求进行修改。 ### 回答2: QPSK调制是一种常用的数字调制技术,用于将数字信号转换为模拟信号,以便在通信系统中进行传输。在C语言实现QPSK调制的过程如下: 首先,我们需要定义一些关于QPSK调制的参数,包括载波频率、符号速率、采样率等等。假设我们选择的载波频率为fc,符号速率为fs,采样率为fsample。 接下来,我们需要生成QPSK调制的信号。首先将需要传输的数字信号转换为二进制比特流,然后将比特流划分为两个一组,分别代表实部和虚部。假设我们将比特流存储在一个长度为N的数组中。 然后,我们需要生成QPSK调制信号的载波波形。使用正弦函数和余弦函数分别生成实部和虚部的载波信号。假设我们生成的载波信号存储在两个长度为N的数组中。 接下来,我们将实部和虚部的载波信号叠加,并进行抽样。在每个符号周期内,我们选择一个采样点作为结果信号的一个采样,这个采样点的位置可以根据符号速率和采样率计算得出。 最后,我们将得到的QPSK调制信号输出,即可进行后续的传输或处理。 以上就是使用C语言实现QPSK调制的简单步骤。实际实现时,我们可能还需要考虑一些细节问题,如使用滤波器对信号进行滤波,生成随机的相位偏移等等。同时也可以借助一些现有的信号处理库或函数,如MATLAB等,来简化开发过程和提高程序的性能和准确性。 ### 回答3: QPSK调制是一种常见的调制方式,通过将两路正交的基带信号分别映射到不同的相位上实现信号的调制。在C语言中,我们可以使用一些基本的数学运算和逻辑操作来实现QPSK调制。 首先,我们需要定义两路正交的基带信号,可以用两个数组分别表示,如I_signal和Q_signal。假设每个数组中有N个采样点。 接下来,我们需要将这两路信号映射到相位上,QPSK调制中通常用四个相位表示四个符号,即0度、90度、180度和270度。 我们可以定义一个相位数组,如phase = {0, 90, 180, 270}。然后利用一个循环,将I_signal和Q_signal中的每个采样点按照映射规则转换为相应的相位。 具体实现过程如下: ```C #include <stdio.h> #define N 100 // 采样点数 int main() { int I_signal[N]; // I路信号 int Q_signal[N]; // Q路信号 // 假设已经给出了I_signal和Q_signal的数据 int phase[4] = {0, 90, 180, 270}; // 四个相位 for (int i = 0; i < N; i++) { // 将I_signal和Q_signal中的每个采样点映射为相应的相位 int symbol = 2 * I_signal[i] + Q_signal[i]; // 根据映射规则计算符号 int phase_index = symbol % 4; // 计算相位数组的下标 int phase_value = phase[phase_index]; // 根据下标得到相位值 printf("第%d个采样点的相位为%d度\n", i+1, phase_value); } return 0; } ``` 上述代码是一个简单的QPSK调制实现的示例,实际应用中可能需要根据具体需求进行更加复杂的处理。请根据实际情况进行适当的修改。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值