Включить поддержку ldpc кодирования в роутере

Предисловие

С кодами малой плотности проверок на чётность, которые дальше мы будем именовать коротко LDPC (Low-density parity-check codes), мне удалось познакомиться более или менее близко, работая над семестровым научным проектом в ТУ Ильменау (магистерская программа CSP). Моему научному руководителю направление было интересно в рамках педагогической деятельности (нужно было пополнить базу примеров, а также посмотреть в сторону недвоичных LDPC), а мне из-за того, что эти коды были плюс-минус на слуху на нашей кафедре. Не все удалось рассмотреть в том году, и поэтому исследование плавно перетекло в мое хобби… Так я набрал некоторое количество материала, которым сегодня и хочу поделиться!

Кому может быть интересна данная статья:

  1. Студентам, которые хотят разобраться с данными кодами (в начале статьи будет много теории, я предупредил).
  2. Преподавателям, которые хотели бы добавить коды LDPC в область своих семинаров.
  3. Всем, кто любит покопаться в различных алгоритмах, а также чего-нибудь помоделировать и посравнивать (в конце будут примеры: как скрипты, так и реализации «из коробки» open-source проекта aff3ct).

В общем, присоединяйтесь!

Внимание:
Предполагается, что читатель знаком с основами помехоустойчивого кодирования. Если тема совсем нова, то от себя в качестве ликбеза могу предложить данный материал: Channel codes basics (CommPy).

Содержание

  1. Краткая историческая справка
  2. Азы блочного кодирования
  3. Азы LDPC кодов
  4. Декодирование LDPC кодов
  5. Пример декодирования через SPA на Python (NumPy)
  6. Готовые решения для моделирования (AFF3CT)

Краткая историческая справка

LDPC коды — идея довольно старая, впервые они были описаны Робертом Галлагером ещё в 1963 г. в его работе на степень PhD [1]. Однако, из-за своей неоправданной сложности (по тем временам) они не находили применения в технике относительно долгое время.

И только в 1990-х годах эти коды были, так сказать, заново открыты М. Дэви и Д. Маккеем, которые предложили инновационные на тот момент способы построения LDPC кодов с уменьшенной сложностью [2].

Сейчас LDPC коды это:

  1. Часть Wi-Fi стандарта (802.11n, 802.11ac, в более ранних стандартах, насколько я знаю, использовались сверточные коды);
  2. Часть стандартов группы DVB-x2;
  3. Часть стандарта радиочасти сетей мобильной связи 5G (NR — New Radio)[3];
  4. Помехоустойчивый код, использующийся во флэш-памяти (ссылка на статью на Хабре от alexzeynikov)

Кроме того, все больше LDPC коды проникают и в спутниковую связь. В свое время, я делал небольшой обзор по малым спутникам CubeSat (посмотреть можно по ссылке) — там тенденция однозначная и обусловлена внедрением стандартов DVB-S2/S2X.

И я думаю, это прекрасная мотивация узнать о данных кодах немного больше.

Азы блочного кодирования

LDPC коды — это линейные блочные коды, а значит проверочные биты в данной схеме кодирования добавляются в конец информационного сообщения — блоком.

Соответсвенно, процедура кодирования (encoding) — есть ничто иное, как перемножение вектора информационного сообщения длинной K на некоторую порождающую матрицу \mathbf{G}:

\underset{1\times N} {\mathbf{a}} = \underset{1\times K} {\mathbf{u}} \otimes  \underset{K\times N} {\mathbf{G}}\qquad (1)

где символ \otimes — это умножение по модулю (см. modulo). Для двоичных кодов это modulo 2, для недвоичных modulo q, исходя из полей Галуа GF(q = 2^p).

Соответственно, и кодовая скорость тоже задается через порождающую матрицу:

Порождающая матрица состоит из двух конкатенированных (соединенных) частей:

\underset{K\times N} {\mathbf{G}} = \left[ \underset{K\times K} {\mathbf{I}} \qquad  \underset{K\times (N-K)} {\mathbf{-P}}\right] \qquad (2)

где \mathbf{P} — это, так называемая, четная (parity) часть, а \mathbf{I} — единичная (identity) матрица.

Зачем нужен минус перед второй частью?

Дело в том, что при умножении и сложении по модулю нужно соблюдать правила сопоставления отрицательных и положительных чисел:

На двоичном случае все это незаметно, и поэтому минус иногда пропускают.

Так как мы говорим о линейных блочных кодах, порождающая матрица и должна обеспечивать эту линейность (см. Linear code). То есть, строки порождающей матрицы должны быть линейно независимыми (да, на слух звучит немного парадоксально).

Обратите внимание, identity-часть нужна для того, чтобы оставлять код систематическим: информационное сообщение остается неизменным, а проверочные биты добавляются в конец блоком. При такой схеме, правильно восстановив кодовое слово, можно восстановить и изначальное сообщение, просто убрав проверочные биты. Удобно, не правда ли?

Порождающая матрица напрямую связана с другой важнейшей матрицей, использующейся во время процедуры декодирования: с матрицей проверки на четность (parity-check matrix).

Матрица проверки на четность имеет (N-K) строк и N столбцов, где N соответствует требуемой длине кодового слова, а K, повторим, соответствует длине сообщения:

\underset{(N-K)\times N} {\mathbf{H}} = \left[ \underset{(N-K)\times K} {\mathbf{P}^T} \qquad  \underset{(N-K)\times (N-K)} {\mathbf{I}}\right] \qquad(3)

Ее основную идею очень удобно объяснять с помощью графа Таннера:

То есть существует два вида узлов: так называемые, узлы переменных (variable nodes), количество которых соответствуют числу столбцов K, и узлы проверки (check nodes), соответствующие числу строк (N - K). Узлы связаны между собой, и связь определяется положением единиц в матрице \mathbf{H}. Картинка справа — это моя собственная мнемоничка моего же производства. Как мне кажется, это самый простой способ уловить суть структуры: если элемент матрицы равен 1, значит связь между узлами есть, если равен 0 — связи нет.

Для того, чтобы считать процедуру декодирования успешной, нужно, чтобы на всех проверочных узлах сформировались определенные значения — как правило, нули (см. декодирование на основе синдромов):

\mathbf{s} = \mathbf{H}\mathbf{x} = \mathbf{0} \qquad(4)

Собственно говоря, эта матрица и определяет последние две буквы в аббревиатуре LDPC (Parity-Check).

Азы LDPC кодов

Но всё выше описанное — это общие моменты для большинства блочных кодов. Чем же тогда LDPC отличаются от тех же кодов Хэмминга?

В общем-то, тем, что и определяет их как low-density: их матрицы проверки на четность должны быть разряженными (sparce), то есть нулей в них должно быть значительно больше, чем чего-либо другого:

«Low density parity check codes are codes specified by a parity check matrix containing mostly zeros and only small number of ones.» [1]

Да, вот так просто.

Например, у того же Галлагера данная матрица была такой:

