ACS seems not to select the best channel in 2.4GHz.

Jouni Malinen j
Thu Feb 5 08:18:27 PST 2015


On Fri, Jan 30, 2015 at 02:45:25PM -0800, Fumikazu Yobimoto wrote:
> I verified the ACS(Auto Channel Select) in 2.4GHz environment.
> Set 2 APs, one is ch.1 and one is ch.11, and then transmit a heavy traffic
> at each channel.
> I'm expecting ACS should choose ch.6 for ideal channel, but it always
> choose ch.1 or ch.11 in any case.

> However, acs.c tries to add adjacent channel's value. Thus eventually,
> those values go like as following.
> 1=1.928 (1+2+3)
> 2=2.658 (1+2+3+4)
> 3=3.024 (1+2+3+4+5)

I guess the logic here could have been to assume that "channels" 0 and
-1 would have zero interference. That would not really be the case and I
agree that this would give way too much preference to channels 1 and 11
(and too much for 2 and 10 as well).

> I think it's not necessary to add adjacent value. Because radio survey data
> of each channel would detect the adjacent interference actually 20MHz.
> In fact, the test result shows that ch.4 detect the interference of ch.1,
> similarly ch.8 detect the interference of ch.11.
> I attached a patch file for hostapd-v2.3 .

I'm not sure skipping the adjacent channels completely on 2.4 GHz would
be ideal solution here. It is clear that the channels at each end of the
band will require something more accurate. It may also be reasonable to
at least drop the importance of the impact from adjacent channels. I'm
consider the following patch as a way of addressing this. If you define
ACS_ADJ_WEIGHT 0, ACS_NEXT_ADJ_WEIGHT 0, and ACS_24GHZ_PREFER_1_6_11 1,
you'd get the behavior you should saw with the patch you sent. If
someone has good suggestions on what the best numbers to use here as the
default would be, I'm certainly open to changing these. As noted in the
commit message, I did not really do any real research on picking the
numbers.


[PATCH] ACS: Fix 2.4 GHz adjacent channel interference summing

The interference factors for adjacent 2.4 GHz channels were summed
together without doing any kind of weighted average on them. This
resulted in the channels at the band edges getting undue preference due
to only including interference factors from three channels vs. five for
the channels in the middle of the band.

While it is somewhat unclear whether the design here was supposed to
count overlapping channels together in this way or whether that is
already covered in channel survey results, it is clear that this summing
of three to five values together and then comparing the sum rather than
average of some kind cannot be correct.

Use weighted average of the interference factors rather than a sum from
different number of values. For now, the adjacent 2.4 GHz channels get
weight of 0.5 (1.0 for the main channel itself) and the neighboring
channels to those adjacent ones get 0.25 weight. Band-edge channels are
handled in a way that takes average over the channels that were actually
considered instead of assuming zero interference from neighboring bands.

This change results in significantly less preference for the band-edge
channels. That is arguable good thing to do here, but it would also be
good to avoid picking some arbitrary 2.4 GHz channel and rather give
significant extra preference for the commonly used channels 1, 6, 11.
This is now done by picking those channels over the other ones unless
another channel has significantly better interference factor (0.8 or
smaller times the one on 1, 6, 11).

The initially used multiplier values used here are not based on any real
research, i.e., these are just a wild guess of somethign
semi-reasonable. The values can be optimized in the future and can also
be overridden in build parameters with C preprocessor macros
(ACS_ADJ_WEIGHT, ACS_NEXT_ADJ_WEIGHT, ACS_24GHZ_PREFER_1_6_11).

Signed-off-by: Jouni Malinen <jouni at qca.qualcomm.com>
---
 src/ap/acs.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 104 insertions(+), 18 deletions(-)

diff --git a/src/ap/acs.c b/src/ap/acs.c
index e4c834c..616b810 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -517,6 +517,23 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface,
 }
 
 
+#ifndef ACS_ADJ_WEIGHT
+#define ACS_ADJ_WEIGHT 0.5
+#endif /* ACS_ADJ_WEIGHT */
+
+#ifndef ACS_NEXT_ADJ_WEIGHT
+#define ACS_NEXT_ADJ_WEIGHT 0.25
+#endif /* ACS_NEXT_ADJ_WEIGHT */
+
+#ifndef ACS_24GHZ_PREFER_1_6_11
+/*
+ * Select commonly used channels 1, 6, 11 even if a neighboring channel has
+ * a smaller interference factor as long as it is not better by more than this
+ * multiplier.
+ */
+#define ACS_24GHZ_PREFER_1_6_11 0.8
+#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
 /*
  * At this point it's assumed chan->interface_factor has been computed.
  * This function should be reusable regardless of interference computation
@@ -529,7 +546,8 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 	struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
 		*rand_chan = NULL;
 	long double factor, ideal_factor = 0;
-	int i, j;
+	long double factor_chans[13];
+	int i, j, max_chans, ideal_idx = -1;
 	int n_chans = 1;
 
 	/* TODO: HT40- support */
