我是靠谱客的博主 怡然缘分,这篇文章主要介绍基于FPGA的映射调制实现项目简述数学建模MATLAB仿真FPGA代码FPGA与MATLAB的交叉验证小结参考文献总结,现在分享给大家,希望可以做个参考。

基于FPGA的映射调制实现

  • 项目简述
  • 数学建模
  • MATLAB仿真
  • FPGA代码
    • FPGA映射的代码
    • FPGA的映射测试代码
  • FPGA与MATLAB的交叉验证
  • 小结
  • 参考文献
  • 总结

项目简述

在通信过程中,经常能碰见调制解调,这里将讲解一种映射调制的方法,并且给出相应的代码供大家学习。一般调制位于无线通信中比较靠后的未知,在交织之后。这里的映射调制并没有介入载波,只是进行了相应的星座图映射,至于最后载波的加入,将在后面的博客中学习。

数学建模

首先我们常见的QPSK与16-QAM的星座图如下:
在这里插入图片描述
由星座图可以得到编码之后的如下信息:
QPSK编码对应坐标轴大小
在这里插入图片描述
在这里插入图片描述
16-QAM编码对应坐标轴大小
在这里插入图片描述
在这里插入图片描述

星座图映射的对象为位交织输出 u = ( u 0 , u 1 , . . . , u N l d p c − 2 , u N l d p c − 1 ) u=(u_0,u_1,...,u_{N_{ldpc}-2},u_{N_{ldpc}-1}) u=(u0,u1,...,uNldpc2,uNldpc1) , N l d p c = 16200 N_{ldpc}=16200 Nldpc=16200主要是因为LDPC编码之后每包的长度就是16200,星座图映射分为两步:
(1)解复用,将 u u u 分解为 N s u b s t r e a m s N_{substreams} Nsubstreams 个子流
(2)将 N s u b s t r e a m s N_{substreams} Nsubstreams 个子流根据调制方式映射到对应星座图。

那么对于不同的调制方式, $N_{substreams}的值如下:

ModulationNumber of sub-streams N s u b s t r e a m s N_{substreams} Nsubstreams
QPSK2
16-QAM8

首先我们要完成解复用,其实说白了解复用就是一个串并变换。

在这里插入图片描述
解复用模块将输入 v d i v_{di} vdi 映射到输出 b i , j b_{i,j} bi,j,其中 i i i为第 i i i个子流, j = d i   d i v   N s u b s t r e a m s j=di div N_{substreams} j=di div Nsubstreams。其中对于QPSK调制,i与 d i   m o d   N s u b s t r e a m s di mod N_{substreams} di mod Nsubstreams的值一样,对于16-QAM则进行了相应的变换,如下表:

Modulation formatQPSK
d i   m o d   N s u b s t r e a m s di mod N_{substreams} di mod Nsubstreams01
e01
Modulation format16-QAM
d i   m o d   N s u b s t r e a m s di mod N_{substreams} di mod Nsubstreams01234567
e71425360

进行完解复用之后就应该进行相应的映射操作,将会将上面产生的 N s u b s t r e a m s N_{substreams} Nsubstreams个并行通道映射到相应的 σ sigma σ个码元,映射的关系如下表:

Modulation N s u b s t r e a m s N_{substreams} Nsubstreams σ sigma σ
QPSK22
16-QAM84

对于 QPSK 调制, Nsubstreams 个子流每次组成一个调制符号,而对于 16-QAM, N s u b s t r e a m s N_{substreams} Nsubstreams 个子流每次组成两个调制符号,前半个子流组成一个调制符号,后半个子流组成一个调制符号。具体公式如下:
定义调制符号: y d o = [ y 0 , d o , . . . , y σ − 1 , d o ] y_{do}=[y_{0,do},...,y_{sigma-1,do}] ydo=[y0,do,...,yσ1,do]
对于QPSK调制: [ y 0 , d o , . . . , y σ − 1 , d o ] = [ b 0 , d o , . . . , b N s u b s t r e a m s − 1 , d o ] [y_{0,do},...,y_{sigma-1,do}]=[b_{0,do},...,b_{N_{substreams}-1,do}] [y0,do,...,yσ1,do]=[b0,do,...,bNsubstreams1,do]
对于16-QAM调制: [ y 0 , 2 d o , . . . , y σ − 1 , 2 d o ] = [ b 0 , d o , . . . , b N s u b s t r e a m s / 2 − 1 , d o ] [y_{0,2do},...,y_{sigma-1,2do}]=[b_{0,do},...,b_{N_{substreams}/2-1,do}] [y0,2do,...,yσ1,2do]=[b0,do,...,bNsubstreams/21,do]
[ y 0 , 2 d o + 1 , . . . , y σ − 1 , 2 d o + 1 ] = [ b N s u b s t r e a m s / 2 , d o , . . . , b N s u b s t r e a m s − 1 , d o ] [y_{0,2do+1},...,y_{sigma-1,2do+1}]=[b_{N_{substreams}/2,do},...,b_{N_{substreams}-1,do}] [y0,2do+1,...,yσ1,2do+1]=[bNsubstreams/2,do,...,bNsubstreams1,do]
然后就完成了相应的映射操作。也就将原来的码映射到了星座表中的坐标上。

