記錄采用Xilinx ZYNQ系列板卡+AD9361實現簡單2x2 MIMO通信過程


2020-06-19

寫在最前,本文對MATLAB提供的例程做了一些檢索和解讀,並在自己的需求上做了更改。

最近一段時間老師不知道在研究些啥,突然之間對硬件產生了濃厚的興趣,並且為我們20級的新生購置了幾塊SDR設備。雖然不知道為什么,但是拿着這些板子也可以作為無聊的宅家消遣,畢竟我已經半年沒有去過學校了。

軟件/硬件 准備

硬件

本次使用到的硬件為ZedBoard,是一塊Xilinx ZYNQ 7000系列的開發板,該開發板的特點是成本低,操作簡單,ARM處理器附帶一塊ZYNQ-7000系列的FPGA。我個人而言對硬件不甚了解,在與同學的探討中認為這塊板子上的FPGA核是作為輔助運算而存在的。在本次實驗中,主要采用MATLAB作為編程平台,通過一個Linux系統驅動ARM核心,並且由ARM核調用FPGA進行部分運算。這塊板子可以采用Vivado HLS那一套工具做相對低層次一些的開發,而我作為不太懂得硬件描述語言的人而言只能采用MATLAB工具作為主要編程工具。

除了Zedboard以外,在擴展接口上我們連接了一塊FMCOMMS3的板卡,是一塊基於AD9361的射頻卡,這將作為本次通信實驗的收發機。

軟件

PC上的操作需要全程依賴MATLAB進行,因此首先安裝對應的支持包。在附加功能中找到獲取硬件支持包,在其中搜索Communications Toolbox Support Package for Xilinx Zynq-Based Radio即可找到對應支持,按提示安裝即可。下載比較慢的情況可以酌情使用科學 上網工具。安裝過程比較久。

實際上安裝持續了將近一個小時

安裝后開始簡單的硬件測試階段,點擊配置選項按步驟進行硬件的配置,按照右側對話框的內容配置zedboard,最后可以運行一個小腳本驗證。

這個配置過程主要在於給SD卡寫入一個小型Linux系統用於ARM控制。zynq系列板卡本質上相當於ARM板攜帶了一塊高性能FPGA,采用SD卡的啟動方式也是為ARM芯片服務。在默認配置中,板卡的IP地址會被設置為192.168.3.2,此時計算機網卡對應有線網的IP地址會被MATLAB自動設置為192.168.3.1,當我們使用網絡時可能需要恢復為之前的設置,因此建議先對原來的IPv4配置進行保存。處理后根據要求斷開板卡的電源開關,將跳線帽設置為正確位置,插入SD卡與網線,網線連接計算機之后接通電源開始啟動。當板卡完全啟動后,MATLAB會給出一個簡單的SDR腳本,測試板卡的各個通道是否可以正常工作。這里采用的AD9361支持兩路發射兩路接收,在通信中相當於全數字\(2\times 2\) MIMO系統,而測試腳本則每次只激活一個收發RF鏈路進行測試。該測試主要是單音測試,代碼比較簡單,設置了單音信號參數后會在I路Q路分別發送正交的單音信號,並重復發射到結束,接收機則進行接收,並在分析窗口展示接收到的波形、星座圖與頻譜圖。

需要額外說明的是,信號處理與分析的主要工作是在PC端完成的。

在實驗前也還需要確保MATLAB中的LTE Toolbox以及Communication Toolbox已經被正確安裝。

1x1 MIMO系統的建立與測試

MATLAB的官方給了相當多的例程,這些有空可以自己去研究,我的第一個目標是實現1t1r系統的搭建,需要滿足

  1. 可以發送指定的數據
  2. 可以接收到發射的數據並統計誤碼率
  3. 可以借助信道估計技術得到正確的信道。
  4. 可以觀察星座圖和頻譜圖

能夠實現這些功能,這個開發板平台就可以替代一些成品售賣的SDR系統了,窮科研的目標就可以達到了(笑)。首先實例化一個頻譜圖模塊和一個星座圖模塊,

clear all;
spectrumScope = dsp.SpectrumAnalyzer( ...
    'SpectrumType',    'Power density', ...
    'SpectralAverages', 10, ...
    'YLimits',         [-130 -40], ...
    'Title',           'Received Baseband LTE Signal Spectrum', ...
    'YLabel',          'Power spectral density');
constellation = comm.ConstellationDiagram('Title','Equalized PDSCH Symbols',...
                                'ShowReferenceConstellation',false);

然后我們為AD9361射頻卡做一個發射機配置

txsim = struct;
txsim.SDRDeviceName = 'AD936x';
radio = sdrdev(txsim.SDRDeviceName); % Create SDR device object

接下來進行詳細的系統設計。根據MATLAB中例程Transmit and Receive LTE MIMO Using a Analog Devices AD9361/AD9364的系統設計方案,完整流程為①輸入圖像並轉化為二進制數據流②生成基帶LTE信號(LTE工具箱),將二進制數據流封裝為不同傳輸塊③為硬件准備合適的傳輸形式④在合適的中心載波上發射。首先對發射機進行合適的配置

txsim.RC = 'R.7';       % Base RMC configuration, 10 MHz bandwidth
txsim.NCellID = 88;     % Cell identity
txsim.NFrame = 700;     % Initial frame number
txsim.TotFrames = 1;    % Number of frames to generate
txsim.DesiredCenterFrequency = 2.45e9; % Center frequency in Hz
txsim.NTxAnts = 1;
txsim.Gain = -10;
sdrTransmitter = sdrtx(txsim.SDRDeviceName);

其中txsim.RC參數給定了一個參考測量信道的參數,R.7則對應(Port0, 50 RB, 64QAM, CellRefP=1, R=3/4)參數。將發射機增益降低可以觀察不同信噪比條件下的效果,因為距離等參數是固定的,可以通過發射功率來靈活改變發射或接收信噪比。最后通過sdrtx函數進行發射機的實例化。
然后讀取數據進行預處理。采用matlab中預置的圖像pepper進行發送,此時

