Перейти к содержанию
    

Вопросы по итеративному декодированию

проверка sum(abs(rx_symb - tx_symb).^2)/Nbits и sum(abs(rx_symb1 - tx_symb1).^2)/Nbits показывает что мощность шума у вас там разная.

Точно. Нужно немного поправить, во первых я неправильно взвешивал шум, нужно так:

noise = randn(1, Nbits)+1j*randn(1, Nbits);
noise = noise * sqrt(Pn/2);

А во-вторых:

rx_symb = tx_symb + noise;
rx_symb1 = tx_symb1 + noise;

Даёт результат:

ber = 0.022872 ber1 = 0.023012

и

>> sum(abs(rx_symb - tx_symb).^2)/Nbits

ans =

    1.0017

>> sum(abs(rx_symb1 - tx_symb1).^2)/Nbits

ans =

    1.0017

В таком случае действительный сигнал tx_symb1 трактуется как комплексный с im=0.

 

Но вот другой интересный эффект заметил:

Формально, т.к. оба сигнала теперь считаются комплексными к ним должно применяться одно правило принятия решений:

hd_bits  = ((real(rx_symb) + imag(rx_symb)) >= 0);
hd_bits1 = ((real(rx_symb1) + 1*imag(rx_symb1)) >= 0);

Но тогда получается

ber = 0.023051 ber1 = 0.079219

А если второе созвездие предварительно развернуть:

rx_symb1 = rx_symb1 * exp(1i*pi/4);

то получается

ber = 0.02295 ber1 = 0.0228

Как же так?

 

Кажется нашел ответ на свой вопрос: правило

hd_bits  = ((real(rx_symb) + imag(rx_symb)) >= 0);

Даёт лучший результат при 100% восстановленной фазе, т.е. при когерентном приёме, а в остальных случаях получаются потери вплоть до 3дБ, что соответствует некогерентному приёму. Так ли это?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но вот другой интересный эффект заметил:

Угу, я тоже его заметил. Похоже весь сыр бор вокруг вокруг вот этого

if(strcmp(cplxMode,'complex'))
   y = (sqrt(imp*noisePower/2))*(func(row, col)+1i*func(row, col));
else
   y = (sqrt(imp*noisePower))*func(row, col);
end;

Правда не понятно как тогда быть обработкой "разных" BPSK. Так можно на 3дб ошибиться, а потом считать свой декодер супер-пупер крутым :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Даёт лучший результат при 100% восстановленной фазе, т.е. при когерентном приёме, а в остальных случаях получаются потери вплоть до 3дБ, что соответствует некогерентному приёму. Так ли это?

Это я вчера так коряво с одномерным созвездием пытался объяснить этот случай :rolleyes:

Да, теперь нужно знать точно фазу, поскольку используются две координаты.

 

Правда не понятно как тогда быть обработкой "разных" BPSK. Так можно на 3дб ошибиться, а потом считать свой декодер супер-пупер крутым :)

Использовать Simulink, о чем я написал выше :08: Кстати, не пробовали использовать вместо awgn объект comm Симулинковского АБГШ? По идее там должно быть всё хорошо.

Изменено пользователем Grizzzly

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, не пробовали использовать вместо awgn объект comm Симулинковского АБГШ?

Пока еще нет, на досуге попробую :)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Правда не понятно как тогда быть обработкой "разных" BPSK.

Для BPSK с произвольным поворотом на угол ang от оси Ox правило принятия решения будет:

a = cos(degtorad(ang));
b = sin(degtorad(ang));
hd_bits1 = ((a*real(rx_symb1) + b*imag(rx_symb1)) >= 0);

Это даёт BER порядка 0.023 для любых углов поворота при SNR=3 дБ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Провел тщательный эксперимент. :biggrin:

В MATLAB pskmod для BPSK возвращает комплексные значения вида (+/-1 + j0). Поэтому awgn работает корректно. Ничего добавлять не нужно к SNR.

В Simulink. Создал вместо стандартного BPSK-модулятора свой на блоках умножения на 2 и с вычитанием 1. На выходе вещественные числа. Если задаю в AWGN Eb/N0 = 3 дБ, получаю правильный BER = 0.023. Если SNR = 3 дБ, то неверный BER = 0.07.

Стандартный BPSK-модулятор в Simulink также формирует комплексные значения (+/-1 + j0). Тут всегда верно.

Соглашусь с serjj, лучше всегда прибавлять к сигналу 1j*1e-15, а потом брать вещественную часть. Либо уж стандартной функций pskmod пользоваться. Тогда точно никаких ошибок не будет.

Изменено пользователем Grizzzly

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем доброго!

 