MATLAB仿真

上面我们已经讲解了映射调制的星座图对应关系,但是相信大家还都不是特别明白,接下来给出相应的MATLAB代码供大家学习,学习的时候需要结合数学模型与MATLAB仿真相互学习。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
sim_options = struct(... 'CONSTELLATION', '16-QAM' ... ); fid1 = fopen('mapper_in.txt','r'); DataIn = fscanf(fid1,'%d'); %------------------------------------------------------------------------------ %------------------------------------------------------------------------------ switch sim_options.CONSTELLATION case 'QPSK' V = 2; % Bits per cell case '16-QAM' V = 4; otherwise, error('sim_options UNKNOWN CONSTELLATION'); end %------------------------------------------------------------------------------ % Parameters Definition %------------------------------------------------------------------------------ CONSTEL = sim_options.CONSTELLATION; %------------------------------------------------------------------------------ % Procedure %------------------------------------------------------------------------------ %bits to cells data = DataIn'; streams = V * 2; switch CONSTEL case 'QPSK' mapping = [0 1 2 3] + 1; case '16-QAM' mapping = [7 1 4 2 5 3 6 0] + 1; end numBits = length(data); numCells = floor(numBits/streams); numBits = numCells*streams; data = data(1:numBits); %make streams cells = reshape(data', streams, size(data,2)/streams)'; %swap this to agree with spec, above line maps the wrong way cells(:, mapping) = cells; cells = reshape(cells', [] , 1); cells = reshape(cells, V , [])'; if ~isempty(cells) DataOut = bi2de(cells,'left-msb'); else DataOut = []; end save DataOut.mat DataOut

上面的代码主要是源于电子发烧友学院,只是博主为了方便理解,进行了一小部分的更改。需要的同学可以关注上面的课程信息。阅读完相应的MATLAB代码,再观察前面的数学模型,会发现映射调制非常简单。

设置调制方式:
在这里插入图片描述
找到输入数据:
在这里插入图片描述
设置映射方式:
在这里插入图片描述
解复用:
在这里插入图片描述
映射到星座图:
在这里插入图片描述

FPGA代码

上面我们已经详细介绍了映射调制的原理与MATLAB代码,这里将给出相应的MATLAB代码。代码非常简单,这里也就不对说了。

FPGA映射的代码