(3,4)-регулярная матрица проверки на четность длинною 12. Пояснение: кодовое слово, которое будет закодировано с помощью такого кода, будет иметь длину 12 бит; в каждом столбце 3 единицы, а в каждой строке 4, отсюда обозначение (3,4); количество единиц в строках и столбцах — это константы (в нашем случае 3 и 4), а значит код — регулярный.

У Маккея и Нила матрица проверки на четность была такой:

(3,4)-регулярная матрица проверки на четность длинною 12.

О регулярности и нерегулярности.

В стандарте DVB-S2 приняты уже нерегулярные (irregular) матрицы проверки на четность. См.:

Eroz M., Sun F. W., Lee L. N. DVB‐S2 low density parity check codes with near Shannon limit performance //International Journal of Satellite Communications and Networking. – 2004. – Т. 22. – №. 3. – С. 269-279.

Связано это с лучшей помехоустойчивостью нерегулярных схем.

Однако, ничего не замечаете? Правильно: эти матрицы не попадают под стандартную форму из формулы (3), ведь для LDPC кодов мы стремимся сделать проверочные матрицы разреженными. А если матрицы проверки не попадают под стандартную форму, значит не совсем понятно, как для них формировать порождающие матрицы.

Ответ, конечно, есть (и не один). Допустим, такой: изначальную матрицу \mathbf{H} приводят к стандартной форме через метод Гаусса (Gaussian elimination), из стандартной формы получают порождающую матрицу, а ее используют для кодирования.

Приведем пример из данного учебного материала:

Johnson, S. J. (2006). Introducing low-density parity-check codes. University of Newcastle, Australia, V1.

Была такая матрица \mathbf{H}:

import numpy as np

H = np.array([[1, 1, 0, 1, 1, 0, 0, 1, 0, 0],\
              [0, 1, 1, 0, 1, 1, 1, 0 ,0 ,0],\
              [0, 0, 0, 1, 0, 0, 0, 1, 1, 1],\
              [1, 1, 0, 0, 0, 1, 1, 0, 1, 0],\
              [0, 0, 1, 0, 0, 1, 0, 1, 0, 1]])

От нее, путем перемещений и преобразований строк по модулю 2, а также перемещений столбцов, перешли к матрице \mathbf{H}_{std}:

Hstd = np.array([[0, 1, 1, 1, 0, 1, 0, 0, 0, 0],\
                 [1, 0, 1, 0, 0, 0, 1, 0 ,0 ,0],\
                 [1, 0, 1, 0, 1, 0, 0, 1, 0, 0],\
                 [0, 0, 1, 1, 1, 0, 0, 0, 1, 0],\
                 [1, 1, 0, 0, 1, 0, 0, 0, 0, 1]])

Преобразования со строками с точки зрения линейной алгебры не влияют на кодовое слово, а вот перемещения столбцов нужно запомнить:

idx = [5, 6, 7, 8, 9, 0, 1, 2, 3, 4]

Формируем порождающую матрицу:

M = np.shape(H)[0] # N-K
N = np.shape(H)[1] 
K = N - M

G = np.concatenate([np.eye(K), ((-1)*Hstd[:, :K].T %2)], axis=1)
print("Generator matrix:\n"+str(G))

>>> Generator matrix:
[[1. 0. 0. 0. 0. 0. 1. 1. 0. 1.]
 [0. 1. 0. 0. 0. 1. 0. 0. 0. 1.]
 [0. 0. 1. 0. 0. 1. 1. 1. 1. 0.]
 [0. 0. 0. 1. 0. 1. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1. 0. 0. 1. 1. 1.]]

Создаем кодовое слово:

c = np.array([1, 0, 1, 0, 1]) @ G %2
print(str(c))

>>> array([1., 0., 1., 0., 1., 1., 0., 1., 0., 0.])

И проверяем синдром (то есть закодировали мы слово матрицей, произведенной от \mathbf{H}_{std}, а в процессе декодирования будем использовать разреженную матрицу \mathbf{H}):

c[idx] @ H.T %2

>>> array([0, 0, 0, 0, 0])

Магия линейной алгебры сработала!

Завершая раздел, нужно сказать, что такой метод кодирования самый простой для понимания, однако весьма сложный для вычисления в случае больших матриц — порождающая матрица, как правило, перестает быть разряженной. Конечно, на все это есть свои решения, однако, это уже совсем другая история…

Декодирование LDPC кодов

По LDPC кодам есть неплохой подбор материалов на Medium:

  • LDPC — low density parity check code (by @EventHelix — 5G | LTE | Networking)

Однако, лично мне объяснение одного из центральных и самых, наверное, популярных алгоритмов декодирования — алгоритма Belief propagation (aka SPASum-product algorithm) показалось, мягко говоря, слишком формальным (там просто прикреплена научная статья). Душа просит картинок и примеров!

За основу возьмем уже знакомый нам учебный материал:

Johnson, S. J. (2006). Introducing low-density parity-check codes. University of Newcastle, Australia, V1.

Итак, во-первых, предположим, что у нас есть некая система связи:

Пояснение

Система связи состоит из:

  • источника сообщения (source),
  • передатчика:
  • беспроводного канала связи,
  • приемника:
  • и получателя сообщения (destination).

Передатчик состоит из :

  • помехоустойчивого кодера (channel encoder),
  • цифрового модулятора (digital modulator) и
  • радиочасти (RF — radio frequency).

Приемник состоит из:

  • радиочасти,
  • цифрового демодулятора (digital demodulator) и
  • помехоустойчивого декодера (channel decoder).

Договоримся, что под цифровыми модемами будем понимать в первую очередь самые популярные их разновидности: PSK и QAM.

Чем интересны для нас данные типы модуляции? Во-первых, тем, что именно они входят в стандарты современных беспроводных систем (LTE, Wi-Fi, DVB и т.д. ).

А, во-вторых, тем, что они умеют представлять зашумленные значения, полученные из канала связи, в форме, так называемых, мягких значений демодуляции (soft decisions). Или, если выражаться более наукообразно, в форме логарифмированных коэффициентов правдоподобия (LLRlog likelihood ratios):

r = \ln \left( \frac{p(x=0)}{p(x=1)}\right)  = \ln \left(\frac{1 - p}{p} \right) \qquad (5)

где p обозначает вероятность, а x обозначает некоторое событие.

Мне чаще попадался случай, когда в числителе оставляют вероятность того, что бит изначально был нулем, а в знаменателе — что был единицей. Соответственно, если значение LLR на выходе демодулятора отрицательное, мы можем предположить, что скорее всего, бит был нулевым, а если положительное — единицей (см. NRZ). Собственно говоря, особой разницы в положении вероятностей нет. Главное, чтобы ваши приемник и передатчик были одинаково осведомлены о выбранной вами схеме наложения (маппинга). Мне кажется, популярность такого «нелогичного» NRZ (0 -> +1, 1 -> -1) в первую очередь продиктована распространенностью MatLab в кругах телекоммуникационщиков.

