View RSS Feed

weetabixharry

Working through Annex I.1 of the 802.11 PHY standard in MATLAB

Rate this Entry

Note: In earlier versions of the 802.11 standard, the (BCC) OFDM example was given in Annex G. However, an error existed (e.g. in IEEE Std 802.11-2007) in that the FCS was incorrect (see link or search online for "IEEE 802.11-09/0042r0").

The WiFi (802.11) standards documents are free to download from the IEEE webpages (see, for example, here). (Sadly, you are required to register first, which I would describe as irritating and pointless).

Nonetheless, I became interested in throwing together a simple 802.11g (OFDM) modulator. A really useful walk-through of how to do this is provided in Annex I.1 of this document.

However, there are a few gaps in the worked example and some details are perhaps easy to miss. Therefore, I thought I would share the MATLAB scripts I used for filling in the gaps. These are rather verbose, which I find makes them more useful as a reference, but less useful as anything resembling a usable implementation.

Unfortunately, the main script alone vastly exceeds edaboard's miserly character limit, so please download the full code here: wifi.zip.

As a quick taster, here is the start of the code. This excerpt gets you as far as the end of the STF:

Code Matlab M - [expand]
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
close all; clear all; clc;
 
% This script works through Annex I.1 of the 802.11-2016 standard.
 
% Make sure we can see the helper subroutines
addpath('helpers');
 
% ======================== %
% == I.1.1 Introduction == %
% ======================== %
 
% "This example uses the 36 Mb/s data rate..."
rate_info_lut = get_rate_info();
rate_info = rate_info_lut(6);
 
% "... and a message of 100 octets"
length_bytes = 100;
 
% ======================= %
% == I.1.2 The Message == %
% ======================= %
 
% The 72-character message
a = ['Joy, bright spark of divinity,' char(10) 'Daughter of Elysium,' char(10) 'Fire-insired we trea'];
 
% [Table I-1] The 100-byte PSDU in hex
% Comprises: 24-Byte MAC + 72-Byte DATA + 4-Byte CRC.
table_I1 = [...
'0402002e00';
'6008cd37a6';
'0020d6013c';
'f1006008ad';
'3baf00004a';
'6f792c2062';
'7269676874';
'2073706172';
'6b206f6620';
'646976696e';
'6974792c0a';
'4461756768';
'746572206f';
'6620456c79';
'7369756d2c';
'0a46697265';
'2d696e7369';
'7265642077';
'6520747265';
'61673321b6'];
 