Отложил немного турбокоды, ушел в другую сторону стандарта Wimax. Сделал в матлабе эталонную модель LDPC декодера, алгоритм декодирования Normalized Min-Sum и 2-D Normalized Min-Sum. В процессе снятия характеристик, обнаружил один, не очень понятный мне эффект. В приложении матлабовский код bertest а. В главном файле bertest.m есть параметр ERR_MODE = 0. Он может принимать значения 0/1.

 

Режимы 0/1 отличаются инверсией символов радиоканала и битовой инверсией результатов декодирования при измерении коэффициента ошибок.

.....
        if ERR_MODE == 1
            rx_symb = awgn(tx_symb, SNR, 10*log10(2));
        else 
            rx_symb = awgn(-1*tx_symb, SNR, 10*log10(2));
        end   
.....
        if ERR_MODE == 1
            err    = biterr(code(1:Nbits), decode(1:Nbits));         
        else 
            err    = biterr(code(1:Nbits), not(decode(1:Nbits)));         
        end

Так вот, качество работы декодера, в разных режимах, существенно отличается. В режиме 1 он работает намного хуже ber где то 10^-2, в режиме 0 ber нулевой.

Полдня не мог понять что же сделано неправильно. Перечитывая на Nый раз статью Optimized Min-Sum Decoding Algorithm for Low Density Parity Check Codes, взгляд упал на описание алгоритма (скрин в приложении). Они в этом алгоритме инвертируют входные метрики и считают инверсные жесткие решения. Пробежался по другой литературе и во многих статьях наблюдается этот эффект.

 

Проясните что это за эффект ? Логическое обоснование результатов, подсказывает мне что min-sum обладает чем то, вроде постоянного смещения в вычисляемых LLR, и начальная инверсия метрик является чем то вроде коррекции этого смещения. Но в турбокодах же такого нет, или просто я случайно угадал с инверсией?

 

Спасибо.

 

ЗЫ. Раз полез в LDPC коды, то название темы изменил на более корректное :)

wimax_ldpc.7z

post-3453-1427479087_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так вот, качество работы декодера, в разных режимах, существенно отличается. В режиме 1 он работает намного хуже ber где то 10^-2, в режиме 0 ber нулевой.

 

Для меня (не знаток LDPC и особенно того LDPC, что в ваймакс) вовсе не очевидно, что инвертированное кодовое слово тоже является кодовым словом. По логике вещей, если с - кодовое слово, то его инверсия - это:

с+ones(1, Nbits/rate).

 

Для того, чтобы это выполнялось, слово из всех единиц должно быть кодовым. Вот и встает вопрос - выполняется ли ones * H' = 0 для рассматриваемого кода. Закодировал твоим кодером все единицы и НЕ получил кодовое слово из всех единиц, т.е. код как минимум не систематический. Сгенери полную проверочную матрицу и проверь (сумма столбцов (??? может, строк, плохо соображаю) проверочной матрицы должна быть равна zeros).

Изменено пользователем andyp

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем доброго!

 

Отложил немного турбокоды, ушел в другую сторону стандарта Wimax. Сделал в матлабе эталонную модель LDPC декодера, алгоритм декодирования Normalized Min-Sum и 2-D Normalized Min-Sum. В процессе снятия характеристик, обнаружил один, не очень понятный мне эффект. В приложении матлабовский код bertest а. В главном файле bertest.m есть параметр ERR_MODE = 0. Он может принимать значения 0/1.

 

Режимы 0/1 отличаются инверсией символов радиоканала и битовой инверсией результатов декодирования при измерении коэффициента ошибок.

.....
        if ERR_MODE == 1
            rx_symb = awgn(tx_symb, SNR, 10*log10(2));
        else 
            rx_symb = awgn(-1*tx_symb, SNR, 10*log10(2));
        end   
.....
        if ERR_MODE == 1
            err    = biterr(code(1:Nbits), decode(1:Nbits));         
        else 
            err    = biterr(code(1:Nbits), not(decode(1:Nbits)));         
        end

Так вот, качество работы декодера, в разных режимах, существенно отличается. В режиме 1 он работает намного хуже ber где то 10^-2, в режиме 0 ber нулевой.

Полдня не мог понять что же сделано неправильно. Перечитывая на Nый раз статью Optimized Min-Sum Decoding Algorithm for Low Density Parity Check Codes, взгляд упал на описание алгоритма (скрин в приложении). Они в этом алгоритме инвертируют входные метрики и считают инверсные жесткие решения. Пробежался по другой литературе и во многих статьях наблюдается этот эффект.

 

Проясните что это за эффект ? Логическое обоснование результатов, подсказывает мне что min-sum обладает чем то, вроде постоянного смещения в вычисляемых LLR, и начальная инверсия метрик является чем то вроде коррекции этого смещения. Но в турбокодах же такого нет, или просто я случайно угадал с инверсией?

 

Спасибо.

 

ЗЫ. Раз полез в LDPC коды, то название темы изменил на более корректное :)