Несложно догадаться, что схема, состоящая только из источника сообщений и модема, весьма чувствительна к сильным шумам, а значит и к ошибкам демодуляции. Благо, что мы включили в нашу схему помехоустойчивый (канальный) кодек. Декодер нам эту ошибку как раз и исправит. А точнее тот алгоритм, который в этот самый декодер зашит.

Итак, Belief propagation.

  • Почему belief?

Потому что алгоритм работает с вероятностями. А точнее, с теми натуральными логарифмами от отношений вероятностей, которые мы указали в формуле (5).

  • Почему propagation?

Потому что эти вероятности будут итеративно «пересылаться» от узлов переменных к узлам проверки (сообщение V2CVariable-to-Check) и наоборот (сообщение C2VCheck-to-Variable).

  • Почему SPA?

Под пересылкой сообщений между узлами проверки и переменных понимается то, что LLR будут складываться и перемножаться по определенным формулам.

На этапе инициализации алгоритма LLR соответствуют априорным вероятностям. SPA является одним из алгоритмов максимальной апостериорной вероятности (MAP — maximum a posteriori probability), а значит он стремится максимизировать апостериорную вероятность, полученную после итеративной пересылки между узлами проверок и переменных.

Предлагаю рассмотреть пошагово.

Предупреждение:
Ниже будет представлено некоторое количество математических формул, и иногда они будут довольно непростыми для визуального восприятия. Поэтому если вы не настроены в данный момент на штудирование, предлагаю перейти сразу к пункту «Пример декодирования через SPA на Python (numpy)». Вернетесь к теории, когда будет время и настроение или когда захочется посмотреть, что лежит в основе скриптов (наверное).

1. Инициализация

Итак, для начала рассмотрим априорные вероятности.

Начальной точкой для нашего алгоритма является матрица значений LLR, повторяющая структуру матрицы \mathbf{H}. Подберем аналитическое описание:

\underset{M\times N} {\mathbf{M}} = \left(\underset{N\times 1} {\mathbf{r}} \cdot \underset{1\times M} {\mathbf{1}} \right)^T  \odot \underset{M\times N} {\mathbf{H}} \qquad (6)

где \mathbf{1} является массивом единиц, а \odot обозначает произведение Адамара (поэлементное умножение). На практике без единичной матрицы можно будет обойтись: заменим скобку на итерационное умножением Адамара вектора LLR со столбцами матрицы контроля четности (нужен будет дополнительный цикл). Если матрицы будут достаточно большими, такой подход может быть более эффективным с точки зрения памяти.

2. Сообщение V2C

Затем следует, так называемый, горизонтальный шаг: алгоритм требует обработки сообщения (V2C) в области вероятности. Для перехода от LLR к вероятностям воспользуемся отношением между гиперболическим тангенсом и натуральным логарифмом [4, с.32 ]:

tanh\left(\frac{1}{2}\ln\left( \frac{1 - p}{p} \right)\right) = 1 - 2p \qquad(7)

Собственно говоря, процедура передачи V2C сообщения — это перемножение ненулевых вероятностей в каждой строке:

где j — это номер определенной строки, i — это номер определенного столбца, B_{j} — это множество ненулевых значений в j-ой строке, а выражение i'\neq i означает, что мы исключаем i-ый узел переменных (variable node) из рассмотрения.

  • Из готового под рукой был только пример для стандартной формы. Сути операции это не меняет, и поэтому, я думаю, в таком варианте нет ничего страшного.

Пояснение формулы

То есть на данном этапе нам нужно:

Пункт с исключением узла из рассмотрения можно провести двумя способами: 1) выяснять нужное подмножество до перемножения вероятностей или удалять значение из результата после подсчетов. Я, простоты ради, буду пользоваться вторым методом.

Я думаю, кто-то из вас, возможно, слышал названия и других алгоритмов декодирования LDPC кодов. Например, Min-sum [5], Log-SPA [6] или еще какие-нибудь [7]. Такие алгоритмы еще иногда называются субоптимальными. В чем их отличие? Собственно, в данном пункте: данные алгоритмы стремятся снизить сложность декодирования и для этого используют иные формулы для вычисления горизонтального шага. Как правило, здесь начинается подсчет рисков: каким количеством помехоустойчивости мы готовы пожертвовать ради повышения скорости декодирования.

3. Проверка критерия остановки декодирования

Итак, мы подходим к концу первой итерации, а значит пора обновить наши априорные вероятности — сделать их апостериорными:

l_i = r_i + \sum_{j\epsilon A_i}E_{j,i} \qquad(9)

где A_i — это множество элементов, отвечающих ненулевым элементам матрицы проверки на четность в i-ом столбце.

Наложим их на биты через обратный NRZ:

z_i = 
\begin{cases}
0 &\text{if $l_i \geq 0$}\\
1 &\text{if $l_i < 0$}
\end{cases} \qquad(10)

И вычислим синдром по формуле (4). Если вектор нулевой — останавливаем декодирование. Если нет, то переходим к следующему шагу.

4. Сообщение C2V

На этом этапе нужно пересчитать матрицу \mathbf{M}:


И далее перейти к вычислению матрицы \mathbf{E}. И так до тех пор, пока не выполнится пункт 3 (или не кончится количество доступных итераций).

Пример декодирования через SPA на Python (numpy)

А теперь давайте перейдем к вещам более интересным — к примерам и скриптам!

Возьмем все тот же пример из [4, с.33 ]:

  • было кодовое слово вида: a = [0 0 1 0 1 1]
  • на выходе демодулятора получили: r = [−1.3863,1.3863,−1.3863,1.3863,−1.3863,−1.3863]
  • видим ошибку в первом бите

Начинаем декодировать (должна понадобиться одна итерация).

Исходники для алгоритма.

import numpy as np

class SPA:
    def __init__(self, H, Imax=1000, trace_on=True):
        self.H = H
        self.Imax = Imax
        self.trace_on = trace_on
        self.H_0 = np.shape(H)[0]
        self.H_1 = np.shape(H)[1]
        self.H_mirr = (self.H + np.ones(np.shape(self.H))) %2

    def __nrz(self, l):
        for idx, l_j in enumerate(l):
            if l_j >= 0:
                l[idx] = 0
            else:
                l[idx] = 1
        return l

    def __calc_E(self, E, M):
        M = np.tanh(M / 2) + self.H_mirr
        for j in range(self.H_0):
            for i in range(self.H_1):
                if self.H[j,i] != 0:
                    E[j,i] = np.log(( 1 + np.prod(M[j,:]) \
                                     / M[j,i]) / ( 1 - np.prod(M[j,:]) / M[j,i]) )
        return E

    def __calc_M(self, M, E, r):
        for j in range(self.H_0):
            for i in range(self.H_1):
                if self.H[j,i] != 0:
                    M[j,i] = np.sum(E[:, i]) - E[j,i] + r[i]
        M = M*H 
        return M

    def decode(self, r):
        stop = False
        I = 0
        M = np.zeros(np.shape(H))
        E = np.zeros(np.shape(H))
        l = np.zeros(np.shape(r))
        print('H:\n'+str(H))
        while stop == False and I != self.Imax:
            if I == 0:
                for j in range(np.shape(H)[0]):
                    M[j, :] = r*H[j, :]
            if self.trace_on == True:
                print('M:\n'+str(M))

            E = self.__calc_E(E, M)
            if self.trace_on == True:    
                print('E:\n'+str(E))

            l = r + np.sum(E, axis=0)
            if self.trace_on == True:
                print('l:\n'+str(l))

            l = self.__nrz(l)
            if self.trace_on == True:
                print('decoded:\n'+str(l))

            s = np.dot(H, l) %2
            if np.prod(s == np.zeros(np.size(s))) == 1:
                stop = True
            else:
                I = I + 1
                M = self.__calc_M(M, E, r)
        return l

