13 * |
13 * |
14 * You should have received a copy of the GNU General Public License |
14 * You should have received a copy of the GNU General Public License |
15 * along with this program; if not, write to the Free Software |
15 * along with this program; if not, write to the Free Software |
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 * |
17 * |
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
18 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr> |
|
19 * Sébastien Deronne <sebastien.deronne@gmail.com> |
19 */ |
20 */ |
20 |
21 |
21 #include "wifi-mode.h" |
22 #include "wifi-mode.h" |
22 #include "ns3/simulator.h" |
23 #include "ns3/simulator.h" |
23 #include "ns3/assert.h" |
24 #include "ns3/assert.h" |
24 #include "ns3/log.h" |
25 #include "ns3/log.h" |
|
26 #include <cmath> |
25 |
27 |
26 namespace ns3 { |
28 namespace ns3 { |
27 |
29 |
28 /** |
30 /** |
29 * Check if the two WifiModes are identical. |
31 * Check if the two WifiModes are identical. |
65 is >> str; |
67 is >> str; |
66 mode = WifiModeFactory::GetFactory ()->Search (str); |
68 mode = WifiModeFactory::GetFactory ()->Search (str); |
67 return is; |
69 return is; |
68 } |
70 } |
69 |
71 |
70 uint32_t |
|
71 WifiMode::GetBandwidth (void) const |
|
72 { |
|
73 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
|
74 return item->bandwidth; |
|
75 } |
|
76 |
|
77 uint64_t |
72 uint64_t |
78 WifiMode::GetPhyRate (void) const |
73 WifiMode::GetPhyRate (uint32_t channelWidth, bool isShortGuardInterval, uint8_t nss) const |
79 { |
74 { |
80 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
75 uint32_t dataRate, phyRate; |
81 return item->phyRate; |
76 dataRate = GetDataRate (channelWidth, isShortGuardInterval, nss); |
|
77 switch (GetCodeRate (nss)) |
|
78 { |
|
79 case WIFI_CODE_RATE_5_6: |
|
80 phyRate = dataRate * 6 / 5; |
|
81 break; |
|
82 case WIFI_CODE_RATE_3_4: |
|
83 phyRate = dataRate * 4 / 3; |
|
84 break; |
|
85 case WIFI_CODE_RATE_2_3: |
|
86 phyRate = dataRate * 3 / 2; |
|
87 break; |
|
88 case WIFI_CODE_RATE_1_2: |
|
89 phyRate = dataRate * 2 / 1; |
|
90 break; |
|
91 case WIFI_CODE_RATE_UNDEFINED: |
|
92 default: |
|
93 phyRate = dataRate; |
|
94 break; |
|
95 } |
|
96 return phyRate; |
82 } |
97 } |
83 |
98 |
84 uint64_t |
99 uint64_t |
85 WifiMode::GetDataRate (void) const |
100 WifiMode::GetDataRate (uint32_t channelWidth, bool isShortGuardInterval, uint8_t nss) const |
86 { |
101 { |
87 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
102 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
88 return item->dataRate; |
103 uint64_t dataRate = 0; |
|
104 if (nss > 1) |
|
105 { |
|
106 NS_FATAL_ERROR ("MIMO is not supported"); |
|
107 return 0; |
|
108 } |
|
109 if (item->modClass == WIFI_MOD_CLASS_DSSS) |
|
110 { |
|
111 dataRate = (11000000 / 11) * log2 (GetConstellationSize (1)); |
|
112 } |
|
113 else if (item->modClass == WIFI_MOD_CLASS_HR_DSSS) |
|
114 { |
|
115 dataRate = (11000000 / 8) * log2 (GetConstellationSize (1)); |
|
116 } |
|
117 else if (item->modClass == WIFI_MOD_CLASS_OFDM || item->modClass == WIFI_MOD_CLASS_ERP_OFDM) |
|
118 { |
|
119 double symbolRate = (1 / 4.0) * 1e6; |
|
120 |
|
121 uint32_t usableSubCarriers; |
|
122 switch (channelWidth) |
|
123 { |
|
124 case 20: |
|
125 default: |
|
126 usableSubCarriers = 48; |
|
127 break; |
|
128 case 10: |
|
129 usableSubCarriers = 24; |
|
130 break; |
|
131 case 5: |
|
132 usableSubCarriers = 12; |
|
133 break; |
|
134 } |
|
135 |
|
136 double codingRate; |
|
137 switch (GetCodeRate (1)) |
|
138 { |
|
139 case WIFI_CODE_RATE_3_4: |
|
140 codingRate = (3.0 / 4.0); |
|
141 break; |
|
142 case WIFI_CODE_RATE_2_3: |
|
143 codingRate = (2.0 / 3.0); |
|
144 break; |
|
145 case WIFI_CODE_RATE_1_2: |
|
146 codingRate = (1.0 / 2.0); |
|
147 break; |
|
148 case WIFI_CODE_RATE_UNDEFINED: |
|
149 default: |
|
150 NS_FATAL_ERROR ("trying to get datarate for a mcs without any coding rate defined"); |
|
151 break; |
|
152 } |
|
153 |
|
154 uint32_t numberOfBitsPerSubcarrier = log2 (GetConstellationSize (1)); |
|
155 |
|
156 dataRate = lrint (ceil (symbolRate * usableSubCarriers * numberOfBitsPerSubcarrier * codingRate)); |
|
157 } |
|
158 else if (item->modClass == WIFI_MOD_CLASS_HT || item->modClass == WIFI_MOD_CLASS_VHT) |
|
159 { |
|
160 if (item->mcsValue == 9) |
|
161 { |
|
162 //VHT MCS 9 forbidden at 20 MHz |
|
163 NS_ASSERT (channelWidth != 20); |
|
164 } |
|
165 |
|
166 double symbolRate; |
|
167 if (!isShortGuardInterval) |
|
168 { |
|
169 symbolRate = (1 / 4.0) * 1e6; |
|
170 } |
|
171 else |
|
172 { |
|
173 symbolRate = (1 / 3.6) * 1e6; |
|
174 } |
|
175 |
|
176 uint32_t usableSubCarriers; |
|
177 switch (channelWidth) |
|
178 { |
|
179 case 20: |
|
180 default: |
|
181 usableSubCarriers = 52; |
|
182 break; |
|
183 case 40: |
|
184 usableSubCarriers = 108; |
|
185 break; |
|
186 case 80: |
|
187 usableSubCarriers = 234; |
|
188 break; |
|
189 case 160: |
|
190 usableSubCarriers = 468; |
|
191 break; |
|
192 } |
|
193 |
|
194 double codingRate; |
|
195 switch (GetCodeRate (nss)) |
|
196 { |
|
197 case WIFI_CODE_RATE_5_6: |
|
198 codingRate = (5.0 / 6.0); |
|
199 break; |
|
200 case WIFI_CODE_RATE_3_4: |
|
201 codingRate = (3.0 / 4.0); |
|
202 break; |
|
203 case WIFI_CODE_RATE_2_3: |
|
204 codingRate = (2.0 / 3.0); |
|
205 break; |
|
206 case WIFI_CODE_RATE_1_2: |
|
207 codingRate = (1.0 / 2.0); |
|
208 break; |
|
209 case WIFI_CODE_RATE_UNDEFINED: |
|
210 default: |
|
211 NS_FATAL_ERROR ("trying to get datarate for a mcs without any coding rate defined"); |
|
212 break; |
|
213 } |
|
214 |
|
215 uint32_t numberOfBitsPerSubcarrier = log2 (GetConstellationSize (nss)); |
|
216 |
|
217 dataRate = lrint (ceil (symbolRate * usableSubCarriers * numberOfBitsPerSubcarrier * codingRate)); |
|
218 } |
|
219 else |
|
220 { |
|
221 NS_ASSERT ("undefined datarate for the modulation class!"); |
|
222 } |
|
223 return dataRate; |
89 } |
224 } |
90 |
225 |
91 enum WifiCodeRate |
226 enum WifiCodeRate |
92 WifiMode::GetCodeRate (void) const |
227 WifiMode::GetCodeRate (uint8_t nss) const |
93 { |
228 { |
94 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
229 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
95 return item->codingRate; |
230 if (item->modClass == WIFI_MOD_CLASS_HT) |
96 } |
231 { |
97 |
232 NS_ASSERT (nss <= 4); |
98 uint8_t |
233 NS_ASSERT ((item->mcsValue - (8 * (nss - 1))) >= 0 || (item->mcsValue - (8 * (nss - 1))) <= 7); |
99 WifiMode::GetConstellationSize (void) const |
234 switch (item->mcsValue - (8 * (nss - 1))) |
100 { |
235 { |
101 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
236 case 0: |
102 return item->constellationSize; |
237 case 1: |
|
238 case 3: |
|
239 return WIFI_CODE_RATE_1_2; |
|
240 case 2: |
|
241 case 4: |
|
242 case 6: |
|
243 return WIFI_CODE_RATE_3_4; |
|
244 case 5: |
|
245 return WIFI_CODE_RATE_2_3; |
|
246 case 7: |
|
247 return WIFI_CODE_RATE_5_6; |
|
248 default: |
|
249 return WIFI_CODE_RATE_UNDEFINED; |
|
250 } |
|
251 } |
|
252 else if (item->modClass == WIFI_MOD_CLASS_VHT) |
|
253 { |
|
254 NS_ASSERT (nss <= 8); |
|
255 switch (item->mcsValue) |
|
256 { |
|
257 case 0: |
|
258 case 1: |
|
259 case 3: |
|
260 return WIFI_CODE_RATE_1_2; |
|
261 case 2: |
|
262 case 4: |
|
263 case 6: |
|
264 case 8: |
|
265 return WIFI_CODE_RATE_3_4; |
|
266 case 5: |
|
267 return WIFI_CODE_RATE_2_3; |
|
268 case 7: |
|
269 case 9: |
|
270 return WIFI_CODE_RATE_5_6; |
|
271 default: |
|
272 return WIFI_CODE_RATE_UNDEFINED; |
|
273 } |
|
274 } |
|
275 else |
|
276 { |
|
277 return item->codingRate; |
|
278 } |
|
279 } |
|
280 |
|
281 uint16_t |
|
282 WifiMode::GetConstellationSize (uint8_t nss) const |
|
283 { |
|
284 struct WifiModeFactory::WifiModeItem *item = WifiModeFactory::GetFactory ()->Get (m_uid); |
|
285 if (item->modClass == WIFI_MOD_CLASS_HT) |
|
286 { |
|
287 NS_ASSERT (nss <= 4); |
|
288 NS_ASSERT ((item->mcsValue - (8 * (nss - 1))) >= 0 || (item->mcsValue - (8 * (nss - 1))) <= 7); |
|
289 switch (item->mcsValue - (8 * (nss - 1))) |
|
290 { |
|
291 case 0: |
|
292 return 2; |
|
293 case 1: |
|
294 case 2: |
|
295 return 4; |
|
296 case 3: |
|
297 case 4: |
|
298 return 16; |
|
299 case 5: |
|
300 case 6: |
|
301 case 7: |
|
302 return 64; |
|
303 default: |
|
304 return 0; |
|
305 } |
|
306 } |
|
307 else if (item->modClass == WIFI_MOD_CLASS_VHT) |
|
308 { |
|
309 NS_ASSERT (nss <= 8); |
|
310 switch (item->mcsValue) |
|
311 { |
|
312 case 0: |
|
313 return 2; |
|
314 case 1: |
|
315 case 2: |
|
316 return 4; |
|
317 case 3: |
|
318 case 4: |
|
319 return 16; |
|
320 case 5: |
|
321 case 6: |
|
322 case 7: |
|
323 return 64; |
|
324 case 8: |
|
325 case 9: |
|
326 return 256; |
|
327 default: |
|
328 return 0; |
|
329 } |
|
330 } |
|
331 else |
|
332 { |
|
333 return item->constellationSize; |
|
334 } |
103 } |
335 } |
104 |
336 |
105 std::string |
337 std::string |
106 WifiMode::GetUniqueName (void) const |
338 WifiMode::GetUniqueName (void) const |
107 { |
339 { |
152 |
401 |
153 WifiMode |
402 WifiMode |
154 WifiModeFactory::CreateWifiMode (std::string uniqueName, |
403 WifiModeFactory::CreateWifiMode (std::string uniqueName, |
155 enum WifiModulationClass modClass, |
404 enum WifiModulationClass modClass, |
156 bool isMandatory, |
405 bool isMandatory, |
157 uint32_t bandwidth, |
|
158 uint32_t dataRate, |
|
159 enum WifiCodeRate codingRate, |
406 enum WifiCodeRate codingRate, |
160 uint8_t constellationSize) |
407 uint16_t constellationSize) |
161 { |
408 { |
162 WifiModeFactory *factory = GetFactory (); |
409 WifiModeFactory *factory = GetFactory (); |
163 uint32_t uid = factory->AllocateUid (uniqueName); |
410 uint32_t uid = factory->AllocateUid (uniqueName); |
164 WifiModeItem *item = factory->Get (uid); |
411 WifiModeItem *item = factory->Get (uid); |
165 item->uniqueUid = uniqueName; |
412 item->uniqueUid = uniqueName; |
166 item->modClass = modClass; |
413 item->modClass = modClass; |
167 //The modulation class for this WifiMode must be valid. |
414 //The modulation class for this WifiMode must be valid. |
168 NS_ASSERT (modClass != WIFI_MOD_CLASS_UNKNOWN); |
415 NS_ASSERT (modClass != WIFI_MOD_CLASS_UNKNOWN); |
169 item->bandwidth = bandwidth; |
|
170 item->dataRate = dataRate; |
|
171 item->codingRate = codingRate; |
416 item->codingRate = codingRate; |
172 |
|
173 switch (codingRate) |
|
174 { |
|
175 case WIFI_CODE_RATE_5_6: |
|
176 item->phyRate = dataRate * 6 / 5; |
|
177 break; |
|
178 case WIFI_CODE_RATE_3_4: |
|
179 item->phyRate = dataRate * 4 / 3; |
|
180 break; |
|
181 case WIFI_CODE_RATE_2_3: |
|
182 item->phyRate = dataRate * 3 / 2; |
|
183 break; |
|
184 case WIFI_CODE_RATE_1_2: |
|
185 item->phyRate = dataRate * 2 / 1; |
|
186 break; |
|
187 case WIFI_CODE_RATE_UNDEFINED: |
|
188 default: |
|
189 item->phyRate = dataRate; |
|
190 break; |
|
191 } |
|
192 |
417 |
193 //Check for compatibility between modulation class and coding |
418 //Check for compatibility between modulation class and coding |
194 //rate. If modulation class is DSSS then coding rate must be |
419 //rate. If modulation class is DSSS then coding rate must be |
195 //undefined, and vice versa. I could have done this with an |
420 //undefined, and vice versa. I could have done this with an |
196 //assertion, but it seems better to always give the error (i.e., |
421 //assertion, but it seems better to always give the error (i.e., |
197 //not only in non-optimised builds) and the cycles that extra test |
422 //not only in non-optimised builds) and the cycles that extra test |
198 //here costs are only suffered at simulation setup. |
423 //here costs are only suffered at simulation setup. |
199 if ((codingRate == WIFI_CODE_RATE_UNDEFINED) != (modClass == WIFI_MOD_CLASS_DSSS)) |
424 if ((codingRate == WIFI_CODE_RATE_UNDEFINED) && modClass != WIFI_MOD_CLASS_DSSS && modClass != WIFI_MOD_CLASS_HR_DSSS) |
200 { |
425 { |
201 NS_FATAL_ERROR ("Error in creation of WifiMode named " << uniqueName << std::endl |
426 NS_FATAL_ERROR ("Error in creation of WifiMode named " << uniqueName << std::endl |
202 << "Code rate must be WIFI_CODE_RATE_UNDEFINED iff Modulation Class is WIFI_MOD_CLASS_DSSS"); |
427 << "Code rate must be WIFI_CODE_RATE_UNDEFINED iff Modulation Class is WIFI_MOD_CLASS_DSSS or WIFI_MOD_CLASS_HR_DSSS"); |
203 } |
428 } |
204 |
429 |
205 item->constellationSize = constellationSize; |
430 item->constellationSize = constellationSize; |
206 item->isMandatory = isMandatory; |
431 item->isMandatory = isMandatory; |
|
432 |
|
433 NS_ASSERT (modClass != WIFI_MOD_CLASS_HT && modClass != WIFI_MOD_CLASS_VHT); |
|
434 //fill unused mcs item with a dummy value |
|
435 item->mcsValue = 0; |
|
436 |
|
437 return WifiMode (uid); |
|
438 } |
|
439 |
|
440 WifiMode |
|
441 WifiModeFactory::CreateWifiMcs (std::string uniqueName, |
|
442 uint8_t mcsValue, |
|
443 enum WifiModulationClass modClass) |
|
444 { |
|
445 WifiModeFactory *factory = GetFactory (); |
|
446 uint32_t uid = factory->AllocateUid (uniqueName); |
|
447 WifiModeItem *item = factory->Get (uid); |
|
448 item->uniqueUid = uniqueName; |
|
449 item->modClass = modClass; |
|
450 |
|
451 //The modulation class must be either HT or VHT |
|
452 NS_ASSERT (modClass == WIFI_MOD_CLASS_HT || modClass == WIFI_MOD_CLASS_VHT); |
|
453 |
|
454 item->mcsValue = mcsValue; |
|
455 //fill unused items with dummy values |
|
456 item->constellationSize = 0; |
|
457 item->codingRate = WIFI_CODE_RATE_UNDEFINED; |
|
458 item->isMandatory = false; |
207 |
459 |
208 return WifiMode (uid); |
460 return WifiMode (uid); |
209 } |
461 } |
210 |
462 |
211 WifiMode |
463 WifiMode |