tx_Mapper模块:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
`timescale 1ns / 1ps // ********************************************************************************* // Project Name : OSXXXX // Author : zhangningning // Email : nnzhang1996@foxmail.com // Website : // Module Name : tx_Mapper.v // Create Time : 2020-05-31 11:23:32 // Editor : sublime text3, tab size (4) // CopyRight(c) : All Rights Reserved // // ********************************************************************************* // Modification History: // Date By Version Change Description // ----------------------------------------------------------------------- // XXXX zhangningning 1.0 Original // // ********************************************************************************* module tx_Mapper( input clk , input rst_n , input s_config_tvalid , input s_config_tdata , input s_data_tvalid , input s_data_tdata , output reg s_data_tready , input s_data_tlast , output reg m_data_tvalid , output reg [ 3:0] m_data_tdata , input m_data_tready , output reg m_data_tlast ); //======================================================================================== //**************Define Parameter and Internal Signals********************************** //========================================================================================/ reg mode_type ; reg [12:0] Ncell ; reg [ 1:0] QPSK_cnt ; reg [ 3:0] QPSK_data ; reg map_ena ; reg [ 7:0] QPSK_mod_data ; reg QPSK_mod_valid ; reg [ 2:0] QAM_cnt ; reg [ 7:0] QAM_data ; reg map_enb ; reg [ 7:0] QAM_mod_data ; reg QAM_mod_valid ; reg map_wea ; reg [11:0] map_addra ; reg [ 7:0] map_dina ; reg [12:0] map_addrb ; wire [ 3:0] map_doutb ; reg data_ordy ; reg [12:0] m_cnt ; reg s_data_tvalid_reg ; wire start_data_invld ; //======================================================================================== //************** Main Code ********************************** //========================================================================================/ assign start_data_invld = ~s_data_tvalid_reg && s_data_tvalid; //==================================================================================== // configure parameter //==================================================================================== always@(posedge clk) if(rst_n == 1'b0) mode_type <= 0; else if(s_config_tvalid == 1'b1) mode_type <= s_config_tdata; ///mode_type = 0,QPSK ; mode_type = 1 ,16QAM; always@(*) case(mode_type) 1'b0 : Ncell = 13'd8100; 1'b1 : Ncell = 13'd4050; default : Ncell = 13'd0; endcase always@(posedge clk) if(mode_type == 1'b0 && s_data_tvalid == 1'b1) QPSK_cnt <= QPSK_cnt + 1'b1; else QPSK_cnt <= 0; always@(posedge clk) if(rst_n == 1'b0) QPSK_data <= 0; else case(QPSK_cnt) 2'b00 : QPSK_data[0] <= s_data_tdata; 2'b01 : QPSK_data[1] <= s_data_tdata; 2'b10 : QPSK_data[2] <= s_data_tdata; 2'b11 : QPSK_data[3] <= s_data_tdata; default : QPSK_data <= QPSK_data; endcase always@(posedge clk) if(QPSK_cnt == 2'b11) map_ena <= 1'b1; else map_ena <= 1'b0; always@(posedge clk) if(map_ena)begin QPSK_mod_data <= {2'b00,QPSK_data[2],QPSK_data[3],2'b00,QPSK_data[0],QPSK_data[1]}; QPSK_mod_valid <= 1'b1; end else begin QPSK_mod_data <= 0; QPSK_mod_valid <= 0; end //16QAM always@(posedge clk) if(mode_type == 1'b1 && s_data_tvalid) QAM_cnt <= QAM_cnt + 1'b1; else QAM_cnt <= 0; always@(posedge clk) if(rst_n == 1'b0) QAM_data <= 0; else case(QAM_cnt) 3'b000 : QAM_data[0] <= s_data_tdata; 3'b001 : QAM_data[1] <= s_data_tdata; 3'b010 : QAM_data[2] <= s_data_tdata; 3'b011 : QAM_data[3] <= s_data_tdata; 3'b100 : QAM_data[4] <= s_data_tdata; 3'b101 : QAM_data[5] <= s_data_tdata; 3'b110 : QAM_data[6] <= s_data_tdata; 3'b111 : QAM_data[7] <= s_data_tdata; default : QAM_data <= QAM_data; endcase always@(posedge clk) if(QAM_cnt == 3'b111) map_enb <= 1'b1; else map_enb <= 1'b0; always@(posedge clk) if(map_enb)begin QAM_mod_data <= {QAM_data[0],QAM_data[6],QAM_data[4],QAM_data[2],QAM_data[5],QAM_data[3],QAM_data[1],QAM_data[7]}; QAM_mod_valid <= 1'b1; end else begin QAM_mod_data <= 0; QAM_mod_valid <= 0; end always@(posedge clk) map_wea <= QAM_mod_valid || QPSK_mod_valid; always@(posedge clk) if(mode_type == 0) map_dina <= QPSK_mod_data ; else map_dina <= QAM_mod_data; always@(posedge clk) if(rst_n == 1'b0) map_addra <= 0; else if(mode_type == 0 && map_addra == 12'd4050) map_addra <= 0; else if(mode_type == 1 && map_addra == 12'd2025) map_addra <= 0; else if(map_wea == 1'b1) map_addra <= map_addra + 1'b1; always@(posedge clk) if(map_addra > 12'd3100 && mode_type == 0) map_addrb <= map_addrb + 1'b1; else if(map_addra > 12'd1800 && mode_type == 1) map_addrb <= map_addrb + 1'b1; else if(map_addrb < (Ncell-1) && map_addrb > 0) map_addrb <= map_addrb + 1'b1; else map_addrb <= 0; //==================================================================================== // Output //==================================================================================== always@(posedge clk) if(mode_type) m_data_tdata <= {map_doutb[0],map_doutb[1],map_doutb[2],map_doutb[3]}; else m_data_tdata <= map_doutb; always@(posedge clk) if(~rst_n) m_data_tvalid <= 0; else if(map_addrb > 0) m_data_tvalid <= 1; else if(m_cnt == (Ncell -1)) m_data_tvalid <= 0; always@(posedge clk) if(m_data_tvalid) m_cnt <= m_cnt + 1'b1; else m_cnt <= 0; always@(posedge clk) if(m_cnt == (Ncell-2)) m_data_tlast <= 1'b1; else m_data_tlast <= 1'b0; //==================================================================================== // m_data_tready && s_data_tready //==================================================================================== always@(posedge clk) s_data_tvalid_reg <= s_data_tvalid; always@(posedge clk) if(rst_n == 1'b0) data_ordy <= 1'b0; else if(s_config_tvalid == 1'b1) data_ordy <= 1'b1; else if(start_data_invld == 1'b1) data_ordy <= 1'b0; else if(m_data_tlast == 1'b1) data_ordy <= 1'b1; always@(posedge clk) s_data_tready <= data_ordy && m_data_tready; map_ram map_ram( .clka (clk ), // input wire clka .wea (map_wea ), // input wire [0 : 0] wea .addra (map_addra ), // input wire [11 : 0] addra .dina (map_dina ), // input wire [7 : 0] dina .clkb (clk ), // input wire clkb .addrb (map_addrb ), // input wire [12 : 0] addrb .doutb (map_doutb ) // output wire [3 : 0] doutb ); endmodule

这部分代码也是主要参考了电子发烧友学院中的课程。代码非常简单,大家自己阅读学习即可,这里不再详细说明。

FPGA的映射测试代码

测试代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
`timescale 1ns / 1ps module tb_tx_Mapper; // Inputs reg clk ; reg rstn ; reg s_config_tvalid ; wire s_config_tdata ; reg s_data_tvalid ; reg s_data_tdata ; reg s_data_tlast ; reg m_data_tready ; // Outputs wire s_data_tready ; wire m_data_tvalid ; wire [3:0] m_data_tdata ; wire m_data_tlast ; reg s_data_tvalid1 ; reg s_data_tlast1 ; reg mode_type = 1 ; assign s_config_tdata = mode_type; integer i; initial begin clk = 0; rstn = 0; s_config_tvalid = 0; s_data_tvalid = 0; m_data_tready = 1; repeat(10) @(posedge clk);#1; rstn = 1; repeat(5) @(posedge clk);#1; s_config_tvalid = 1; repeat(1) @(posedge clk);#1; s_config_tvalid = 0; for(i=1;i<=1;i=i+1) begin repeat(1)@(posedge clk);#1; //begin s_data_tvalid = 1; s_data_tlast = 0; repeat(16200*1-1)@(posedge clk);#1; s_data_tvalid = 1; s_data_tlast =1; repeat(1)@(posedge clk);#1; //end s_data_tvalid = 0; s_data_tlast = 0; repeat(5000*1)@(posedge clk);#1; //IDLE end end always #5 clk = ~clk; //==================================================================================== // input //==================================================================================== always@(posedge clk) begin s_data_tvalid1 <=`UD s_data_tvalid; s_data_tlast1 <= `UD s_data_tlast; end integer fid1; initial begin fid1 = $fopen("mapper_in.txt","r"); end always@(posedge clk) begin if(s_data_tvalid) $fscanf(fid1,"%d",s_data_tdata); end //==================================================================================== // output //==================================================================================== integer fid2; initial begin fid2 = $fopen("ms_mapper_out.txt","w"); end always@(posedge clk) begin if(m_data_tvalid) $fwrite(fid2,"%dn",m_data_tdata); end tx_Mapper uut ( .clk (clk ), .rst_n (rstn ), .s_config_tvalid (s_config_tvalid ), .s_config_tdata (s_config_tdata ), .s_data_tvalid (s_data_tvalid1 ), .s_data_tdata (s_data_tdata ), .s_data_tready (s_data_tready ), .s_data_tlast (s_data_tlast1 ), .m_data_tvalid (m_data_tvalid ), .m_data_tdata (m_data_tdata ), .m_data_tready (m_data_tready ), .m_data_tlast (m_data_tlast ) ); endmodule