l = SPA(H).decode(r)
print('Decoded message:\n'+str(l))

>>> H:
[[1 1 0 1 0 0]
 [0 1 1 0 1 0]
 [1 0 0 0 1 1]
 [0 0 1 1 0 1]]
M:
[[-1.3863  1.3863 -0.      1.3863 -0.     -0.    ]
 [-0.      1.3863 -1.3863  0.     -1.3863 -0.    ]
 [-1.3863  0.     -0.      0.     -1.3863 -1.3863]
 [-0.      0.     -1.3863  1.3863 -0.     -1.3863]]
E:
[[ 0.75377678 -0.75377678  0.         -0.75377678  0.          0.        ]
 [ 0.          0.75377678 -0.75377678  0.         -0.75377678  0.        ]
 [ 0.75377678  0.          0.          0.          0.75377678  0.75377678]
 [ 0.          0.         -0.75377678  0.75377678  0.         -0.75377678]]
l:
[ 0.12125356  1.3863     -2.89385356  1.3863     -1.3863     -1.3863    ]

Decoded message:
[0. 0. 1. 0. 1. 1.]

Сошлось.

Попробуем другой пример [4, с.36 ]:

  • матрица проверки на четность та же;
  • кодовое слово: a = [0 0 1 0 1 1];
  • приняли: y = [−0.5, 2.5, −4.0, 5.0, −3.5, 2.5].

Исправить нужно первый и последний биты.

r = np.array([-.5, 2.5, -4., 5., -3.5, 2.5])

l = SPA(H, trace_on=False).decode(r)
print('Decoded message:\n'+str(l))

>>> H:
[[1 1 0 1 0 0]
 [0 1 1 0 1 0]
 [1 0 0 0 1 1]
 [0 0 1 1 0 1]]
Decoded message:
[0. 0. 1. 0. 1. 1.]

Well done!

Готовые решения для моделирования

Ну, что же, теперь мы знаем азы блочного кодирования, в целом, и LDPC кодов, в частности, и даже попробовали сделать что-то, так сказать, своими руками. Можно считать, что стадия перехода от обезьяны к человеку пройдена — теорию усвоили (или хотя бы запасли на будущее).

Давайте использовать готовые решения.

Наверное, первое, что придет вам на ум, — это Communication Toolbox от MathWorks (MatLab). Решение, пожалуй, действительно хорошее, но мне оно не нравится по нескольким причинам:

  • нужно держать целый MatLab под ограниченный круг задач (хотя если MatLab — это ваш хлеб насущный, и вы пользуетесь им постоянно — согласен, проблемы нет);
  • реализация из коробки для матриц проверок на четность создана только под DVB-S2 (поправьте, если я отстал от жизни);
  • MatLab — это закрытый, платный проект (да, торренты, но я все равно за open-source).

Поэтому я отправился в путешествие по проектам на GitHub и нашел весьма интересный инструментарий: проект aff3ct, написанный на C++.

Мысли вслух

Интересно, почему еще никто не создал проект LDPC++ ?..

Прочтем, как проект позиционируют его разработчики:

Симулятор нацелен на высокоскоростное моделирование и широко использует параллельные методы, такие как SIMD, многопоточные и многоузловые модели программирования. Ниже приведен список функций, которые мотивировали создание симулятора:

  • воспроизведение самых современных характеристик декодирования,
  • исследование различных конфигураций помехоустойчивых кодов (нахождение новых компромиссов),
  • аппаратная реализация прототипа (приемники с фиксированной точкой, аппаратные средства в цикле),
  • повторное использование проверенных и протестированных модулей (и возможность добавлять свои),
  • альтернатива MATLAB (если вы стремитесь сократить время моделирования).

Работает ПО не только для LDPC кодов, но и для других кодеков (например, можно рассмотреть Turbo-коды и полярные коды).

У проекта есть хорошая документация в формате PDF, в формате WEB-страниц, а также онлайн-версия с визуализацией уже полученных результатов (BER/FER Comparator).

Выберем что-нибудь для примера:


Лучше открыть в новой вкладке для полноты эффекта.

Красота!

Можно запустить любой эксперимент и под свой вкус. Для этого нужно будет по инструкции (см. Instalation) установить ПО и запустить его из командной строки с нужными параметрами.

Уточнение по сборке

Устанавливать нужно путем сборки из исходников. Поэтому не забывайте про суперпользователей и места нахождения make-файлов.

Например, я запустил на досуге такую модель к командной строке Ubuntu 18.04:

aff3ct -C "LDPC" -K 32400 -N 64800 --enc-type LDPC_DVBS2 --dec-implem SPA --mdm-type QAM --mdm-bps 8 --chn-type RAYLEIGH -m 0.0 -M 15.0 -s 1.0

То есть:

  • -C «LDPC» -K 32400 -N 64800: LDPC-код с кодой скростью 1/2 ( = 32400 / 64800 )
  • —enc-type LDPC_DVBS2: матрица проверки из стандарта DVB-S2
  • —dec-implem SPA: алгоритм декодирования — SPA
  • —mdm-type QAM —mdm-bps 8: 256-QAM (256 = 2^8)
  • —chn-type RAYLEIGH: Рэлеевский канал связи (см. «Почти самый простой MIMO канал с замираниями (модель Кронекера прилагается)»)
  • -m 0.0 -M 15.0 -s 1.0: Eb/No от 0 до 15 дБ с шагом в 1 дБ

Лог (шапка) эксперимента

