回顾
上篇博客讲述了AWGN信道下TPC码迭代译码的原理及CPP实现,此次主要讨论一种改进的译码方式,也就是基于错误和擦除(Error-and-Erasure, EaE)的译码。
EaE信道模型
如上图所示,我们定义一个可配置的阈值
T
T
T,使得值
y
i
∈
[
−
T
,
+
T
]
y_i∈[−T, +T]
yi∈[−T,+T]时被声明为擦除“?”。对于
∣
y
i
∣
>
T
|y _ i| > T
∣yi∣>T,根据通常的硬判决规则,
y
i
=
s
i
g
n
(
y
~
i
)
y_i =sign(\tilde y_i)
yi=sign(y~i)。显然,当
T
=
0
T=0
T=0时,EaE信道退化为二进制对称信道(Binary symmetric channel, BSC)。
Error-and-erasure译码算法(EaED)
算法核心思想(分量码为BCH码)
- 设置 T T T值和迭代次数 N N N。
- 以BPSK调制为例,首先进行判决,当接收信号幅度 y ∈ [ − T , T ] y\in[-T,T] y∈[−T,T]时,随机地将 y y y判决为0或1,生成 y 1 y_1 y1,取反则生成 y 2 y_2 y2;当 y < − T y<-T y<−T时,判决为0;当 y > T y>T y>T时,判决为1。经过判决, y 1 y_1 y1和 y 2 y_2 y2只有擦除部分01相反,其他部分完全一致。
- 每次译码之前,随机地对擦除位置赋值,同样
y
1
y_1
y1和
y
2
y_2
y2相反,开始按行译码(第
i
i
i行记为
y
1
[
i
]
y_1[i]
y1[i])。确定每行的擦除位置个数
num_era_row
,若num_era_row> 2 t + 1 2t+1 2t+1,则不进行译码;否则,对 y 1 [ i ] y_1[i] y1[i]和 y 2 [ i ] y_2[i] y2[i]分别进行译码,得到 w 1 w_1 w1和 w 2 w_2 w2。 - 对于译码结果 w 1 w_1 w1和 w 2 w_2 w2,若其对应的伴随式为0的个数为zero1和zero2,若zero1和zero2均为0,则将该行的擦除位置标记为未擦除状态(不断迭代,擦除位置减少);按如下规则译码:
if
zero1和zero2均不为0,则不进行译码else if
zero1 < zero2,则选择 w 1 w_1 w1作为译码结果else if
zero1 > zero2,则选择 w 2 w_2 w2作为译码结果else
则分别计算该行与 w 1 w_1 w1和 w 2 w_2 w2的汉明距离,选择距离小的作为译码结果
- 按列译码,重复第3、4、5步;
- 迭代,重复第2、3、4、5步。
C语言实现
子程序
与第一篇博客相同,可查看
【Turbo乘积码1】AWGN信道下TPC码迭代译码的C语言实现及工程详细解析『需要完整工程代码请先私信』
主程序
int main()
{
//以 (63,51,2) BCH码为例
//int t = 2;
int t = 3;
//unsigned char cpx[] = { 1,0,0,0,0,1,1 }; //通过输入获取 八进制103
//unsigned char cpx[] = { 1,0,0,0,1,1,1,0,1 }; //八进制 435, (255,247,1)
unsigned char cpx[] = { 1,0,0,0,0,1,0,0,0,1 }; //八进制 1021, (511,502,1)
int m = _countof(cpx) - 1; //px次数
unsigned char* px = new unsigned char[m + 1];
memmove(px, cpx, sizeof(unsigned char)*(m + 1));
//unsigned char cgx[] = { 1,0,1,0,1,0,0,1,1,1,0,0,1 }; //通过输入获取 八进制 12471
//unsigned char cgx[] = { 1,1,0,1,1,1,0,1,1,1,0,1,0,0,0,0,1,1,0,1,1,0,1,0,1 }; //八进制 156720665, (255,231,3)
unsigned char cgx[] = { 1, 1,0,1, 0,1,1, 0,0,0, 0,1,0, 0,1,0, 1,0,1, 1,0,1, 1,1,1, 0,0,1 }; //八进制 1530225571, (511,484,3)
int glen = _countof(cgx);
int n = (0x01 << m) - 1;
int k = n - glen + 1;
printf("(%d,%d,%d)*(%d,%d,%d) TPC码的误码率:\n", n, k, t, n, k, t);
unsigned char* gx = new unsigned char[glen];
memmove(gx, cgx, sizeof(unsigned char)*glen);
int malign = 0;
if (m % 8 == 0)
malign = m;
else
malign = (m / 8 + 1) * 8;
unsigned char* a = new unsigned char[n*malign];
unsigned int* a_dec = new unsigned int[n];
unsigned int* log_a = new unsigned int[n];
int* pos_err = new int[t];
gf_gen(px, m + 1, a, a_dec, log_a);
double snr0 = 4.7, snr1 = 4.9, snrstep = 0.5, T = 0.057;
//double snr0 = 0.005, snr1 = 0.1, snrstep = 0.005;
int snrlen = (int)((snr1 - snr0) / snrstep) + 1;
double* snr = new double[snrlen];
snr[0] = snr0;
int i = 0, j, l, s, ss, it, row;
for (i = 1; snr[i - 1] + snrstep <= snr1; ++i)
{
snr[i] = snr0 + i * snrstep;
}
unsigned char* v = new unsigned char[n*n];
unsigned char* u = new unsigned char[k*k];
double* vd = new double[n*n];
double* vn = new double[n*n];
double* num_bef = new double[snrlen];
double* num_aft = new double[snrlen];
unsigned char* r = new unsigned char[n*n];
unsigned char* rtmp = new unsigned char[n*n];
unsigned char* rdec = new unsigned char[n*n];
unsigned char* rdectmp = new unsigned char[n*n];
unsigned char* y1 = new unsigned char[n*n];
unsigned char* y2 = new unsigned char[n*n];
PT* pos_era = new PT[n*n]; // record the erasing pos
memset(pos_era, 0xff, n*n * sizeof(PT));
unsigned char* is_era = new unsigned char[n*n];
unsigned char* is_era_tmp = new unsigned char[n*n];
memset(is_era_tmp, 0, n*n);
unsigned char* w1 = new unsigned char[n];
memset(w1, 0, n);
unsigned char* w2 = new unsigned char[n];
memset(w2, 0, n);
int codnum = 50;
int iter = 10;
double num_test = 0;
std::list<int> listIndEra, listIndRowEra;
std::list<int>::iterator ite;
for (i = 0; i < snrlen; ++i)
{
double SNRi = snr[i];
num_bef[i] = 0;
num_aft[i] = 0;
for (j = 0; j < codnum; ++j)
{
listIndEra.clear(); // clear the list
num_test = 0;
memset(y1, 0, n*n);
memset(y2, 0, n*n);
memset(is_era, 0, n*n);
randi(u, k*k, 0, 1); // k*k source bit
tpcEncod(u, k, gx, glen, k, gx, glen, v, false);
for (l = 0; l < n*n; ++l)
{
vd[l] = 2.0*v[l] - 1;
}
awgn(vd, n*n, SNRi, false, vn);
//crossover(v, n*n, SNRi, r);
for (l = 0; l < n*n; ++l)
{
r[l] = (unsigned char)(vn[l] > 0);
}
for(l=0;l<k;++l)
for (s = 0; s < k; ++s)
{
num_bef[i] += r[l*n + s] ^ v[l*n + s];
}
int sum_era = 0;
for (l = 0; l < n; ++l)
{
for (s = 0; s < n; ++s)
{
if (vn[l*n + s] < -T)
{
y1[l*n + s] = 0;
y2[l*n + s] = 0;
}
else if (vn[l*n + s] > T)
{
y1[l*n + s] = 1;
y2[l*n + s] = 1;
}
else
{
is_era[l*n + s] = 1;
pos_era[sum_era].x = s;
pos_era[sum_era].y = l;
listIndEra.push_back(l*n + s);
++sum_era;
}
}
}
unsigned char* random_values = new unsigned char[sum_era];
此处为核心代码……
请先私信获取!
for (s = 0; s < n; ++s) // trans
{
for (ss = 0; ss < n; ++ss)
{
rdectmp[s * n + ss] = rdec[ss * n + s];
rtmp[s*n + ss] = r[ss*n + s];
is_era_tmp[s*n + ss] = is_era[ss*n + s];
}
}
memmove(rdec, rdectmp, sizeof(unsigned char)*n*n);
memmove(r, rtmp, sizeof(unsigned char)*n*n);
memmove(is_era, is_era_tmp, sizeof(unsigned char)*n*n);
for (l = 0; l < n*n; ++l)
{
if (!is_era[l])
{
y1[l] = rdec[l];
y2[l] = rdec[l];
}
}
}
delete[] random_values;
//if (j % 100000 == 0 && j>0)
//{
// printf("SNR:%4.3f, N:%8d, 译码前误码率:%10.2e, 译码后误码率:%10.2e\n", SNRi, j, num_bef[i] / (k*k) / j, num_aft[i] / (k*k) / j);
//}
}//end codnum
for (l = 0; l < k; ++l)
for(s=0;s<k;++s)
{
num_aft[i] += rdec[l*n +s] ^ v[l*n + s];
}
printf("SNR:%4.3f 译码前误码率:%10.2e 译码后误码率:%10.2e\n", SNRi, num_bef[i] / (k*k) / codnum, num_aft[i] / (k*k) / codnum);
}//end snr
delete[] w2;
delete[] w1;
delete[] is_era;
delete[] is_era_tmp;
delete[] pos_era;
delete[] y2;
delete[] y1;
delete[] rdectmp;
delete[] num_aft;
delete[] num_bef;
delete[] rdec;
delete[] r;
delete[] rtmp;
delete[] vn;
delete[] vd;
delete[] u;
delete[] v;
delete[] snr;
delete[] pos_err;
delete[] px;
delete[] gx;
delete[] a;
delete[] a_dec;
delete[] log_a;
return 0;
}
运行结果
参数
BCH码:(511,484,3)BCH码,t=3
SNR为:3:0.4:4.6
迭代次数:5
T:0.057
截图
完整工程代码
请先私信领取!
参考文献
Improved Soft-Aided Decoding of Product Codes With Dynamic Reliability Scores.