要進行QAM調制的仿真首先要了解QAM調制的基本原理,QAM調制是一種根據數字基帶信號同時控制載波的幅度和相位的調制方式,也就是說對應不同的1和0的基帶信號,載波的幅度和相位都可以發生變化,

根據這個調制方式可以得到QAM的帶通信號的公式可以表示為

根據這個公式我們還不能進行仿真,我們還需要將這個公式做進一步的展開,

查看展開后的公式可以發現,一個QAM信號的碼元波形,可以通過I路和Q路兩路幅度調制的信號疊加而成,由于cost和sint是正交的,所以這是兩路正交信號的疊加,
所以,如果我們想要的到一個QAM信號的碼元波形,就要分別得到I路的幅度值,和Q路的幅度值,這里以16QAM為例進行說明,由于16QAM是16進制的,每4個位元為一組對應一個帶通信號的碼元波形, 對于給定的基帶信號的位元流,就要每4個為一組,每一組繪制出對應的帶通信號的碼元波形,

基帶信號的4個位元,有16種不同的位元組合,

要進行仿真就要給出這16種位元組合中,每種位元組合對應的帶通信號的碼元波形是多少,要想得到碼元波形,就要知道I路和Q路的幅度值分別是多少,

接下來 就設定仿真中1和0的位元組合對應的I路和Q路的幅度值如下,將I路振幅對應前兩個位元b0b1,Q路對應后兩個位元b2b3,I路信號的四個振幅+3A +A -A -3A與位元b0b1的四個組合11 10 01 00相對應,Q路信號也采用相同的對應關系,

這樣對于一個基帶信號的位元組合,我們就可以對應到I路和Q路的不同幅度值,
例如基帶信號中的1101,前面的兩個位元11就對應I路幅度值+3A,后面兩個位元01對應著Q路幅度值-A,這樣基帶信號1101對應的兩路正交載波的振幅就可以得到了,

將I路載波乘以3進行振幅調制,Q路載波乘以-1進行振幅調制.再將兩路正交載波經過振幅調制后的波形想加就得到了16QAM調制后的波形,可以發現1101對應的碼元波形振幅為3.162A,相位為341.60 ,需要注意的是16QAM帶通信號碼元寬度應該是基帶信號碼元寬度的4倍,
由于在仿真中每個碼元信號的波形,要對應一個I路幅度值,一個Q路幅度值,還有碼元本身的幅度值和相位,

這種復雜的對應關系可以保存在一個星座圖中,

矩陣圖中的一個點對應了一種位元組合,到原點的距離對應著帶通信號的振幅,該點的相位對應這帶通信號的相位,該點的橫坐標對應I路振幅,縱坐標對應Q路振幅,這樣就將位元組合對應帶通信號直觀的展現出來了,16QAM有16中位元組合,因此星座圖中就有16個點,

接下來我們看一下如何進行16QAM星座和波形的Python仿真,
首先是星座圖的繪制,
import numpy as np
import matplotlib.pyplot as plt
digram = {'11':3,'10':1,'01':-1,'00':-3}#設定數字和幅度的對應關系
spots = {}#放置點
plt.figure()
plt.xlabel('I',loc='right',labelpad = 0.5)
plt.ylabel('Q',loc='top',labelpad = 0.5) # 設定坐標軸的文字標簽
ax = plt.gca() # get current axis 獲得坐標軸物件
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none') # 將右邊 上邊的兩條邊顏色設定為空 其實就相當于抹掉這兩條邊
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left') # 指定下邊的邊作為 x 軸 指定左邊的邊為 y 軸
ax.spines['bottom'].set_position(('data', 0)) # 指定 data 設定的bottom(也就是指定的x軸)系結到y軸的0這個點上
ax.spines['left'].set_position(('data', 0))
plt.axis([-5,5,-5,5])#設定坐標的數字范圍
for i in ['0','1']:
for j in ['0','1']:
for k in ['0','1']:
for p in ['0','1']:
str = ''.join([i,j,k,p])#通過回圈獲得16個4位數的10組合
str1 = ''.join([i,j])#前兩個10組合
a = digram[str1]#獲取前兩個10組合對應的幅值
# a = int(a)
str2 = ''.join([k,p])
b = digram[str2]#獲取后兩個10組合對應的幅值
# b = int(b)
complexSpot = complex(a,b)#不能寫為a+bj,因為編譯不通過 生成坐標
plt.scatter(a,b,c='black')#繪制點
plt.text(a, b+0.3, str, fontsize=10, color = "black", weight = "light", verticalalignment='center', horizontalalignment='center', rotation=0)#繪制10組合
tempspot = {str:complexSpot}#獲得數字組合和點
spots.update(tempspot)#存入點的集合
plt.show()
首先將16QAM中位元與振幅的對應關系保存在Python的字典物件diagram中,然后通過for回圈遍歷出16種不同的位元組合放在變數str種,str中的前兩個位元取出來放到str1變數中,查詢字典可以得到I路幅值存到變數a中,str中的后兩個位元取出來放到str2變數中,查詢字典可以得到Q路幅值存到變數b中.有了I路的幅度值和Q路幅度值就可以定位位元組合對應的點的位置了,這里將I路幅度值a和Q路幅度值b保存在Python特有的資料型別一個復數變數complexSpot中,這樣16中不同的位元組合就對應了16個不同的復數,每個復數就對應了一個坐標軸里的點的位置,16個位元組合和復數的對應關系作為字典型別保存在了spot中,運行以上程式就得到了16QAM波形圖,
觀察星座圖可以發現16QAM共有三個不同的幅度,12個不同的相位,相鄰位元需符合格雷碼編碼方式,