# ----------------------------------------------------
# ---- A FAST FORWARD ERROR CORRECTION TOOLBOX >> ----
# ----------------------------------------------------
# Parameters:
# * Simulation ------------------------------------
#    ** Type                      = BFER
#    ** Type of bits              = int32
#    ** Type of reals             = float32
#    ** Date (UTC)                = 2020-02-19 18:43:51
#    ** Git version               = v2.3.5
#    ** Code type (C)             = LDPC
#    ** Noise range               = 0 -> 15 dB
#    ** Noise type (E)            = EBN0
#    ** Seed                      = 0
#    ** Statistics                = off
#    ** Debug mode                = off
#    ** Multi-threading (t)       = 2 thread(s)
#    ** Coset approach (c)        = no
#    ** Coded monitoring          = no
#    ** Bad frames tracking       = off
#    ** Bad frames replay         = off
#    ** Bit rate                  = 0.5 (1/2)
#    ** Inter frame level         = 1
# * Source ----------------------------------------
#    ** Type                      = RAND
#    ** Implementation            = STD
#    ** Info. bits (K_info)       = 32400
# * Codec -----------------------------------------
#    ** Type                      = LDPC
#    ** Info. bits (K)            = 32400
#    ** Codeword size (N_cw)      = 64800
#    ** Frame size (N)            = 64800
#    ** Code rate                 = 0.5 (1/2)
# * Encoder ---------------------------------------
#    ** Type                      = LDPC_DVBS2
#    ** Systematic                = yes
# * Decoder ---------------------------------------
#    ** Type (D)                  = BP_FLOODING
#    ** Implementation            = SPA
#    ** Systematic                = yes
#    ** Num. of iterations (i)    = 10
#    ** Stop criterion (syndrome) = on
#    ** Stop criterion depth      = 1
# * Modem -----------------------------------------
#    ** Type                      = QAM
#    ** Implementation            = STD
#    ** Bits per symbol           = 8
#    ** Sigma square              = on
#    ** Max type                  = MAX
# * Channel ---------------------------------------
#    ** Type                      = RAYLEIGH
#    ** Implementation            = STD
#    ** Block fading policy       = NO
#    ** Complex                   = on
#    ** Add users                 = off
# * Monitor ---------------------------------------
#    ** Lazy reduction            = off
#    ** Frame error count (e)     = 100
#    ** Compute mutual info       = no
# * Terminal --------------------------------------
#    ** Show Sigma                = off
#    ** Enabled                   = yes
#    ** Frequency (ms)            = 500
# 

В итоге сформировалась такая таблица:


# The simulation is running...
# ---------------------||------------------------------------------------------||---------------------
#  Signal Noise Ratio  ||   Bit Error Rate (BER) and Frame Error Rate (FER)    ||  Global throughput  
#         (SNR)        ||                                                      ||  and elapsed time   
# ---------------------||------------------------------------------------------||---------------------
# ----------|----------||----------|----------|----------|----------|----------||----------|----------
#     Es/N0 |    Eb/N0 ||      FRA |       BE |       FE |      BER |      FER ||  SIM_THR |    ET/RT 
#      (dB) |     (dB) ||          |          |          |          |          ||   (Mb/s) | (hhmmss) 
# ----------|----------||----------|----------|----------|----------|----------||----------|----------
       6.02 |     0.00 ||      101 |  1095697 |      101 | 3.35e-01 | 1.00e+00 ||    0.005 | 00h11'43   
       7.02 |     1.00 ||      102 |  1054711 |      102 | 3.19e-01 | 1.00e+00 ||    0.006 | 00h09'02   
       8.02 |     2.00 ||      102 |  1003146 |      102 | 3.04e-01 | 1.00e+00 ||    0.006 | 00h08'58   
       9.02 |     3.00 ||      101 |   936980 |      101 | 2.86e-01 | 1.00e+00 ||    0.006 | 00h09'38   
      10.02 |     4.00 ||      102 |   887637 |      102 | 2.69e-01 | 1.00e+00 ||    0.005 | 00h11'19   
      11.02 |     5.00 ||      101 |   817568 |      101 | 2.50e-01 | 1.00e+00 ||    0.006 | 00h09'25   
      12.02 |     6.00 ||      101 |   749147 |      101 | 2.29e-01 | 1.00e+00 ||    0.006 | 00h09'25   
      13.02 |     7.00 ||      102 |   684123 |      102 | 2.07e-01 | 1.00e+00 ||    0.006 | 00h09'19   
      14.02 |     8.00 ||      102 |   601807 |      102 | 1.82e-01 | 1.00e+00 ||    0.006 | 00h09'19   
      15.02 |     9.00 ||      102 |   507251 |      102 | 1.53e-01 | 1.00e+00 ||    0.006 | 00h09'22   
      16.02 |    10.00 ||      101 |   378508 |      101 | 1.16e-01 | 1.00e+00 ||    0.006 | 00h09'16   
      17.02 |    11.00 ||      102 |   170607 |      102 | 5.16e-02 | 1.00e+00 ||    0.006 | 00h09'19   
      18.02 |    12.00 ||      101 |    14895 |      101 | 4.55e-03 | 1.00e+00 ||    0.006 | 00h09'22   
      19.02 |    13.00 ||      107 |      467 |      102 | 1.35e-04 | 9.53e-01 ||    0.006 | 00h09'49   
      20.02 |    14.00 ||      812 |      123 |      101 | 4.68e-06 | 1.24e-01 ||    0.006 | 01h14'21   
      21.02 |    15.00 ||    14283 |      110 |      100 | 2.38e-07 | 7.00e-03 ||    0.006 | 21h13'14   
# End of the simulation.

Уточнение

Как вы могли заметить, на последней строке я потерял неимоверное количество времени. Дабы не гнаться за идеалом декодирования со сверхмалыми значениями ошибок (и не повторять моих промахов), выставите нужный вам таймер с помощью флага --sim-stop-time (не забудьте --sim-crit-nostop, чтобы моделирование не останавливалось, а переходило к следующей точке отношения сигнал-шум).

Даже такое аскетичное представление данных — как мне кажется, это уже классная возможность.

Можно, конечно, пойти дальше написать какие-нибудь обертки для отрисовки графиков.

Про обертки от создателей проекта

У создателей проекта есть и собственные решения по визуализации. Например, PyBER. Суть «тулзы» заключается в том, что с помощью GUI вы можете выбирать сформированные aff3ct txt-файлы, PyBER вам их распарсит и отрисует (полученное можно даже экспортировать, вроде). Лично мне не понравилось представление: графики представлены через plot, а не через более логичный semilogy. Поэтому оставляю опыт использования PyBER на ваше усмотрение.

Допустим, результаты моделирования можно сохранить в txt-файл, а значения отношений битовых ошибок (BER — bit error ratio) можно вытащить уже из него c помощью простой манипуляции с awk:

cat results.txt | awk '{if ($1 !="#") print $11}'

Все это передать, допустим, в Python и нарисовать графики под свой вкус.

Для кодовых скоростей 1/2 и 3/4 (AWGN канал) у меня получились такая картинка:

Без изысков, но в качестве первого шага неплохо, как мне кажется.

Послесловие

Не спорю, сколько я ни пытался объять необъятное, прошлись мы все же только по вершкам. Однако, я все же надеюсь, что данная статья хоть сколько-то снизит порог вхождения человеку, желающему погрузиться в тему LDPC-кодов (наверное).

Конструктивная критика только приветствуется. И спасибо за ваше внимание!