но инверсия может декодеру не помочь, а наоборот ухудшить ситуацию с декодированием - не будет декодироваться.

и наоборот.

Лучше для каждого сигнала брать пару-тройку входных данных и пробовать их декодировать с инверсией и без инверсии - соответственно принимать решение изначально инвертировать входные данные или нет.

Намного лучше декодируется 4-5 битные входные данные ("мягкие" входные данные), чем их жесткое соответствие 1/0 (бывает даже в разы)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для того, чтобы это выполнялось, слово из всех единиц должно быть кодовым. Вот и встает вопрос - выполняется ли ones * H' = 0 для рассматриваемого кода. Закодировал твоим кодером все единицы и НЕ получил кодовое слово из всех единиц, т.е. код как минимум не систематический. Сгенери полную проверочную матрицу и проверь (сумма столбцов (??? может, строк, плохо соображаю) проверочной матрицы должна быть равна zeros).

Все чудеснее и чудеснее. Взял CML сорцы и сделал простой тест. Только параметры поставил 2304 1/2 (позже скажу зачем):

plength = 2304;
data = ones(1, plength/2); 
[H_rows, H_cols, P] = InitializeWiMaxLDPC(1/2, 2304, []);
codeword = LdpcEncode( data, H_rows, P);
% 
code = '1/2';
[Hb, zf, coderate] = get_wimax_ldpc_Hb(code, plength);
code = ldpc_encode(data, Hb, zf);    

disp(['cml ones = ', num2str(length(find(codeword == 1))), ' cml zeros = ', num2str(length(find(codeword == 0)))]);
disp(['my  ones = ', num2str(length(find(codeword == 1))), ' my zeros  = ', num2str(length(find(codeword == 0)))]);
disp(['cml vs my diff = ', num2str(sum(abs(codeword - code)))]);

E = eye(zf);
[c, t] = size(Hb); 
H = zeros(c*zf, t*zf);
for row = 1:c
    for col = 1:t
        if Hb(row, col) >= 0
            H(zf*(row-1)+1 : zf*row, zf*(col-1)+1 : zf*col) = ...
                circshift(E,-1*Hb(row,col));
        end 
    end    
end

sum_of_rows = zeros(1, c); 
for row = 1:c
    sum_of_rows(row) = sum(H(row*zf, :)); % can check only one row per zf-by-zf
end 
sum_of_cols = zeros(1, t); 
for col = 1:t
    sum_of_cols(col) = sum(H(:,col*zf)); % can check only one col per zf-by-zf
end 

disp(['H sum rows = ', num2str(sum_of_rows)]);
disp(['H sum cols = ', num2str(sum_of_cols)]);