这部分测试代码的编写没有难度,这里不再介绍。

FPGA与MATLAB的交叉验证

通过阅读MATLAB代码,可以知道我们最后会把映射之后的信息保存到相应的mat文件,然后再Modelsim仿真的时候会将映射之后的结果保存到txt文件,那么我们通过MATLAB代码很容易验证实现两块内容的交叉验证。MATLAB代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
clc; clear all; load DataOut.mat data_lab = DataOut; map_data_lab = [data_lab]; fid1 = fopen('ms_mapper_out.txt','r'); map_data_sim = fscanf(fid1,'%d'); if(isempty(map_data_sim)) map_data_result = 0; else map_data_result = sum(abs(map_data_lab - map_data_sim(1:length(map_data_lab)))); end a = map_data_result;

运行之后,发现如下结果:
在这里插入图片描述
从而验证了我们实验的正确性。

小结

相信大家在学习算法的FPGA实现的时候都掌握了上面的流程,就是先在MATLAB中实现,然后再在FPGA中实现,交互验证实现的正确性。

参考文献

[1]、电子发烧友学院

总结

创作不易,认为文章有帮助的同学们可以关注、点赞、转发支持。为行业贡献及其微小的一部分。或者对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

最后

以上就是怡然缘分最近收集整理的关于基于FPGA的映射调制实现项目简述数学建模MATLAB仿真FPGA代码FPGA与MATLAB的交叉验证小结参考文献总结的全部内容,更多相关基于FPGA内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(112)

评论列表共有 0 条评论

立即
投稿
返回
顶部