Литература

  1. R.G. Gallager Low-Density Parity-Check Codes, IRE Transactions on Information Theory, 1962

  2. D.J.C. MacKay Good Error-Correcting Codes Based on Very Sparse Matrices, IEEE Transactions on Information Theory, VOL.45, NO 2., March 1999

  3. «3GPP RAN1 meeting #87 final report». 3GPP. Retrieved 31 August 2017.

    • Полярные коды были выбраны для CP (Control Plane) FEC. LDPC — для UP (User Plane) FEC. Напомню, что в сетях 2G использовались сверточные коды, а в сетях 3G и 4G (LTE/LTE-A) — Турбо сверточные коды.

  4. Johnson, S. J. (2006). Introducing low-density parity-check codes. University of Newcastle, Australia, V1

  5. Declercq D., Fossorier M. Decoding algorithms for nonbinary LDPC codes over GF(q) //IEEE transactions on communications. – 2007. – Т. 55. – №. 4. – С. 633-643.

  6. Wymeersch H., Steendam H., Moeneclaey M. Log-domain decoding of LDPC codes over GF (q) //2004 IEEE International Conference on Communications (IEEE Cat. No. 04CH37577). – IEEE, 2004. – Т. 2. – С. 772-776.

  7. Chen J. et al. Reduced-complexity decoding of LDPC codes //IEEE transactions on communications. – 2005. – Т. 53. – №. 8. – С. 1288-1299.

Приложения

ПРИЛОЖЕНИЕ 1. Некоторые рассуждения по поводу перемножения вероятностей в SPA

Хотите немного линейной алгебры?

Давайте порассуждаем о том, как можно найти подмножества ненулевых вероятностей?

  1. Его можно выявить заранее по структуре матрицы H.
  2. Однако, можно немного схитрить и заменить все нули на единицы, перемножить и убрать излишние единицы поэлементным перемножением с матрицей H.

Для второго способа нужна будет, правда, заранее подготовленная матрица, которая будет повторять структуру матрицы H с точностью до наоборот: вместо единиц в ней будут нули, а вместо нулей единицы. Назовем ее «зеркалом» матрицы H:

где \oplus — это сложение по модулю (в нашем случае modulo 2).

Соответственно, процедура замены нулей на единицы в матрице \mathbf{M} — это сложение двух матриц:

После перемножения нужно будет вернуть структуру к исходному виду:

Выглядит забавно, не правда ли? Такой подход очень удобен при небольших матрицах проверки на четность: можно использовать встроенные функции для перемножения элементов в векторах. Однако, я думаю, для больших матриц такой подход может быть неподходящим из-за дополнительного расхода памяти и побочных вычислений.

ПРИЛОЖЕНИЕ 2. Рассуждения о декодировании недвоичных LDPC через SPA

Вопрос о сложности и простоте декодирования, может быть, не так хорошо просматривается на двоичных кодах, однако на кодах недвоичных встает, так сказать, во весь рост. Пример для GF(4).

Во-первых, вместо вектора LLR, нам придется работать с матрицей LLR (нужно ведь проверять вероятность уже не только двух событий):

Соответственно, пересылаемые сообщения — это уже тензоры, которые придется разбивать на слои и обрабатывать в цикле:

И уже потом выбирать наиболее вероятное значение:

Сложность будет расти пропорционально увеличению q в выражении GF(q). Волей-неволей задумаешься о более быстрых алгоритмах…

Домашній інтернет без свіstrongmanrus.ruстіший спосіб

Data processing agreement: GDPR, LGPD, іноземні клієнти

Інтернет без світла 2.0 – все що Ви хотіли знати, Дууууже детальне відео

Как подключить роутер к аккумулятору и повербанку при отключении света. Самое понятное видео.

Теперь у каждой домохозяйки есть идеальное место для изучения новых навыков и техник. Наш сайт предлагает видеоуроки, которые помогут разнообразить семейные рецепты любимых блюд, создать красивый сад и даже крупные швейные проекты! Например тематика этой страницы: включить поддержку Ldpc кодирования, здесь вы увидите самую полную подборку видео по данной теме.
Использование наших видеоуроков делает освоение новых навыков проще, чем когда-либо прежде. Для того чтобы разобраться в теме: включить поддержку Ldpc кодирования от вас требуется только внимательность и желание научиться чему-то новому!

Смотрите еще:

  1. Сон банки с соленьями
  2. Какие есть материалы для кровли крыши
  3. После автоклава крышки вздутые что делать
  4. Балкон для кошек на окно своими руками
  5. Apache редирект на другой сервер

VHT = Very High Throughput = 802.11ac
HT = High Throughput = 802.11n

The first three sections are about optional features of the IEEE 802.11n and 802.11ac standards. They should all help and should not hurt, and you want them enabled unless you suspect that your client or AP has a buggy implementation of that feature that is causing problems.

LDPC is Low-Density Parity Check. It’s a standard part of 802.11n and 802.11ac. It allows your 802.11 transmissions to be more efficient. You want it on for both VHT and HT.

STBC is Space-Time Block Coding. It’s a standard part of 802.11n and 802.11ac. It allows your 802.11 transmissions to be more reliable and efficient. You want it on for both VHT and HT.

BeamCap/BEAM is almost certainly beamforming. Beamforming is a standard part of 802.11n and 802.11ac. It allows you to get greater better signal strength, and thus better throughput, at range. You want it on for both VHT and HT.

«Adaptivity» seems to relate to ETSI’s (European Technology Standards Institute’s) adaptive frequency hopping requirements which are mostly for Bluetooth. I note that ALFA says your adapter contains some kind of anti-Bluetooth-interference device, which is probably what this is all about. It probably has a stripped-down Bluetooth radio that simply tells other Bluetooth radios to stop using the frequencies that its Wi-Fi radio is using.

The Adaptivity settings you’re seeing don’t seem to have any direct correlation to parts of the ETSI adaptivity test, so it’s hard for me to say what it’s all about. Maybe someone with deep knowledge of how Bluetooth AFH works might know what these settings mean. Then again, maybe these settings are very specific to Realtek’s or ALFA’s implementation, so perhaps no one outside of Realtek or ALFA would know what they mean, since there doesn’t seem to be any public documentation about them.

This example shows how to implement a WLAN LDPC encoder using Simulink® blocks that are optimized for HDL code generation. This example supports the IEEE® 802.11n™, 802.11ac™, 802.11ax™, and 802.11ad™ standards. The WLAN LDPC Encoder block in this example works in conjunction with the WLAN LDPC Decoder block. To verify the behavior of the WLAN LDPC Encoder block, compare the output of the block with the output of the ldpcEncode function.

Introduction

The IEEE 802.11n (also known as Wi-Fi™ 4) [ 1 ], IEEE 802.11ac (also known as Wi-Fi 5) [ 1 ] and IEEE 802.11ax (also known as Wi-Fi 6) [ 2 ] standards use convolutional codes for forward error correction (FEC). Due to the advantages over convolutional codes, the standards use low-density parity-check (LDPC) codes. These standards define quasi-cyclic (QC) LDPCs with codeword block lengths of 648, 1296, and 1944 and subblock sizes, also known as expansion factors, of 27, 54, and 81, respectively. For each codeword block length, the standard defines code rates of 1/2, 2/3, 3/4, and 5/6.