disp(['cml check = ', num2str(H(1,:)*codeword')]);
disp(['cml inv check = ', num2str(H(1,:)*not(codeword'))]);

disp(['my check = ', num2str(H(1,:)*codeword')]);
disp(['my inv check = ', num2str(H(1,:)*not(codeword'))]);

вот результат его работы:

cml ones = 1920 cml zeros = 384
my  ones = 1920 my zeros  = 384
cml vs my diff = 0
H sum rows = 6  7  7  6  6  7  6  6  7  6  6  6
H sum cols = 3  3  6  3  3  6  3  6  3  6  3  6  3  2  2  2  2  2  2  2  2  2  2  2
cml check = 6
cml inv check = 0
my check = 6
my inv check = 0

1/2 2304 взял по причине того, что нашел в книге рисунок матрицы такого кода. Он в приложении. Приведу первую строку и первый столбец проверочной матрицы:

find(H(1,:)) = 191         266         824         948        1160        1249
find(H(:,1))' = 324         853        1110

Совсем не то что приведено в книге, в других книгах точно такой же рисунок (похоже списывали друг у друга).

 

Вот как то у меня теперь шаблон линейных кодов немного взрывается, после результатов

 

но инверсия может декодеру не помочь....

в обсуждаемом коде мягкое решение без квантования. Инверсия в канале это поворот созвездия QPSK на 180 градусов.

 

Вот как то у меня теперь шаблон линейных кодов немного взрывается, после результатов

Залез в сорцы CML, кодируют они так

    for (i=0;i<kldpc;i++){
        c_in[i]=u[i]; // my: systematic bits
    }
    for (i=0;i<mldpc;i++){
        c_in[kldpc+i]=0; // my: parity bits
    }

    sum=0;
    for(i=0;i<mldpc;i++){ // my: mldpc - parity bit length 
        for(k=1;k<=wid_Hrows;k++){ // my: wid_Hrows - H rows number 
            if(H_rows[i+mldpc*(k-1)]!=0){
                count=(int)H_rows[i+mldpc*(k-1)];
                x[i]=((int)c_in[count-1])^((int)x[i]);
            }
        }
        c_in[kldpc+i]=x[i]^sum; /* Differential encoding */
        sum=c_in[kldpc+i];
    }

Ничего неожиданного, классический расчет битов четности, а нули в потоке образуются похоже в тех рядах где 7 единиц :)

 

UPD. Шаблон разрывает по причине того, что не могу понять почему проверка проходит на инверсных битах.

post-3453-1427554049_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

UPD. Шаблон разрывает по причине того, что не могу понять почему проверка проходит на инверсных битах.

Отвечаю сам себе. Потому что кто-то(ну т.е. я) лошпет :)

1. Математика там должна быть по модулю 2.

2. Проверять надо весь вектор, а не один бит.

 

Правильный код проверки

check     = mod(H*codeword', 2); 
inv_check = mod(H*not(codeword'), 2); 

disp(['cml check = ', num2str(sum(check))]);
disp(['cml inv check = ', num2str(sum(inv_check))]);

check     = mod(H*code', 2); 
inv_check = mod(H*not(code'), 2); 

disp(['my check = ', num2str(sum(check))]);
disp(['my inv check = ', num2str(sum(inv_check))]);

и результат

cml ones = 1920 cml zeros = 384
my  ones = 1920 my zeros  = 384
cml vs my diff = 0
H sum rows = 6  7  7  6  6  7  6  6  7  6  6  6
H sum cols = 3  3  6  3  3  6  3  6  3  6  3  6  3  2  2  2  2  2  2  2  2  2  2  2
cml check = 0
cml inv check = 384
my check = 0
my inv check = 384

т.е. все работает правильно. Это возвращает к первоначальному вопросу из поста №142:

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Если ты правильно сформировал матрицу (а похоже, что это так), то вектор-столбец, являющийся суммой по модулю два столбцов проверочной матрицы выглядит так - см картинку

 

Он явно не нулевой, а это означает, что декодер будет работать по разному, в зависимости от знаков входных данных

 

Теперь по статье.

 

Разберемся с работой чек ноды в LDPC декодере. Пусть мы имеем простейшую чек-ноду с двумя входами, между которыми вычисляется xor, чтобы получить значение чек-бита.

 

В этом случае, чек бит равен единице, если входы разные и 0, если они одинаковые. Для вероятностей получаем:

 

p_c(1) = p_1(1) * p_2(0) + p_1(0) * p_2(1); p_c(0) = p_1(1) * p_2(1) + p_1(0) * p_2(0);

 

Рассмотрим отношение p_c(1)/p_c(0). Разделим числитель и знаметатель на p_1(0) * p_2(0) и получим:

 

p_c(1)/p_c(0) = (exp(L1) + exp(L2))/(1+exp(L1)*exp(L2))

 

 

L1, L2 - LLR первого и второго битов. p_1(1)/p_1(0) = exp(L1); p_2(1)/p_2(0) = exp(L2)

 

Далее, используем следующее соотношение:

 

exp(L) = (1+tanh(L/2))/(1-tanh(L/2)) - это собственно следует из определения tanh

 

После подстановки и скучного приведения слагаемых получаем

 

p_c(1)/p_c(0) = (1- tanh(L1/2)*tanh(L2/2))/(1 + tanh(L1/2)*tanh(L2/2))

 

О волшебство! получили инверсию того, что используется для чек-ноды в статье. Следовательно, в статье для чек-нод получают инверсное соотношение

 

p_c(0)/p_c(1)

 

Для "взрослого" случая из n входных бит чек-ноды, можно воспользоваться мат. индукцией и прийти к такому же выводу.

 

Для variable node соотношения будут иметь тот же вид, что и в статье, но делаем вывод, что декодер работает в терминах инверсных LLR (ln(p(0)/p(1))). Именно из-за этого и инвертируют входные LLR.

Если ты используешь инверсный маппинг, то получаешь инверсные LLR и твой декодер начинает работать правильно.

 

Как-то так.

post-39163-1427576429_thumb.jpg

Изменено пользователем andyp

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Теперь по статье.

.....

После подстановки и скучного приведения слагаемых получаем

.....

Математику уже затем учить надо, что она ум в порядок приводит (с) Ломоносов.

Все вывел, посмотрел что к чему, как то не подумал в эту сторону :(. Причем маппинг в статье как у меня один в один. Спасибо большое!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

+ интересный факт, при вычислении llr если выбрать неправильную дисперсию шума, sum-product работает ужасно, а вот min-sum, которому не важен коэффициент при llr-ах работает нормально.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

+ интересный факт, при вычислении llr если выбрать неправильную дисперсию шума, sum-product работает ужасно, а вот min-sum, которому не важен коэффициент при llr-ах работает нормально.

"Ужасно" и "нормально" это в децибеллах (до Шеннона) сколько?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...