與16PSK星座圖相比較,16QAM星座圖中點和點之間的距離較遠,這就表示16QAM符號間更加不容易產生相互干擾,通常進制數M增加,會引起誤碼率的增加,

因此在5G網路中,M<=8時采用MPSK;M>8時誤碼率就會繼續增加,從而采用具有更好抗噪聲性能的QAM,一般 16QAM是最低階的QAM,在實際網路中,會根據信道條件相應調整調制方式,信道條件越好,就可以采用越高階的調制方式,

通過星座圖我們也可以詳細的看到16種位元組合對應的16個碼元波形,

有了16QAM星座圖,就有了16種位元組合分別對應的I路和Q路幅度值,接下來就可以將需要進行調制的基帶信號的位元流,每四個為一組進行帶通信號碼元的繪制,由于在繪制星座圖的時候就已經保存了位元組合和I路和Q路幅度值的對應關系,因此對于基帶信號,只需要每次繪制4個位元,先查詢4個位元對應的I路和Q路幅度值,然后分別與兩路載波相乘,然后相加就可以得到當前4個位元對應的碼元波形了,最后將所有的碼元波形都追加到一個串列中,進行圖形繪制,就得到了基帶信號位元流所對應的帶通信號的波形圖,

import numpy as np
import matplotlib.pyplot as plt
bitsToAmp = {'11': 3, '10': 1, '01': -1, '00': -3} # 設定數字和幅度的對應關系
spots = {} # 放置點
for i in ['0', '1']:
for j in ['0', '1']:
for k in ['0', '1']:
for p in ['0', '1']:
strs = ''.join([i, j, k, p]) # 通過回圈獲得16個4位數的10組合
str1 = ''.join([i, j]) # 前兩個10組合
a = bitsToAmp[str1] # 獲取前兩個10組合對應的幅值
a = int(a)
str2 = ''.join([k, p])
b = bitsToAmp[str2]
b = int(b) # 獲取后兩個10組合對應的幅值
complexSpot = complex(a, b) # 不能寫為a+bj,因為編譯不通過 生成坐標
tempSpot = {strs: complexSpot} # 獲得數字組合和點
spots.update(tempSpot) # 存入點的集合
fig = plt.figure()
t = np.arange(0, 12.0, 0.5) # 設定基帶信號10的坐標軸,每隔0.5的距離繪制一個基帶的二進制信號,一共16個位元
# input
plt.subplot(2, 1, 1)
y1 = [0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1]
plt.plot(t, y1, drawstyle='steps-post') # 將16個位元每隔0.5繪制到坐標系上
plt.xlim(0, 12)
plt.ylim(-0.5, 1.5)
plt.title('16QAM modulation')
# 串并變換
l4 = int(len(y1) / 4) # 獲取位元流的長度除以4,4個位元為一組,則共有多少組
a = np.asarray(y1) # 將基帶信號轉換為numpy格式
y2 = a.reshape(l4, 4) # 將一維陣列轉置為二維陣列,每一行中有4個位元的資料
plt.subplot(2, 1, 2)
t = np.arange(0, 12., 0.01) # 橫坐標的資料串列,每個0.01繪制一個點
rectwav = [] # 用來存盤縱坐標值的串列
# i表示第i個線段,每個線段對應一個二進制的四位組合s0s1s2s3,每個線段的長度為2,是基帶信號每個信號長度0.5的四倍
for i in range(l4):
b = y2[i] # 取出第i組四位陣列合s0s1s2s3
str4Bits = str(b).strip('[').strip(']').replace(' ', '') # 將串列中的4個位元轉換為字串并且去掉[ ] 和空格
complexWave = spots[str4Bits] # 根據四個位元的字串對應到字典中的復數,得到橫坐標和縱坐標的幅度,I Q的幅度值
xWave = complexWave.real # 取出橫坐標的值
yWave = complexWave.imag # 取出縱坐標的值
# 在t陣列中第i段橫坐標的點數,此處每個段的波形長度應該是0.5的4倍,也就是2
t_tmp = t[(i * 200):((i + 1) * 200)]
xI_tmp = xWave * np.ones(200) # 200個橫坐標的幅度值
yQ_tmp = yWave * np.ones(200) # 200個縱坐標的幅度值
# 將幅度分別與兩個正交載波相乘求和
wav_tmp = xI_tmp * np.cos(2 * np.pi * 5 * t_tmp) - yQ_tmp * np.sin(2 * np.pi * 5 * t_tmp)
rectwav.append(wav_tmp) # 將調制后的點加到總的波形串列中
# 繪制調制后的波形
plt.plot(t, np.array(rectwav).flatten())
plt.xlim(0, 12)
plt.ylim(-5, 5)
plt.tight_layout()
plt.show()
通過波形圖可以觀察到16QAM每個碼元對應4個位元,不同位元組在振幅和相位上都有不同變化,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/345749.html
標籤:python