@@ -556,7 +574,16 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 		   n_chans == 4 ? 80 :
 		   -1);
 
+	max_chans = iface->current_mode->num_channels;
+	if (max_chans > 13)
+		max_chans = 13;
+	for (i = 0; i < max_chans; i++)
+		factor_chans[i] = 0;
+
 	for (i = 0; i < iface->current_mode->num_channels; i++) {
+		double total_weight;
+		int usable;
+
 		chan = &iface->current_mode->channels[i];
 
 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
@@ -586,16 +613,20 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 		}
 
 		factor = 0;
-		if (acs_usable_chan(chan))
+		usable = acs_usable_chan(chan);
+		if (usable)
 			factor = chan->interference_factor;
+		total_weight = 1;
 
 		for (j = 1; j < n_chans; j++) {
 			adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
 			if (!adj_chan)
 				break;
 
-			if (acs_usable_chan(adj_chan))
+			if (acs_usable_chan(adj_chan)) {
 				factor += adj_chan->interference_factor;
+				total_weight += 1;
+			}
 		}
 
 		if (j != n_chans) {
@@ -609,38 +640,53 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B ||
 		    iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) {
 			for (j = 0; j < n_chans; j++) {
-				/* TODO: perhaps a multiplier should be used
-				 * here? */
-
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 5);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) - 10);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_NEXT_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_NEXT_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 5);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_ADJ_WEIGHT *
+						adj_chan->interference_factor;
+					total_weight += ACS_ADJ_WEIGHT;
+				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
 							 (j * 20) + 10);
-				if (adj_chan && acs_usable_chan(adj_chan))
-					factor += adj_chan->interference_factor;
+				if (adj_chan && acs_usable_chan(adj_chan)) {
+					factor += ACS_NEXT_ADJ_WEIGHT +
+						adj_chan->interference_factor;
+					total_weight += ACS_NEXT_ADJ_WEIGHT;
+				}
 			}
 		}
 
+		factor /= total_weight;
+
 		wpa_printf(MSG_DEBUG, "ACS:  * channel %d: total interference = %Lg",
 			   chan->chan, factor);
 
-		if (acs_usable_chan(chan) &&
-		    (!ideal_chan || factor < ideal_factor)) {
-			ideal_factor = factor;
-			ideal_chan = chan;
+		if (usable) {
+			if (i < max_chans)
+				factor_chans[i] = factor;
+			if (!ideal_chan || factor < ideal_factor) {
+				ideal_factor = factor;
+				ideal_chan = chan;
+				ideal_idx = i;
+			}
 		}
 
 		/* This channel would at least be usable */
@@ -648,6 +694,46 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
 			rand_chan = chan;
 	}
 
+	/*
+	 * Try to prefer commonly used channels 1, 6, and 11 unless
+	 * there is a significantly better channel available.
+	 */
+	if ((iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B ||
+	     iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) &&
+	    ideal_idx >= 0 && ideal_chan) {
+		if ((ideal_idx == 1 || ideal_idx == 2) &&
+		    factor_chans[0] > 0 &&
+		    factor_chans[ideal_idx] >
+		    ACS_24GHZ_PREFER_1_6_11 * factor_chans[0]) {
+			wpa_printf(MSG_DEBUG,
+				   "ACS: Prefer common 2.4 GHz channel 1 over ideal channel %d",
+				   ideal_chan->chan);
+			ideal_chan = &iface->current_mode->channels[0];
+		}
+
+		if ((ideal_idx == 3 || ideal_idx == 4 ||
+		     ideal_idx == 6 || ideal_idx == 7) &&
+		    factor_chans[5] > 0 &&
+		    factor_chans[ideal_idx] >
+		    ACS_24GHZ_PREFER_1_6_11 * factor_chans[5]) {
+			wpa_printf(MSG_DEBUG,
+				   "ACS: Prefer common 2.4 GHz channel 6 over ideal channel %d",
+				   ideal_chan->chan);
+			ideal_chan = &iface->current_mode->channels[5];
+		}
+
+		if ((ideal_idx == 8 || ideal_idx == 9 ||
+		     ideal_idx == 11 || ideal_idx == 12) &&
+		    factor_chans[10] > 0 &&
+		    factor_chans[ideal_idx] >
+		    ACS_24GHZ_PREFER_1_6_11 * factor_chans[10]) {
+			wpa_printf(MSG_DEBUG,
+				   "ACS: Prefer common 2.4 GHz channel 11 over ideal channel %d",
+				   ideal_chan->chan);
+			ideal_chan = &iface->current_mode->channels[10];
+		}
+	}
+
 	if (ideal_chan) {
 		wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
 			   ideal_chan->chan, ideal_chan->freq, ideal_factor);
-- 
1.9.1


-- 
Jouni Malinen                                            PGP id EFC895FA



More information about the Hostap mailing list