bastibl / gr-ieee802-11

IEEE 802.11 a/g/p Transceiver
https://wime-project.net/
GNU General Public License v3.0
751 stars 293 forks source link

WiFi Halow : Synchronization and Equalization #416

Open neo-knight-td opened 2 weeks ago

neo-knight-td commented 2 weeks ago

@bastibl Work was recently conducted to extend your repository to support 802.11ah (https://github.com/irongiant33/gr-halow). Adaptation of the synchronization and equalization logic is however required, provided the significant differences between the two 802.11 variants.

I was trying to reverse engineer your sync_short.cc, sync_long.cc and frame_equalizer_impl.cc codes but I eventually got stuck when reaching the sampling offset compensation and residual frequency offset compensation steps. I read in your blog that you base yourself on the paper “Frequency Offset Estimation and Correction in the IEEE 802.11a WLAN”, by Essam Sourour, Hussein El-Ghoroury and Dale McNeill for implementing these steps. However, I still observe mismatches between the paper equations and your implementation.

Here are some the divergences I could not resolve :

Help and/or documentation would be greatly appreciated as it would allow re-using these calculation methods for Halow.

Thank you !

bastibl commented 2 weeks ago

Hi, glad you're looking into it.

Why do you multiply the frequency offset computed on the LTF by the bandwidth for computing epsilon_0 on line 147 ?

Sync Short and Sync Long calculate the offsets in radians. At this point, the values are normalized to the sample rate (=bandwidth) and the center frequency.

Why don't you take into account the channel gain (see Equation 8) when computing beta on line 172 and line 176

At 172, we are receiving the long training sequence, i.e., there is no channel estimate yet. At 176, it would be possible, but I'm not sure that it would be better. In the current version, pilots with smaller amplitude (and probably lower SNR) have a smaller impact.

Where does this "-" come from when adding the second pilot on line 172 ?

This is for the first two symbols, i.e., the long training sequence, which has the given polarities. Check the corresponding indices of this vector: https://github.com/bastibl/gr-ieee802-11/blob/ce7097384bb29f9e73777cf1458a072a90430528/utils/sync_words.py#L6

Why do you multiply each pilot by its polarity on line 176 ?

Because they are sent with the given polarity. I'm not sure I get the question.

On what equations do you base yourself for updating epsilon_r on line 208 ? You implementation has similarities with Equation 12 but still is not completly equivalent to it.

According to my understanding, the paper suggests a more complicated version that has advantages for fixed-point HW implementations. I don't think this is required here.

Hope it helps.

neo-knight-td commented 2 weeks ago

Thank you for your swift reply !

Sync Short and Sync Long calculate the offsets in radians. At this point, the values are normalized to the sample rate (=bandwidth) and the center frequency.

Ok, got it. You normalize these values according to Equation 1.

At 172, we are receiving the long training sequence, i.e., there is no channel estimate yet. At 176, it would be possible, but I'm not sure that it would be better. In the current version, pilots with smaller amplitude (and probably lower SNR) have a smaller impact.

I agree that for the first two symbols it is not possible to do better. For the following symbols, I am just wondering how your implementation works if no channel gain is taken into account. How I understand it from the paper is that the residual carrier frequency offset is a phase offset that is common to all sub-carriers across the same symbol and that is corrected using the pilot symbol (because we know their phase). Now, because your channel introduces a phase shift that is not linear across frequencies, beta will not correctly estimate this residual carrier frequency offset (after removing the sampling frequency offset, not all your pilots will have the same phase, because of the channel gain). So I understand your computation but I am just surprised it actually works.

This is for the first two symbols, i.e., the long training sequence, which has the given polarities. Check the corresponding indices of this vector:

Ok, makes sense.

Because they are sent with the given polarity. I'm not sure I get the question.

My first question was a bit immature. After reading the paper again, I understand why none of this would work without this correction.

According to my understanding, the paper suggests a more complicated version that has advantages for fixed-point HW implementations. I don't think this is required here.

Ok so what you do is computing W_l (Equation 10) and taking its argument as a basis for estimating epsilon_r. What I don't get is where does this updating method come from at line 208. Why don't you just put d_er = e ? Where does this alpha = 0.1 come from ?

Your help is precious. Thanks a lot for your answers !

bastibl commented 2 weeks ago

I agree that for the first two symbols it is not possible to do better. For the following symbols, I am just wondering how your implementation works if no channel gain is taken into account. How I understand it from the paper is that the residual carrier frequency offset is a phase offset that is common to all sub-carriers across the same symbol and that is corrected using the pilot symbol (because we know their phase). Now, because your channel introduces a phase shift that is not linear across frequencies, beta will not correctly estimate this residual carrier frequency offset (after removing the sampling frequency offset, not all your pilots will have the same phase, because of the channel gain). So I understand your computation but I am just surprised it actually works.

Makes sense. I don't have the time at the moment to have a closer look myself. Maybe you could give it a try shifting this after the equalization step and see if this improves performance. (I assume this is what you're suggesting?)

Ok so what you do is computing W_l (Equation 10) and taking its argument as a basis for estimating epsilon_r. What I don't get is where does this updating method come from at line 208. Why don't you just put d_er = e ? Where does this alpha = 0.1 come from ?

This is just a moving average. https://en.wikipedia.org/wiki/Exponential_smoothing There is no science behind the 0.1. The ideal value would probably depend on the coherence time of the channel.