fileTx = 'peppers.png';            % Image file name
fData = imread(fileTx);            % Read image data from file
scale = 0.5;                       % Image scaling factor
origSize = size(fData);            % Original input image size
scaledSize = max(floor(scale.*origSize(1:2)),1); % Calculate new image size
heightIx = min(round(((1:scaledSize(1))-0.5)./scale+0.5),origSize(1));
widthIx = min(round(((1:scaledSize(2))-0.5)./scale+0.5),origSize(2));
fData = fData(heightIx,widthIx,:); % Resize image
imsize = size(fData);              % Store new image size
binData = dec2bin(fData(:),8);     % Convert to 8 bit unsigned binary
trData = reshape((binData-'0').',1,[]).'; % Create binary stream

首先對圖像做了\(0.5\)倍縮放,降低傳輸壓力。這些代碼實際上就是每兩個像素點選擇一個,最終實現25%壓縮比的有損壓縮。RGB圖像中均為uint8數據類型,十進制數據范圍0-255,將十進制轉化為8位二進制后得到了二進制數據流,重排之后形成數據流(此處binData為char型,實際上對於每一個位仍然是一個位存儲,而不采用char保存)。對於不必要的中間變量可以進行clear處理,節約內存消耗,一個參考為8G內存在開啟MATLAB與Chrome后內存即滿。

figure(imFig);
imFig.Visible = 'on';
subplot(211); 
    imshow(fData);
    title('Transmitted Image');
subplot(212);
    title('Received image will appear here...');
    set(gca,'Visible','off'); % Hide axes
    set(findall(gca, 'type', 'text'), 'visible', 'on'); % Unhide title

pause(1); % Pause to plot Tx image

進行圖片顯示,方便后期進行對比。
然后是實際傳輸中很重要的一個環節,即傳輸波形設計。首先進行rmc生成

rmc = lteRMCDL(txsim.RC);
% Calculate the required number of LTE frames based on the size of the
trBlkSize = rmc.PDSCH.TrBlkSizes;
txsim.TotFrames = ceil(numel(trData)/sum(trBlkSize(:)));
% Customize RMC parameters
rmc.NCellID = txsim.NCellID;
rmc.NFrame = txsim.NFrame;
rmc.TotSubframes = txsim.TotFrames*10; % 10 subframes per frame
rmc.CellRefP = txsim.NTxAnts; % Configure number of cell reference ports
rmc.PDSCH.RVSeq = 0;

lteRMCDL用於產生LTE協議相關的參考信道參數,rmc.PDSCH.TrBlkSizes是根據協議分配的每一幀傳輸的數據量,據此可以計算出總共需要的幀數(向上取整)。本次傳輸中計算的總幀數txsim.TotFrames = 5CellID這個參數應該是沒有什么意義,TotSubframes是子幀數,根據協議,每一幀中包含10個子幀;根據前面的單天線假設,此處的CellRefP也為1。另外,我們可以從rmc.DuplexMode的輸出得到,本次實驗是基於FDD

% Fill subframe 5 with dummy data
rmc.OCNGPDSCHEnable = 'On';
rmc.OCNGPDCCHEnable = 'On';
fprintf('\nGenerating LTE transmit waveform:\n')
fprintf('  Packing image data into %d frame(s).\n\n', txsim.TotFrames);
% Pack the image data into a single LTE frame
[eNodeBOutput,txGrid,rmc] = lteRMCDLTool(rmc,trData);% Generate downlink RMC waveform

這里采用lteRMCDLTool生成合適傳輸的波形。該函數運行結束后會得到一個輸出波形和一個時頻資源塊的分配。例如此處計算需要5幀才能實現傳輸,我們繪制txGrid即可得到

這時完整的五個幀,而對於其中的每一幀,我們可以單獨繪制為

這個圖中包含的信息有,采用600子載波傳輸,每一子幀傳輸12個數據符號和兩個特殊符號,總計14個符號,一幀總共有10個子幀。但是很顯然每一個子幀傳輸的數據量並不相同,例如第一個子幀的數據量較少(部分時頻資源塊傳輸了特殊信息),第六個子幀完全沒有傳輸數據。將五幀疊加在一起就可以得到傳輸的資源塊。除了txGrid之外,函數還返回了eNodeBOutput作為傳輸波形,這個傳輸波形已經按照信道特征做了合適的重采樣、滾降濾波,截取片段的功率譜如圖所示

另外需要注意的是,對於多天線而言,生成的波形的第二個維度將是天線數量。經過處理的數據將用於數據發射,后面繼續配置發射機。

sdrTransmitter.BasebandSampleRate = rmc.SamplingRate; % 15.36 Msps for default RMC (R.7) 
                                          % with a bandwidth of 10 MHz  
sdrTransmitter.CenterFrequency = txsim.DesiredCenterFrequency;
sdrTransmitter.ShowAdvancedProperties = true;
sdrTransmitter.Gain = txsim.Gain;
fprintf('Setting channel map to ''1''.\n\n'); 
sdrTransmitter.ChannelMapping = 1;
powerScaleFactor = 0.8;
eNodeBOutput = eNodeBOutput.*(1/max(abs(eNodeBOutput))*powerScaleFactor);
% Cast the transmit signal to int16 --- 
% this is the native format for the SDR hardware. 
eNodeBOutput = int16(eNodeBOutput*2^15);

基帶采樣率是\(15.36\)MHz,發射機射頻中心頻率是前面設置的\(2.45\)GHz,這個具體數值可以根據需要自由配置。發射機增益也是前面配置的\(-10\)dB,然后將單天線映射加入配置。功率因數是限制了最大值的取值范圍,為方便發射。處理后將發射向量映射到16位整數。16位整數的范圍是\(-32768\sim 32767\)
一句話來循環發射信號

transmitRepeat(sdrTransmitter,eNodeBOutput);

這個命令會讓發射機sdrTransmitter按照預定配置循環發送波形eNodeBOutput


接收機的物理設計比發射機更為復雜,在SDR過程中就顯得稍微簡單一些,主要步驟為

  1. 捕獲合適數量的幀
  2. 修正頻率偏移
  3. 同步LTE幀
  4. OFDM解調得到時頻資源塊
  5. 信道估計
  6. 解碼PDSCH 和DL-SCH 以便觀測觀測block內的其他數據信息
  7. 重組接收信息組成接收圖像
rxsim = struct;
rxsim.RadioFrontEndSampleRate = sdrTransmitter.BasebandSampleRate; % Configure for same sample rate
                                                       % as transmitter
rxsim.RadioCenterFrequency = txsim.DesiredCenterFrequency;
rxsim.NRxAnts = txsim.NTxAnts;
rxsim.FramesPerBurst = txsim.TotFrames+1; % Number of LTE frames to capture in each burst.
                                          % Capture 1 more LTE frame than transmitted to  
                                          % allow for timing offset wraparound...
rxsim.numBurstCaptures = 1; % Number of bursts to capture
% Derived parameters
samplesPerFrame = 10e-3*rxsim.RadioFrontEndSampleRate; % LTE frames period is 10 ms

首先定義接收機參數為一個結構,基帶采樣頻率、射頻頻率、天線數與發射機相同,采用突發接收模式,每次捕獲6幀(比發射時多一幀,便於實現定時偏移的回繞),另外由於同步的問題比較復雜,這里並沒有考慮同步的情況,只在重復發送中突發捕獲一次。每一幀的采樣數可以計算,協議要求每一幀10ms,相比基帶采樣率15.36M,則每幀需要153600點。同理,我們發送5幀,因此waveform有768000點。

rxsim.SDRDeviceName = txsim.SDRDeviceName;
sdrReceiver = sdrrx(rxsim.SDRDeviceName);
sdrReceiver.BasebandSampleRate = rxsim.RadioFrontEndSampleRate;
sdrReceiver.CenterFrequency = rxsim.RadioCenterFrequency;
sdrReceiver.SamplesPerFrame = samplesPerFrame;
sdrReceiver.OutputDataType = 'double';
sdrReceiver.EnableBurstMode = true;
sdrReceiver.NumFramesInBurst = rxsim.FramesPerBurst;

% Configure RX channel map
sdrReceiver.ChannelMapping = 1:rxsim.NRxAnts;

% burstCaptures holds sdrReceiver.FramesPerBurst number of consecutive 
% frames worth of baseband LTE samples. Each column holds one LTE frame 
% worth of data.
burstCaptures = zeros(samplesPerFrame,rxsim.NRxAnts,rxsim.FramesPerBurst);

以上繼續進行接收機配置。實例化接收機后配置基帶采樣率、中心頻率、每一幀的采樣數、輸出類型、突發接收及每次接受幀數。然后預分配接收數據的內存。

enb.PDSCH = rmc.PDSCH;
enb.DuplexMode = 'FDD';
enb.CyclicPrefix = 'Normal';
enb.CellRefP = 4; 

本次實驗是假設收發機完全已知對方的發射模式等信息,例如FDD模式,CP模式等。直接在接收機處將這些信息預置。enb在LTE中一般代表基站。

SampleRateLUT = [1.92 3.84 7.68 15.36 30.72]*1e6;
NDLRBLUT = [6 15 25 50 100];
enb.NDLRB = NDLRBLUT(SampleRateLUT==rxsim.RadioFrontEndSampleRate);
if isempty(enb.NDLRB)
    error('Sampling rate not supported. Supported rates are %s.',...
            '1.92 MHz, 3.84 MHz, 7.68 MHz, 15.36 MHz, 30.72 MHz');
end
fprintf('\nSDR hardware sampling rate configured to capture %d LTE RBs.\n',enb.NDLRB);

從查找表中選取合適的數值。實際上前面已經定義了rxsim.RadioFrontEndSampleRate,所以后面操作比較傻瓜。這里附加注釋RB,全稱為Resource Block,一個子幀時長中12個子載波為一組被稱為是一個RB,這里是600子載波的系統,因此說接收50個RB

% Channel estimation configuration structure
cec.PilotAverage = 'UserDefined';  % Type of pilot symbol averaging
cec.FreqWindow = 9;                % Frequency window size in REs
cec.TimeWindow = 9;                % Time window size in REs
cec.InterpType = 'Cubic';          % 2D interpolation type
cec.InterpWindow = 'Centered';     % Interpolation window type
cec.InterpWinSize = 3;             % Interpolation window size

配置合適的信道估計。其中導頻平均是一種導頻計算方法,這種方法中導頻將在時間上進行平均,在這個過程中自然是假設信道不發生改變,在實際通信場景中信道在這種時間量級中的變化大多數情況下是微乎其微的,且估計算法不能保證任何時刻都是實時的。除此之外,由於導頻插入時並非在頻域每一個點都插入,而往往是梳狀插入,這樣估計的信道也不是所有頻率點上的信道,而是部分點上的。由於信道的特征,假如信道在時域上只有4個tap,那么頻域上只需要取4個導頻就可以重建時域信道,因此部分點的估計信道可以推出完整信道(DFT插值)。此處采用的插值為立方差值法,具體參數都已經給出。
接下來的部分為接收機部分代碼,這部分比較長,但由於是一段循環內容,因此未進行分割。

enbDefault = enb;

while rxsim.numBurstCaptures
    % Set default LTE parameters
    enb = enbDefault;
    
    % SDR Capture
    fprintf('\nStarting a new RF capture.\n\n')
    len = 0;
    for frame = 1:rxsim.FramesPerBurst
        while len == 0
            % Store one LTE frame worth of samples
            [data,len,lostSamples] = sdrReceiver();
            burstCaptures(:,:,frame) = data;
        end
        if lostSamples && frame > 1
            warning(message('sdrpluginbase:zynqradioExamples:DroppedSamples'));
        end
        len = 0;
    end    
    rxWaveform = burstCaptures(:);
    % Show power spectral density of captured burst
    spectrumScope.SampleRate = rxsim.RadioFrontEndSampleRate;
    spectrumScope(rxWaveform);
    
    % Perform frequency offset correction for known cell ID
    frequencyOffset = lteFrequencyOffset(enb,rxWaveform);
    rxWaveform = lteFrequencyCorrect(enb,rxWaveform,frequencyOffset);
    fprintf('\nCorrected a frequency offset of %i Hz.\n',frequencyOffset)
    
    % Perform the blind cell search to obtain cell identity and timing offset
    %   Use 'PostFFT' SSS detection method to improve speed
    cellSearch.SSSDetection = 'PostFFT'; cellSearch.MaxCellCount = 1;
    [NCellID,frameOffset] = lteCellSearch(enb,rxWaveform,cellSearch);
    fprintf('Detected a cell identity of %i.\n', NCellID);
    enb.NCellID = NCellID; % From lteCellSearch
    
    % Sync the captured samples to the start of an LTE frame, and trim off
    % any samples that are part of an incomplete frame.
    rxWaveform = rxWaveform(frameOffset+1:end,:);
    tailSamples = mod(length(rxWaveform),samplesPerFrame);
    rxWaveform = rxWaveform(1:end-tailSamples,:);
    enb.NSubframe = 0;
    fprintf('Corrected a timing offset of %i samples.\n',frameOffset)
    
    % OFDM demodulation
    rxGrid = lteOFDMDemodulate(enb,rxWaveform);
    
    % Perform channel estimation for 4 CellRefP as currently we do not
    % know the CellRefP for the eNodeB.
    [hest,nest] = lteDLChannelEstimate(enb,cec,rxGrid);
    
    sfDims = lteResourceGridSize(enb);
    Lsf = sfDims(2); % OFDM symbols per subframe
    LFrame = 10*Lsf; % OFDM symbols per frame
    numFullFrames = length(rxWaveform)/samplesPerFrame;
    
    rxDataFrame = zeros(sum(enb.PDSCH.TrBlkSizes(:)),numFullFrames);
    recFrames = zeros(numFullFrames,1);
    rxSymbols = []; txSymbols = [];
    
    % For each frame decode the MIB, PDSCH and DL-SCH
    for frame = 0:(numFullFrames-1)
        fprintf('\nPerforming DL-SCH Decode for frame %i of %i in burst:\n', ...
            frame+1,numFullFrames)
        
        % Extract subframe #0 from each frame of the received resource grid
        % and channel estimate.
        enb.NSubframe = 0;
        rxsf = rxGrid(:,frame*LFrame+(1:Lsf),:);
        hestsf = hest(:,frame*LFrame+(1:Lsf),:,:);
               
        % PBCH demodulation. Extract resource elements (REs)
        % corresponding to the PBCH from the received grid and channel
        % estimate grid for demodulation.
        enb.CellRefP = 4;
        pbchIndices = ltePBCHIndices(enb); 
        [pbchRx,pbchHest] = lteExtractResources(pbchIndices,rxsf,hestsf);
        [~,~,nfmod4,mib,CellRefP] = ltePBCHDecode(enb,pbchRx,pbchHest,nest);
        
        % If PBCH decoding successful CellRefP~=0 then update info
        if ~CellRefP
            fprintf('  No PBCH detected for frame.\n');
            continue;
        end
        enb.CellRefP = CellRefP; % From ltePBCHDecode
        
        % Decode the MIB to get current frame number
        enb = lteMIB(mib,enb);

        % Incorporate the nfmod4 value output from the function
        % ltePBCHDecode, as the NFrame value established from the MIB
        % is the system frame number modulo 4.
        enb.NFrame = enb.NFrame+nfmod4;
        fprintf('  Successful MIB Decode.\n')
        fprintf('  Frame number: %d.\n',enb.NFrame);
        
        % The eNodeB transmission bandwidth may be greater than the
        % captured bandwidth, so limit the bandwidth for processing
        enb.NDLRB = min(enbDefault.NDLRB,enb.NDLRB);
        
        % Store received frame number
        recFrames(frame+1) = enb.NFrame;
               
        % Process subframes within frame (ignoring subframe 5)
        for sf = 0:9
            if sf~=5 % Ignore subframe 5
                % Extract subframe
                enb.NSubframe = sf;
                rxsf = rxGrid(:,frame*LFrame+sf*Lsf+(1:Lsf),:);

                % Perform channel estimation with the correct number of CellRefP
                [hestsf,nestsf] = lteDLChannelEstimate(enb,cec,rxsf);

                % PCFICH demodulation. Extract REs corresponding to the PCFICH
                % from the received grid and channel estimate for demodulation.
                pcfichIndices = ltePCFICHIndices(enb);
                [pcfichRx,pcfichHest] = lteExtractResources(pcfichIndices,rxsf,hestsf);
                [cfiBits,recsym] = ltePCFICHDecode(enb,pcfichRx,pcfichHest,nestsf);

                % CFI decoding
                enb.CFI = lteCFIDecode(cfiBits);
                
                % Get PDSCH indices
                [pdschIndices,pdschIndicesInfo] = ltePDSCHIndices(enb, enb.PDSCH, enb.PDSCH.PRBSet); 
                [pdschRx, pdschHest] = lteExtractResources(pdschIndices, rxsf, hestsf);

                % Perform deprecoding, layer demapping, demodulation and
                % descrambling on the received data using the estimate of
                % the channel
                [rxEncodedBits, rxEncodedSymb] = ltePDSCHDecode(enb,enb.PDSCH,pdschRx,...
                                               pdschHest,nestsf);

                % Append decoded symbol to stream
                rxSymbols = [rxSymbols; rxEncodedSymb{:}]; %#ok<AGROW>

                % Transport block sizes
                outLen = enb.PDSCH.TrBlkSizes(enb.NSubframe+1);  

                % Decode DownLink Shared Channel (DL-SCH)
                [decbits{sf+1}, blkcrc(sf+1)] = lteDLSCHDecode(enb,enb.PDSCH,...
                                                outLen, rxEncodedBits);  %#ok<SAGROW>

                % Recode transmitted PDSCH symbols for EVM calculation                            
                %   Encode transmitted DLSCH 
                txRecode = lteDLSCH(enb,enb.PDSCH,pdschIndicesInfo.G,decbits{sf+1});
                %   Modulate transmitted PDSCH
                txRemod = ltePDSCH(enb, enb.PDSCH, txRecode);
                %   Decode transmitted PDSCH
                [~,refSymbols] = ltePDSCHDecode(enb, enb.PDSCH, txRemod);
                %   Add encoded symbol to stream
                txSymbols = [txSymbols; refSymbols{:}]; %#ok<AGROW>

                release(constellation); % Release previous constellation plot
                constellation(rxEncodedSymb{:}); % Plot current constellation
                pause(0); % Allow constellation to repaint
            end
        end
        
        % Reassemble decoded bits
        fprintf('  Retrieving decoded transport block data.\n');
        rxdata = [];
        for i = 1:length(decbits)
            if i~=6 % Ignore subframe 5
                rxdata = [rxdata; decbits{i}{:}]; %#ok<AGROW>
            end
        end
        
        % Store data from receive frame
        rxDataFrame(:,frame+1) = rxdata;

        % Plot channel estimate between CellRefP 0 and the receive antennae
        focalFrameIdx = frame*LFrame+(1:LFrame);
        figure(hhest);
        hhest.Visible = 'On';
        surf(abs(hest(:,focalFrameIdx,1,1)));
        shading flat;
        xlabel('OFDM symbol index'); 
        ylabel('Subcarrier index');
        zlabel('Magnitude');   
        title('Estimate of Channel Magnitude Frequency Repsonse');                
    end
    rxsim.numBurstCaptures = rxsim.numBurstCaptures-1;
end

最外層的循環為接收次數,每接收一次就會自減1,本次突發接收僅一次,因此一次接收之后就會跳出。前面的配置中計划進行 總幀數+1=6 次的接收,第二次循環就以6位循環次數指標,開始一次接收。接收時接收機會返回接收數據、接收長度以及丟失幀數,如果出現丟失幀數則會警告。循環接收6幀內容后,我們接收到的波形rxWaveform就是前面每一幀的組合。將此信號輸入頻譜分析模塊,我們就可以得到一個頻譜圖(這里我就不知道它是采用什么算法得到的了)。
載波頻偏很小,在此系統中是否修正都不會對系統產生嚴重的影響,但是這個問題在實際系統中是不能忽略的。由於前面設置幀數是從700開始的,因此后面捕獲幀數的時候都會以700位第一幀的序號,可以自己改。在LTE中我們采用PSS和SSS進行同步檢測,此處我們通過SSS檢測得到采樣點偏移,本次收發的偏移為125188采樣點。因此我們將去除接收波形中的這部分,除此之外,我們還要在末尾去除多余部分。由於我們接收了6幀,這樣就可以去除影響因素獲取其中的5幀。
接收波形通過OFDM解調得到了rxGrid

接收波形的邊緣子載波似乎經歷了比較嚴重的fading,原因尚不知曉。利用接收的Grid進行信道估計,我們得到了信道hest

lteResourceGridSize可以根據基站的工作模式提取時頻資源塊的形狀,我們這里輸出為[600 14 4],我們取第二個維度14,這個維度代表的是每一個子幀內有14個符號。由於采樣速率為15.36M,容易通過裁剪后的rxWaveform的長度得到總共接收5幀,而每一幀內的數據量為272944,因此可以配置接收幀矩陣為\(272944\times 5\)維度。

接下來進行每一幀的解碼,循環解碼MIB, PDSCH 和 DL-SCH。每一幀的第一個子幀中包含較多的信息,因此從第一子幀開始解碼,前14個符號解出后,配合估計出的這14個符號的信道。后面通過LTE中我們指定的傳輸方案,可以直接提取出中間指定區域\(240\times 4\)的物理廣播信道塊,提取后就可以從這個塊中解碼我們需要的信息。
由於LTE進行傳輸時必須指定小區編號等信息,因此雖然這些信息在仿真中沒有實際意義,但是解碼的部分要到位。
PBCH占用的時頻資源固定,在每個幀上的子幀0的第2個slot的0,1,2,3個符號上傳輸,占用1.25M頻率資源,72個資源塊(RE)。PBCH傳輸的就是MIB(只傳輸MIB),MIB在40ms內重復發送4次,接收機在這四次中成功解出其中的一個就可以實現MIB的解碼,如果信道條件不佳,就會在10ms后與下一次的MIB進行軟合並,再次嘗試數據解調。
然后進行數據的解調,在10個子幀中,除了第六個子幀外(空幀),均進行適當的信道估計和資源塊的解碼,每一個子幀內信道可能發生改變,因此每一個子幀都進行信道的估計。估計后首先在每一個子幀中獲取控制信息。前面我們看見,雖然一個子幀內傳輸14個slot,但是容易知道其中前面的若干slot並沒有傳輸數據,而是傳輸一些控制信號與預留區域,這部分區域實際上就是物理格式控制信道。PCFICH承載的是CFI(Control Format Indicatior),用來指明PDCCH在子幀內所占用的符號個數。我們接下來就將CFI獲取。有了CFI信息后,我們就可以實現最終的數據解碼。

EVM是LTE中常用的性能指標,用來衡量傳輸中信號與理想信號在同一時刻的向量差,此處的M代表幅度,因此為誤差矢量的幅度。為了衡量這個誤差,需要將得到的正確結果重編碼調制后與接收到的進行對比,這個數值可以一定程度上反應信噪比,誤差越大信噪比也越低。LTE一般要求這個誤差在17.5%。該性能指標可以通過工具箱直接繪制。

每一個子幀解碼最后都可以繪制星座圖。將所有比特進行合並之后,我們得到了總接收數據,將其重新排列為圖像就可以得到接收的圖像結果。

采用空時編碼實現 2x2 MIMO系統

前面一部分的主要問題是代碼冗長,需要對協議有比較深入的了解。我們的主要工作還是集中在所謂學術,對這些協議上的內容在研究中可以等效地忽略。在后面的實現中,我們簡化系統為普通的OFDM系統,不再考慮LTE中的復雜協議要求,而是考慮較為理想的傳輸模型。首先我們進行參數配置與內存的預分配

clear
%%
NT      = 2;
N_sym   = 12;       %  6 symbols -> 12 symbols (STBC)
N_frame = 10;       %  a single frame
fc      = 2.45e9;
fs      = 15.36e6;
N_subcarrier    =   1024;
synSeqLength    =   1024;
Idx_used        =   N_subcarrier/2-300+1:N_subcarrier/2+300;
pilot_idx       =   Idx_used(1):16:Idx_used(end);
data_idx        =   setdiff(Idx_used,pilot_idx);
N_data          =   length(data_idx);
CPlength        =   [178 170 170 170 170 170 170 170 170 170 170 170];% frame 12
samplesPerFrame =   N_sym*N_subcarrier+synSeqLength+sum(CPlength);
frameTime       =   samplesPerFrame/fs;
bit_per_sym =   N_data; %bpsk
total_bit_cnt   =   bit_per_sym * N_sym*N_frame;
user_bit        =   rand (  total_bit_cnt ,1 ) > 0.5 ;
bit_to_mod      =   reshape(user_bit,1,total_bit_cnt);
sym             =   2*bit_to_mod-1;                               % BPSK mod
txGrid          =   zeros(N_subcarrier,(N_sym+1)*N_frame);
avaliableSlot   =   setdiff(1:N_frame*(1+N_sym),1:N_sym+1:N_frame*(1+N_sym));

然后進行bpsk數據的填充,以及波形的准備。

txGrid(data_idx,avaliableSlot)  =   reshape(sym,N_data,N_sym*N_frame);
txGrid(pilot_idx,avaliableSlot)  =   ones(numel(pilot_idx),numel(avaliableSlot));
txDataGrid      =   txGrid(:,avaliableSlot);
txWaveform=zeros(samplesPerFrame*N_frame,NT);
preAmble=zadoffChuSeq(1,1023);
pre_Amble=[preAmble;preAmble(1)];
txWaveform(1:1024,1)=[preAmble;preAmble(1)];
txWaveform(1:1024,2)=[preAmble;preAmble(1)];

上述的preamble的主要作用是進行數據幀的同步。然后我們在OFDM之前對數據進行空時編碼,這里的簡單編碼就是Alamouti code。

%% STBC
% in STBC only half of the symbols are coded. A bug of the program.
STBCGrid=zeros(N_subcarrier,(N_sym+1)*N_frame,NT);
for f=1:N_frame
    % ofdm_frame = sqrt(N_subcarrier*N_subcarrier/numel(Idx_used)) * ifft( fftshift( txGrid(:,(f-1)*(N_sym+1)+2:f*(N_sym+1),1), 1 ) );%IFFT
    ofdm_frame = txGrid(:,(f-1)*(N_sym+1)+2:f*(N_sym+1),1);
    for s=1:N_sym/2
        input = ofdm_frame( :,s*2-1:s*2 );
        X1=input(:,1);
        X2=input(:,2);
        coded_tmp=[X1 X2;-conj(X2) conj(X1)];   % 2t Alamouti code
        for ant = 1:2
            tmp = reshape(coded_tmp(:,ant), N_subcarrier, 2);
            %st_coded(:, s*2-1:s*2 ,ant) = tmp;
            STBCGrid(:,(f-1)*(N_sym+1)+2+s*2-2:(f-1)*(N_sym+1)+2+s*2-1,ant)=tmp;
        end
    end
end

然后產生發射機波形,順便配置一個頻譜分析儀,一個星座圖分析。

endPointer=1025;
for ant = 1:2
    endPointer=1025;
    for f=1:N_frame
        ofdm_frame = sqrt(N_subcarrier*N_subcarrier/numel(Idx_used)) * ifft( fftshift( STBCGrid(:,(f-1)*(N_sym+1)+2:f*(N_sym+1),ant), 1 ) );%IFFT
        for s=1:N_sym
            cpOFDM_frame=[ofdm_frame(end-CPlength(s)+1:end,s);ofdm_frame(:,s)];
            txWaveform(endPointer:endPointer+N_subcarrier+CPlength(s)-1,ant)=cpOFDM_frame;
            endPointer=endPointer+N_subcarrier+CPlength(s);
        end
        endPointer=endPointer+synSeqLength;
    end
end
%%
% Setup Spectrum viewer
spectrumScope = dsp.SpectrumAnalyzer( ...
    'SpectrumType',    'Power density', ...
    'SpectralAverages', 10, ...
    'YLimits',         [-130 -30], ...
    'Title',           'Received Baseband LTE Signal Spectrum', ...
    'YLabel',          'Power spectral density');

% Setup the constellation diagram viewer for equalized PDSCH symbols
constellation = comm.ConstellationDiagram('Title','Equalized PDSCH Symbols',...
                                'ShowReferenceConstellation',false);
spectrumScope.SampleRate = 15.36e6;

接下來進行一段經典的收發機配置

%% Tx
txsim = struct; % Create empty structure for transmitter
txsim.SDRDeviceName = 'AD936x'; % Set SDR Device
radio = sdrdev(txsim.SDRDeviceName); % Create SDR device object
txsim.DesiredCenterFrequency = fc; % Center frequency in Hz
txsim.NTxAnts = NT;
txsim.Gain = -3;
sdrTransmitter = sdrtx(txsim.SDRDeviceName);
sdrTransmitter.BasebandSampleRate = fs; % 15.36 Msps for default RMC (R.7) 
                                          % with a bandwidth of 10 MHz  
sdrTransmitter.CenterFrequency = txsim.DesiredCenterFrequency;
sdrTransmitter.ShowAdvancedProperties = true;
sdrTransmitter.Gain = txsim.Gain;
sdrTransmitter.ChannelMapping = [1,2];
powerScaleFactor = 0.8;
for i =1:NT
    txWaveform(:,i) = txWaveform(:,i).*(1/max(abs(txWaveform(:,i)))*powerScaleFactor);
end
spectrumScope.SampleRate = 15.36e6;
% spectrumScope(txWaveform);
txWaveform2=txWaveform;
txWaveform = int16(txWaveform*2^15);
transmitRepeat(sdrTransmitter,txWaveform);
pause(0.5)
%%
rxsim = struct;
rxsim.RadioFrontEndSampleRate = fs; % Configure for same sample rate
                                                       % as transmitter
rxsim.RadioCenterFrequency = fc;
rxsim.NRxAnts = 2;
rxsim.FramesPerBurst = 2; % Number of LTE frames to capture in each burst.
                                          % Capture 1 more LTE frame than transmitted to  
                                          % allow for timing offset wraparound...
rxsim.numBurstCaptures = 1; % Number of bursts to capture
samplesPerFrame = 10e-3*rxsim.RadioFrontEndSampleRate;
%%
rxsim.SDRDeviceName = txsim.SDRDeviceName;
sdrReceiver = sdrrx(rxsim.SDRDeviceName);
sdrReceiver.BasebandSampleRate = rxsim.RadioFrontEndSampleRate;
sdrReceiver.CenterFrequency = rxsim.RadioCenterFrequency;
sdrReceiver.SamplesPerFrame = samplesPerFrame;
sdrReceiver.OutputDataType = 'double';
sdrReceiver.EnableBurstMode = true;
sdrReceiver.NumFramesInBurst = rxsim.FramesPerBurst;
% Configure RX channel map
sdrReceiver.ChannelMapping = 1:rxsim.NRxAnts;
burstCaptures = zeros(samplesPerFrame,rxsim.NRxAnts,rxsim.FramesPerBurst);

接收機經過一次接收就會獲取兩個幀長度的采樣,然后我們通過同步確定幀頭部出現的位置,並以這個頭部為起點切除周圍不完整的一幀。

rxWaveform_frame=zeros(samplesPerFrame,2);
%  release(spectrumScope)
while rxsim.numBurstCaptures
    % SDR Capture
    fprintf('\nStarting a new RF capture.\n\n')
    len = 0;
    for frame = 1:rxsim.FramesPerBurst
        while len == 0
            % Store one LTE frame worth of samples
            [data,len,lostSamples] = sdrReceiver();
            burstCaptures(:,:,frame) = data;
        end
        if lostSamples && frame > 1
            warning(message('sdrpluginbase:zynqradioExamples:DroppedSamples'));
        end
        len = 0;
    end 
    
    rxWaveform = reshape(permute(burstCaptures,[1 3 2]), ...
        rxsim.FramesPerBurst*samplesPerFrame,rxsim.NRxAnts);
    spectrumScope.ShowLegend = true; % Turn on legend for spectrum analyzer
    spectrumScope.ChannelNames = cellfun(@(x) ['SDR Channel ' num2str(x)], num2cell(1:4), 'UniformOutput', false);
    
    % rxWaveform = burstCaptures(:);
    spectrumScope(rxWaveform);
    
    corr1=abs(xcorr(rxWaveform(:,1),pre_Amble));
    [val,corr1_index]=max(corr1(1:round(0.75*numel(corr1))))
    % corr1_index=find(corr1>50);
    offset_1=corr1_index-round(numel(corr1)/2)-2
    
    corr2=abs(xcorr(rxWaveform(:,2),pre_Amble));
    [val,corr2_index]=max(corr2(1:round(0.75*numel(corr2))))
    % corr1_index=find(corr1>50);
    offset_2=corr2_index-round(numel(corr2)/2)-2
    
    rxWaveform_frame(:,1)=rxWaveform(1+offset_1:samplesPerFrame+offset_1,1);
    rxWaveform_frame(:,2)=rxWaveform(1+offset_2:samplesPerFrame+offset_2,1);
    rxsim.numBurstCaptures = rxsim.numBurstCaptures-1;
end
release(sdrTransmitter);
release(sdrReceiver);
release(spectrumScope);

完成同步之后,我們將接收波形重新整形為Grid形式(即“時頻資源塊”的形式),然后就可以逐幀進行OFDM解調與STBC解碼的過程。值得注意的是,由於采用雙天線接收,因此得到的接收矩陣有兩個維度,分別是兩個天線的波形采樣,這兩個天線的采樣可能存在些許不同。該射頻板天線距離極近,此處的處理方案是直接將兩個天線的采樣疊加。經過同步我們容易發現兩個天線的同步偏移是相同的,直接相加有利於等效信噪比增加,這也被稱為是陣列增益。
合並方式很多,考慮到這兩根天線的情況相似,則此處EGC和MRC為相似的處理,即直接1:1合並。

%% MRC combining
rxWaveform_fr=(rxWaveform_frame(:,1)+rxWaveform_frame(:,2))/2;
%% recv reshape
endPointer=1025;
rxGrid=zeros(N_subcarrier,N_sym*N_frame);
for f=1:N_frame
    for s=1:N_sym
        ofdm_frame = rxWaveform_fr(endPointer+CPlength(s):endPointer+N_subcarrier+CPlength(s)-1);
        % spectrumScope(ofdm_frame)
        % pause(0.05)
        % ofdm_frame_f=fftshift(fft(ofdm_frame));
        rxGrid(:,s+(f-1)*N_sym)=fftshift(fft(ofdm_frame))/(sqrt(N_subcarrier*N_subcarrier/numel(Idx_used)));
        endPointer=endPointer+N_subcarrier+CPlength(s);
    end
    endPointer=endPointer+synSeqLength;
end
%% channel estimation
rxPilotSeq=rxGrid(pilot_idx,:);
channel_f=rxPilotSeq./ones(numel(pilot_idx),numel(avaliableSlot));
channel_f_acc=zeros(numel(pilot_idx),1);
channel_t_acc=zeros(numel(pilot_idx),1);
figure(37);
for i=1:numel(avaliableSlot)
    if mod(i,2)==0
        continue;
    else
        % continue;
    end
    subplot(411)
    plot(abs(channel_f(:,i)));axis([1 numel(channel_f(:,i)) 0 0.5]);title('Instant freq-D channel')
    subplot(412)
    stem(abs(ifft(channel_f(:,i))));axis([1 numel(channel_f(:,i)) 0 0.5]);title('Instant time-D channel')
    % ==================================
    channel_f_acc=channel_f_acc+channel_f(:,i);
    channel_t_acc=channel_t_acc+ifft(channel_f(:,i));
    % ==================================
    subplot(413)
    plot(abs(channel_f_acc/i*2));axis([1 numel(channel_f(:,i)) 0 0.5]);title('Accumulate freq-D channel')
    subplot(414)
    stem(abs(channel_t_acc/i*2));axis([1 numel(channel_f(:,i)) 0 0.5]);title('Accumulate time-D channel')
    pause(0.001)
end
channel_f_acc=channel_f_acc/numel(avaliableSlot)*2;
channel_t_acc=channel_t_acc/numel(avaliableSlot)*2;
%% De STBC
st_decoded = zeros(N_subcarrier, N_frame*N_sym);
Xe=zeros(600,1);
Xo=zeros(600,1);
aveCh=channel_f_acc;
channel_f1=fft(ifft(aveCh),numel(Idx_used));
channel_f2=fft(ifft(aveCh),numel(Idx_used));

for f=1:N_frame
    for n = 1:N_sym/2
%         channel_f1=fft(ifft(channel_f(:,(f-1)*N_sym+n*2)),numel(Idx_used));
%         channel_f2=channel_f1;
        R = [];
        R = [R  rxGrid(Idx_used,(n-1)*2+1+(f-1)*N_sym:n*2+(f-1)*N_sym) ];
        R1=R(:,1);
        R2=R(:,2);
        for i=1:numel(Idx_used)
            Xe(i)= conj(channel_f1(i))*R1(i)+channel_f2(i)*conj(R2(i));
            Xo(i)= conj(channel_f2(i))*R1(i)-channel_f1(i)*conj(R2(i));% if SC-FDMA , need MMSE equalization here
        end
        output=[Xe Xo];
        st_decoded(Idx_used,(n-1)*2+1+(f-1)*N_sym:n*2+(f-1)*N_sym) = output;
        tmp=reshape(output,[numel(output),1]);
        constellation(output)
        pause(0.05)
        
    end
end
release(constellation)
%% Detection
for f=1:N_frame
    for n = 1:N_sym
        for ii=Idx_used
            if st_decoded(ii,(f-1)*N_sym+n)>=0
                st_decoded(ii,(f-1)*N_sym+n)=1;
            else
                st_decoded(ii,(f-1)*N_sym+n)=-1;
            end
        end
    end
end
%% BER
ber=biterr(txDataGrid(data_idx,:)+1,st_decoded(data_idx,:)+1)/numel(txDataGrid(data_idx,:))

經過OFDM解調,STBC解碼之后,原數據得以解出,我們因此可以計算誤碼率、觀測星座圖等。

關於性能對比的分析

OFDM系統是依靠不同子載波傳輸來提高系統的傳輸帶寬,從發射/接收頻譜我們都容易看出,傳輸帶寬可以輕易拉到10MHz水平,並且可以有效實現信道估計。這個應該可以說是頻率上的分集(Diversity),提高了系統的有效性,我們同樣可以在時間上進行分集,從而提高系統的可靠性。時間上的分集借助天線實現,這種編碼方式也被稱為是空時編碼。在期望性能上,我們認為應該是\(2\times 2\) OFDM + STBC + MRC \(\geq\) \(2\times 1\) OFDM + STBC \(\geq\) \(1\times 1\) OFDM,首先我們在AWGN信道條件下驗證性能。

AWGN信道仿真分析

理論到實踐的距離很大,我們首先來測試理論上的誤碼性能。在此次假設中我們認為接收機完美同步,信噪比從-10dB到10dB每隔2.5dB取值一次。在AWGN信道下,OFDM傳輸50幀,最終計算誤碼率曲線為

根據曲線圖我們可以看出,在AWGN信道下進行STBC編碼對最終性能不會產生任何影響,此時的收發機分集並不會引發增益。這是由於AWGN信道的抽頭系數為1,此時進行誤碼率上下界推導時,計算結果為BER隨SNR指數下降,無論外界的分集系數如何,最終結果不會產生影響。但是當我們采用瑞利信道建模時,根據瑞利信道的統計特性我們可以推算瑞利信道下的BER隨着分集階數增加,BER曲線的斜率是發生明顯變化的。因此在AWGN信道的測試中,我們無法觀測到分集增益。實際仿真我們證實了這個結論,接下來我們可以測試瑞利信道下的通信過程。

由於后面的仿真結果受到了天線互耦的影響,因此經過調試后決定延期進行,結果將會在調試結束后發布
2020-7-15 14:07:13


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM