Skip to content

Computing the MCS Index from RF Parameters

The MCS Index is a way of comparing and ranking modulation and coding schemes within, and to some degree between, PHY(s).

MCS is an interesting thing to track because it correlates with signal quality. The higher an MCS Index that is used in a transmission, the more susceptible to interference it is going to be.

Some systems do not report MCS directly as an index however. When working with such systems, one can still compute an MCS estimate directly. Here's how.

Subcarriers

Subcarriers are the smallest, most irreducible unit of symbol transmission. Subcarriers are able to transmit a different amount of information with a different amount of interference sensitivity based on what modulation and coding scheme is being used. In higher interference environments, a lower modulation and coding scheme like BPSK or QPSK transmits data at a lower throughput but with much higher fault tolerance than a high modulation scheme like 64 QAM.

No matter which PHY you are using, the modulation determines the data rate you get per subcarrier. Note that 802.11ax/HE calls subcarriers Resource Units (RU) instead. In pre-802.11ax/HE PHYs, alls subcarriers of one transmission were intended for one receiving station, but resource units have added the capacity for one transmission to "speak to" multiple clients at once.

Every subcarrier gets to transmit its bits every data interval, which is a per-PHY constant * the Guard Interval. Practically speaking, it is a tiny fraction of a second. But add up all those fractions of a second, multiply that by the number of subcarriers/resource units, and multiply that by the number of spatial streams, and you have your data rate.

To calculate the bits per subcarrier per time period, multiply the modulation by the coding. For example, for BPSK, the modulation is 1, and the coding is 1/2. This gives a bitrate per subcarrier per time interval of 0.5.

The bits per subcarrier per time interval is the key pivot point. Once you know this, you can simply look up the MCS from a table. Getting there requires many pieces however:

Guard Interval (GI)

This is a difficult one because it is constantly changing, and therefore can not be reliably ascertained every single time with 100% certainty. The best we can do is assume a short guard interval is being used. The best I can do for now is try to make a reasonable assumption about what GI is being used in each PHY.

Number of Spatial Streams (NSS)

This is a fairly simple component of the whole system. 1 spatial stream = 1x multiplication of the overall data rate. Every client will have 1-4 NSS, though in the future this could go to 8 if manufacturers implement the whole spec.

Channel Width

This is an important input for knowing the number of subcarriers. Roughly speaking, doubling the channel width, doubles the number of subcarriers, but there are some complications depending on the number of pilot subcarriers, which is fixed and does not change as the channel becomes wider. In practice, there are relatively few channel width :: subcarrier count combinations, at least outside of 802.11ax. For 802.11ax, I made some asssumptions about the number of tones/RUs used for each channel width, based on mcsindex.net.

Data Rate

We need to know the data rate in order to decompose it into a rate per subcarrier based on our estimated number of subcarriers.

Nunber of subcarriers = nss * sub-carriers-per-channel-width

  • Data rate per sub carrier = data rate / number of sub carriers

  • MCS Index can be looked up based on the modulation and coding scheme used to get this data rate. In my solution I used the data rate per sub carrier to find the closest key in a hash of data_rates: modulation_schemes.

Example

In this example, the device's PHY is a 802.11ax and it is using MCS 5.

Parameters

  • 106 tone RU (106 subcarriers) (about half a 20mhz channel)
  • 2 spatial streams
  • 64 QAM modulation
  • 2/3 coding
  • 56.7 mbits data rate
  • 1.6 us GI
  • 1.28*10^-5 us Symbol Duration

Steps

  • Number of sub carriers = nss * subcarriers per spatial stream
  • Number of sub carriers = 2 * 106
  • Number of sub carriers = 212
  • Data Rate per subcarrier = rate * (data_interval + guard_interval) / subcarriers
  • Data Rate per sub carrier = 56.7*10^6 * (1.28*10^-5 + 1.6 * 10^-6) / 212
  • Data Rate per sub carrier = 3.86
  • Data Rate per sub carrier = modulation * coding
  • Data Rate per sub carrier = 6 * 2/3
  • Data Rate per sub carrier = 4

Being off by 0.14 is ok because 3.86 will still be closer to 4 in the table than any other modulation * coding product. Being incorrect about the GI will throw this off by a little bit, being incorrect about the number of resource units will throw it off a bit more.

At this point, I would take 3.86 and look up its nearest neighbor in my hash of MCS coding schemes keyed by data rates per subcarrier and find the key 4.

    # 6 * 2/3  => modulation, coding, index 64-QAM 2/3
    6.to_f * 2 / 3 => ["64-QAM", 2.to_f / 3, 5],

64-QAM, 2/3, and 5 are the Modulation, coding rate, and MCS Index respectively.

While the throughputs for each client may be known, an older client that is only WiFi5 capable may have an excellent MCS index, yet transmit at much lower data rates than WiFi6 clients. So, making the effort to determine the MCS Indices of transmissions gleans valuable insight into the environmental conditions around a given AP and its ability to sustain higher data rates of transmission.