The IEEE 802.11ad [ 3 ] standard defines a QC LDPC with a codeword block length of 672 and a subblock size of 42. For each codeword block length, the standard defines code rates of 1/2, 2/3, 3/4, and 5/6.

The standards define the parity-check matrices (PCMs) for LDPCs with various combinations of code word block lengths and code rates.

Model Architecture

This figure shows the architecture block diagram of the WLAN LDPC Encoder block implementation.

Parity Check Matrix

PCM has the size $N-by-K$, where $N$ is output length and $K$ is input length. You can partition the PCM into two concatenated submatrices $H_1$ and $H_2$ such that ${H} = [{H_1}\,{H_2}]$, where ${H}_{1}$ an $(N-K)-by-(K)$ submatrix and ${H}_{2}$ an $(N-K)-by-(N-K)$ submatrix. Let ${c} = [{m}\,{p}]$ be a codeword block, with ${m}$ and ${p}$ representing the information and parity bit sequences, respectively. The encoding consists of these steps.

1. Calculate Alpha Bit Sequence

From the encoding property, ${H} . {c}^T = 0,$

$[H_1\,H_2][m\,p]^T = 0$,

$\alpha + {H_2}. {p}^T = 0,$

$\alpha = {H_1}. {m}^T$. This calculation of the alpha bit sequence is the same for the IEEE 802.11n/ac/ax and IEEE 802.11ad standards.

2 .Calculate Parity Bit Sequence

The parity bit sequence ${p}$ can be expressed as $[p(0)\,p(1)\,\ldots\,p(N-K-1)]$. The $p(0)$ term is subsequence of parity bits with the size of a subblock.

For the IEEE 802.11n/ac/ax LDPC base parity-check matrices, ${H}_{1}$ is a sparse matrix and ${H}_{2}^{-1}$ has a regular pattern, the array multiplications of $p^T = {H}_{2}^{-1} . \alpha$ have linear complexity, which makes it straightforward to compute the parity bit sequence.

For the IEEE 802.11ad LDPC base parity-check matrices, ${H}_{1}$ is a sparse matrix and ${H}_{2}^{-1}$ has an irregular pattern, which makes calculating the parity bit sequence calculation more complicated. Calculating the parity bit sequence consists of solving this equation: $\alpha + H_2[p(0)\,p(1)\,\ldots\,p(N-K-1)]^T = 0.$

So, two separate models were implemented for IEEE 802.11n/ac/ax and IEEE 802.11ad specified LDPC encoders.

IEEE 802.11n/ac/ax Standard LDPC Encoder

The WLAN LDPC Encoder subsystem accepts input data, a control signal, a block length index, and a code rate index. At the start of each frame, the subsystem samples the blockLenIdx and codeRateIdx. The inputController function controls the reading and writing of input data in the Input RAM subsystem and enables the encoding after writing the entire frame to RAM. The Calculate Alpha subsystem calculates the alpha bit sequence and stores its value in the Calculate Alpha/Alpha RAM subsystem. The Calculate Parity subsystem calculates the parity and stores them in the Calculate Parity/Parity RAM subsystem. The outputController function multiplexes and serializes the bits from the Input RAM and Calculate Parity subsystems.

modelName = 'wlan11achdlLDPCEncoder';
load_system(modelName);
open_system([modelName '/WLAN LDPC Encoder']);
set_param([modelName '/WLAN LDPC Encoder'],'Open','on');

Calculate Alpha Bit Sequence

The Calculate Alpha subsystem calculates $\alpha$ bit sequence. Using the parity-check matrix specified in the standard [ 1 ], the ShiftVal LUT and Column LUT blocks calculate and store the shift values for the Circular Shifter subsystem and the address for the Input RAM subsystem. The alphaController function controls the calculation of the alpha bit values by providing the necessary control signals to the Circular Shifter subsystem, ShiftVal LUT block, and Column LUT block. The Circular Shifter subsystem shifts the data circularly, XORs the shifted data with previous shifted data, and stores the data in the Alpha RAM subsystem. By XORing all the alpha values, the model calculates the first column of the parity bit sequence.

set_param([modelName '/WLAN LDPC Encoder'],'Open','off');
open_system([modelName '/WLAN LDPC Encoder/Calculate Alpha']);

Calculate Parity Bit Sequence

The Shiftby1 subsystem shifts the first column of parity bit sequence by one circle. The model then calculates the remaining parity bit subsequences using the shifted first column of parity bit sequence data and the alpha bit values from the Calculate Alpha subsystem. The parityController function controls the parity calculation as well as the reading and writing of parity data to the Parity RAM subsystem.

set_param([modelName '/WLAN LDPC Encoder/Calculate Alpha'],'Open','off');
open_system([modelName '/WLAN LDPC Encoder/Calculate Parity']);

IEEE 802.11ad Standard LDPC Encoder

The WLAN LDPC Encoder subsystem accepts input data, a control signal, and a code rate index. The subsystem samples the codeRateIdx input at the start of a frame. The architecture is same as the the IEEE 802.11n/ac/ax LDPC Encoder.

modelName = 'wlan11adhdlLDPCEncoder';
load_system(modelName);
open_system([modelName '/WLAN LDPC Encoder']);
set_param([modelName '/WLAN LDPC Encoder'],'Open','on');

Calculate Alpha Bit Sequence

The Calculate Alpha subsystem architecture is same as that of the IEEE 802.11n/ac/ax LDPC Encoder’s.

set_param([modelName '/WLAN LDPC Encoder'],'Open','off');
open_system([modelName '/WLAN LDPC Encoder/Calculate Alpha']);

Calculate Parity Bit Sequence

The model calculates the first column of the parity bit sequence by XORing the shifted alpha bit values from the Circular Shifter subsystem. Using the first column of parity bit sequence data and the alpha values from the Calculate Alpha subsystem, the parityController function calculates the remaining parity bit subsequences sequentially and stores them in the Parity RAM subsystem. The parityController function controls the parity calculation and writing of parity data to the Parity RAM subsystem. The parityReading function reads the parity data from Parity RAM subsystem and outputs parity bits serially.

set_param([modelName '/WLAN LDPC Encoder/Calculate Alpha'],'Open','off');
open_system([modelName '/WLAN LDPC Encoder/Calculate Parity']);

Set Up Input Variables

Choose a WLAN specific standard and input values for the block length and code rate according to your chosen standard. You can change the variable values in this section based on your requirements.

standard = 'IEEE 802.11 n/ac/ax';  % IEEE 802.11 n/ac/ax or IEEE 802.11 ad
codeRateIdx = [0; 1; 2; 3];        % Code rate index
blkLenIdx = [2; 1; 2; 0];          % Block length index when standard is
                                   % set to 'IEEE 802.11 n/ac/ax'