% Gradually manipulate PSDU into vector of bytes
table_I1 = reshape(table_I1.',[],1);
psdu_hex = reshape(table_I1, 2, []).';
psdu_dec = hex2dec(psdu_hex);
 
% Separate PSDU into MAC header, message and CRC
mac_header_dec = psdu_dec(1:24);
message_dec = psdu_dec(25:end-4);
crc_dec = psdu_dec(end-3:end);
 
% Sanity check message content
message_char = char(message_dec).';
assert(isequal(message_char, a));
 
% ====================================== %
% == I.1.3 Generation of the preamble == %
% ====================================== %
 
% ------------------------------ %
% -- I.1.3.1 Short sequences  -- %
% ------------------------------ %
 
% [Table I-2] Frequency domain representation of the short sequences.
% Note: We'll use better precision here: sqrt(13/6) instead of 1.472.
p = 1+1j;
STF_26 = sqrt(13/6)*[0, 0, +p, 0, 0, 0, -p, 0, ...
                     0, 0, +p, 0, 0, 0, -p, 0, ...
                     0, 0, -p, 0, 0, 0, +p, 0, ...
                     0, 0,  0, 0, 0, 0, -p, 0, ...
                     0, 0, -p, 0, 0, 0, +p, 0, ...
                     0, 0, +p, 0, 0, 0, +p, 0, ...
                     0, 0, +p, 0, 0].';
% Zero-pad up to OFDM symbol size
table_I2 = [0*(-32:-27).'; STF_26; 0*(27:31).'];
 
% FFT shift to put DC where it belongs and do OFDM IFFT
stf_64 = ifft(fftshift(table_I2));
 
% [Table I-3] One period of IFFT of the short sequences
table_I3 = [
0 0.046 0.046 1 -0.132 0.002 2 -0.013 -0.079 3 0.143 -0.013
4 0.092 0.000 5 0.143 -0.013 6 -0.013 -0.079 7 -0.132 0.002
8 0.046 0.046 9 0.002 -0.132 10 -0.079 -0.013 11 -0.013 0.143
12 0.000 0.092 13 -0.013 0.143 14 -0.079 -0.013 15 0.002 -0.132
16 0.046 0.046 17 -0.132 0.002 18 -0.013 -0.079 19 0.143 -0.013
20 0.092 0.000 21 0.143 -0.013 22 -0.013 -0.079 23 -0.132 0.002
24 0.046 0.046 25 0.002 -0.132 26 -0.079 -0.013 27 -0.013 0.143
28 0.000 0.092 29 -0.013 0.143 30 -0.079 -0.013 31 0.002 -0.132
32 0.046 0.046 33 -0.132 0.002 34 -0.013 -0.079 35 0.143 -0.013
36 0.092 0.000 37 0.143 -0.013 38 -0.013 -0.079 39 -0.132 0.002
40 0.046 0.046 41 0.002 -0.132 42 -0.079 -0.013 43 -0.013 0.143
44 0.000 0.092 45 -0.013 0.143 46 -0.079 -0.013 47 0.002 -0.132
48 0.046 0.046 49 -0.132 0.002 50 -0.013 -0.079 51 0.143 -0.013
52 0.092 0.000 53 0.143 -0.013 54 -0.013 -0.079 55 -0.132 0.002
56 0.046 0.046 57 0.002 -0.132 58 -0.079 -0.013 59 -0.013 0.143
60 0.000 0.092 61 -0.013 0.143 62 -0.079 -0.013 63 0.002 -0.132];
% Discard columns of indices
table_I3(:,[1,4,7,10]) = [];
% Convert to complex
table_I3 = complex(table_I3(:,1:2:end), table_I3(:,2:2:end));
% Stack in order
table_I3 = reshape(table_I3.', [], 1);
 
% Sanity check (up to 3 decimal places)
table_I3_err = stf_64 - table_I3;
table_I3_err = [real(table_I3_err); imag(table_I3_err)];
assert(all(abs(table_I3_err) < 0.001));
 
% Extend periodically up to 161 samples. N.B. We don't need to do anything
% else for STF due to its 16-sample periodicity.
stf_161 = repmat(stf_64, ceil(161/64), 1);
stf_161 = stf_161(1:161);
% Apply window function
stf_161(1) = 0.5 * stf_161(1);
stf_161(161) = 0.5 * stf_161(161);
 
% [Table I-4] Time domain representation of the short sequence
table_I4 = [
0 0.023 0.023 1 -0.132 0.002 2 -0.013 -0.079 3 0.143 -0.013
4 0.092 0.000 5 0.143 -0.013 6 -0.013 -0.079 7 -0.132 0.002
8 0.046 0.046 9 0.002 -0.132 10 -0.079 -0.013 11 -0.013 0.143
12 0.000 0.092 13 -0.013 0.143 14 -0.079 -0.013 15 0.002 -0.132
16 0.046 0.046 17 -0.132 0.002 18 -0.013 -0.079 19 0.143 -0.013
20 0.092 0.000 21 0.143 -0.013 22 -0.013 -0.079 23 -0.132 0.002
24 0.046 0.046 25 0.002 -0.132 26 -0.079 -0.013 27 -0.013 0.143
28 0.000 0.092 29 -0.013 0.143 30 -0.079 -0.013 31 0.002 -0.132
32 0.046 0.046 33 -0.132 0.002 34 -0.013 -0.079 35 0.143 -0.013
36 0.092 0.000 37 0.143 -0.013 38 -0.013 -0.079 39 -0.132 0.002
40 0.046 0.046 41 0.002 -0.132 42 -0.079 -0.013 43 -0.013 0.143
44 0.000 0.092 45 -0.013 0.143 46 -0.079 -0.013 47 0.002 -0.132
48 0.046 0.046 49 -0.132 0.002 50 -0.013 -0.079 51 0.143 -0.013
52 0.092 0.000 53 0.143 -0.013 54 -0.013 -0.079 55 -0.132 0.002
56 0.046 0.046 57 0.002 -0.132 58 -0.079 -0.013 59 -0.013 0.143
60 0.000 0.092 61 -0.013 0.143 62 -0.079 -0.013 63 0.002 -0.132
64 0.046 0.046 65 -0.132 0.002 66 -0.013 -0.079 67 0.143 -0.013
68 0.092 0.000 69 0.143 -0.013 70 -0.013 -0.079 71 -0.132 0.002
72 0.046 0.046 73 0.002 -0.132 74 -0.079 -0.013 75 -0.013 0.143
76 0.000 0.092 77 -0.013 0.143 78 -0.079 -0.013 79 0.002 -0.132
80 0.046 0.046 81 -0.132 0.002 82 -0.013 -0.079 83 0.143 -0.013
84 0.092 0.000 85 0.143 -0.013 86 -0.013 -0.079 87 -0.132 0.002
88 0.046 0.046 89 0.002 -0.132 90 -0.079 -0.013 91 -0.013 0.143
92 0.000 0.092 93 -0.013 0.143 94 -0.079 -0.013 95 0.002 -0.132
96 0.046 0.046 97 -0.132 0.002 98 -0.013 -0.079 99 0.143 -0.013
100 0.092 0.000 101 0.143 -0.013 102 -0.013 -0.079 103 -0.132 0.002
104 0.046 0.046 105 0.002 -0.132 106 -0.079 -0.013 107 -0.013 0.143
108 0.000 0.092 109 -0.013 0.143 110 -0.079 -0.013 111 0.002 -0.132
112 0.046 0.046 113 -0.132 0.002 114 -0.013 -0.079 115 0.143 -0.013
116 0.092 0.000 117 0.143 -0.013 118 -0.013 -0.079 119 -0.132 0.002
120 0.046 0.046 121 0.002 -0.132 122 -0.079 -0.013 123 -0.013 0.143
124 0.000 0.092 125 -0.013 0.143 126 -0.079 -0.013 127 0.002 -0.132
128 0.046 0.046 129 -0.132 0.002 130 -0.013 -0.079 131 0.143 -0.013
132 0.092 0.000 133 0.143 -0.013 134 -0.013 -0.079 135 -0.132 0.002
136 0.046 0.046 137 0.002 -0.132 138 -0.079 -0.013 139 -0.013 0.143
140 0.000 0.092 141 -0.013 0.143 142 -0.079 -0.013 143 0.002 -0.132
144 0.046 0.046 145 -0.132 0.002 146 -0.013 -0.079 147 0.143 -0.013
148 0.092 0.000 149 0.143 -0.013 150 -0.013 -0.079 151 -0.132 0.002
152 0.046 0.046 153 0.002 -0.132 154 -0.079 -0.013 155 -0.013 0.143
156 0.000 0.092 157 -0.013 0.143 158 -0.079 -0.013 159 0.002 -0.132
160 0.023 0.023 000 000000 00000 000 000000 000000 000 00000 000000];
% Discard columns of indices
table_I4(:,[1,4,7,10]) = [];
% Convert to complex
table_I4 = complex(table_I4(:,1:2:end), table_I4(:,2:2:end));
% Stack in order
table_I4 = reshape(table_I4.', [], 1);
% Discard zero-padding at the end
table_I4 = table_I4(1:161);
 
% Sanity check (up to 3 decimal places)
table_I4_err = stf_161 - table_I4;
table_I4_err = [real(table_I4_err); imag(table_I4_err)];
assert(all(abs(table_I4_err) < 0.001));

Again, please download the full code (wifi.zip) and feel free to post any questions here.

Updated 31st October 2018 at 08:02 by weetabixharry

Tags: None Add / Edit Tags
Categories
Uncategorized

Comments