numFrames = 4;

Generate Input Data

Generate inputs for the ldpcEncode function with the specified block length and code rate variables. Create vectors of block length index and code rate index using the blockLenIdx and codeRateIdx variables, respectively. Convert the frames of input data to samples with a control bus signal that indicates the frame boundaries. Provide these vectors and the control bus as inputs to the WLAN LDPC Encoder subsystem.

The encFrameGap variable accommodates the latency of the WLAN LDPC Encoder subsystem for the specified block length and code rate.

msg = {numFrames};
refOut = cell(1,numFrames);

encSampleIn = [];
encStartIn = [];
encEndIn = [];
encValidIn = [];
encBlkLenIdxIn = [];
encCodeRateIdxIn = [];

close_system(modelName);

% Calculate input and output codeword length
for idx = 1:numFrames
    if strcmpi(standard,'IEEE 802.11 n/ac/ax')
        blockLenSet = [648,1296,1944,1944];
        rateSet = {'1/2','2/3','3/4','5/6'};

        blkLen = blockLenSet(blkLenIdx(idx)+1);
        codeRate = rateSet{codeRateIdx(idx)+1};
        modelName = 'wlan11achdlLDPCEncoder';
    else
        rateSet = {'1/2','5/8','3/4','13/16'};
        blkLen = 672;
        codeRate = rateSet{codeRateIdx(idx)+1};
        modelName = 'wlan11adhdlLDPCEncoder';
    end

    % Encoder configuration
    encConfig = wlanEncoderConfiguration(blkLen,codeRate);

    % Input bits generation
    msg{idx} = randi([0 1],encConfig.NumInformationBits,1,'int8');

    % LDPC encoding
    refOut{idx} = ldpcEncode(msg{idx}, encConfig);

    len = length(msg{idx});
    encFrameGap = 2000 + len;
    encIn =  msg{idx}';

    encSampleIn = [encSampleIn encIn zeros(size(encIn,1),encFrameGap)]; %#ok<*AGROW>
    encStartIn = logical([encStartIn 1 zeros(1,len-1) zeros(1,encFrameGap)]);
    encEndIn = logical([encEndIn zeros(1,len-1) 1 zeros(1,encFrameGap)]);
    encValidIn = logical([encValidIn ones(1,len) zeros(1,encFrameGap)]);
    encBlkLenIdxIn = ([encBlkLenIdxIn repmat(blkLenIdx(idx),1,len) zeros(1,encFrameGap)]);
    encCodeRateIdxIn = ([encCodeRateIdxIn repmat(codeRateIdx(idx),1,len) zeros(1,encFrameGap)]);
end

dataIn = timeseries(encSampleIn'>0);
startIn = timeseries(encStartIn);
endIn = timeseries(encEndIn);
validIn = timeseries(encValidIn);

if strcmpi(standard,'IEEE 802.11 n/ac/ax')
    blockLenIdx = timeseries(fi(encBlkLenIdxIn,0,2,0));
end
codeRateIdx = timeseries(fi(encCodeRateIdxIn,0,2,0));

simTime = length(encValidIn);

[columnLUT,shiftLUT] = columnShiftLUTWLAN(standard);

Run WLAN LDPC Encoder Model

The WLAN LDPC Encoder subsystem contains the implementation of the WLAN LDPC Encoder block. Run the model to import the input signal variables dataIn, startIn, endIn, validIn, blockLenIdx, codeRateIdx, and simTime to the block from the script. The model exports a stream of encoded output samples encOut and a control bus containing the startOut, endOut, and validOut signals to the MATLAB® workspace.

load_system(modelName);
open_system(modelName);
sim(modelName);

Compare Simulink Block Output with MATLAB Function Output

Convert the streaming data output of the WLAN LDPC Encoder subsystem to frames. Compare the frames with the output of the ldpcEncode function.

startIdx = find(squeeze(startOut));
endIdx = find(squeeze(endOut));
enc = squeeze(dataOut);

encHDL = {numFrames};
for i = 1:numFrames
    idx = startIdx(i):endIdx(i);
    encHDL{i} = enc(idx);
    HDLOutput = encHDL{i};
    error = sum(abs(double(refOut{i})-HDLOutput(:)));
   fprintf('Encoded frame %d: Output data differs by %d bits\n',i,error);
end
Encoded frame 1: Output data differs by 0 bits
Encoded frame 2: Output data differs by 0 bits
Encoded frame 3: Output data differs by 0 bits
Encoded frame 4: Output data differs by 0 bits

Latency

The latency of the WLAN LDPC Encoder block varies with the selected standard, block length, and code rate configurations. This figure shows the latency of the block when you set the blockLenIdx input port to 2 and the codeRateIdx input port to 0.

This table shows the latency of the WLAN LDPC Encoder block for different standards and configurations.

Generate HDL Code

To check and generate HDL code for this example, you must have an HDL Coder™ license. Use the makehdl and makehdltb commands to generate the HDL code and test bench for the WLAN LDPC Encoder subsystem.

The WLAN LDPC Encoder subsystem is synthesized on a Xilinx® Xilinx Zynq® UltraScale+ MPSoC ZCU102 evaluation board. This table shows the post place and route resource utilization results.

 F = table(...
     categorical({'IEEE 802.11 n/ac/ax';'IEEE 802.11 ad'}),...
     categorical({'2495';'2482'}),...
     categorical({'2153';'1793'}),...
     categorical({'0.5';'0.5'}),...
     categorical({'514.88';'516'}),...
     'VariableNames',{'Standard','Slice LUTs','Slice Registers','BRAM', ...
     'Max. Frequency (MHz)'});

disp(F);
         Standard          Slice LUTs    Slice Registers    BRAM    Max. Frequency (MHz)
    ___________________    __________    _______________    ____    ____________________

    IEEE 802.11 n/ac/ax       2495            2153          0.5            514.88       
    IEEE 802.11 ad            2482            1793          0.5            516          

References

  1. IEEE Std 802.11™-2020. IEEE Standard for Information Technology — Telecommunications and Information Exchange between Systems — Local and Metropolitan Area Networks — Specific Requirements — Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications.

  2. IEEE Std 802.11ax™-2021. IEEE Standard for Information Technology — Telecommunications and Information Exchange between Systems — Local and Metropolitan Area Networks — Specific Requirements — Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications — Amendment 1: Enhancements for High-Efficiency WLAN.

  3. IEEE Std 802.11ad™-2012. IEEE Standard for Information technology — Telecommunications and information exchange between systems—Local and Metropolitan Area Networks — Specific requirements — Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications. Amendment 3: Enhancements for Very High Throughput in the 60 GHz Band.

See Also

Blocks

  • WLAN LDPC
    Decoder

  • Включить wps на роутере дом ру
  • Вифи роутер с сим картой теле2
  • Влияет ли роутер на качество связи
  • Вифи роутер не горят лампочки
  • Включил роутер в новую сеть