介绍
最近在想创新点,把年前写得polar SC、SCL译码C语言版本小结一下。
1.SC缺点
因为SC译码器在对后面的信息比特译码时需要用到之前的信息比特的估计值,会导致严重的错误传递,而且它对每一层仅仅搜索到最优路径就进行下一层,所以无法对错误进行修改。SCL就是对SC算法的改进。
2.SCL译码算法
改进的方案是从码树的根节点出发,逐层依次向叶子节点层进行路径搜索。不同的是,每一层拓展后,尽可能多地暴力后继路径(每一层保留的路径数不大于L)。完成一层的路径拓展后,选择路径度量值(PM)最小的L条,保存在一个列表中,等待进行下一层的拓展。因此该算法称为串行抵消列表(SCL)译码算法,并称参数L为搜索宽度。当L=1,SCL译码算法退化为SC译码算法,当L大于等于2^K时,SCL译码等价于最大似然译码。
2.1 路径度量
− l n P r ( u 1 i ∣ y 1 N ) = ∑ k = 1 i l n ( 1 + e − ( 1 − u k ) L N ( k ) ) , -lnPr(u_1^i|y_1^N)=\sum\nolimits_{k=1}^{i} {ln(1+e^{-(1-u_k)L_N^{(k)}})}, −lnPr(u1i∣y1N)=∑k=1iln(1+e−(1−uk)LN(k)),
其 中 − l n P r ( u 1 i ∣ y 1 N ) 称 为 路 径 度 量 。 这 里 路 径 指 的 是 译 码 路 径 , 即 译 码 序 列 u 1 i . 其中-lnPr(u_1^i|y_1^N)称为路径度量。这里路径指的是译码路径,即译码序列u_1^i. 其中−lnPr(u1i∣y1N)称为路径度量。这里路径指的是译码路径,即译码序列u1i.
① 上 式 说 明 比 特 序 列 u 1 i 后 验 概 率 P r ( u 1 i ∣ y 1 N ) 可 以 使 用 S C 译 码 器 计 算 结 果 , 因 为 已 经 算 出 u k , 所 以 就 可 以 表 示 出 P r ( u 1 i ∣ y 1 N ) 。 ①上式说明比特序列u_1^i后验概率Pr(u_1^i|y_1^N)可以使用SC译码器计算结果,因为已经算出u_k,所以就可以表示出Pr(u_1^i|y_1^N)。 ①上式说明比特序列u1i后验概率Pr(u1i∣y1N)可以使用SC译码器计算结果,因为已经算出uk,所以就可以表示出Pr(u1i∣y1N)。
② 我 们 希 望 译 码 结 果 正 确 , 即 希 望 P r ( u 1 i ∣ y 1 N ) 的 值 越 大 越 好 , 从 而 − l n P r ( u 1 i ∣ y 1 N ) 越 小 越 好 。 一 开 始 我 们 认 为 从 零 开 始 , 然 后 用 上 式 进 行 累 加 。 ②我们希望译码结果正确,即希望Pr(u_1^i|y_1^N)的值越大越好,从而-lnPr(u_1^i|y_1^N)越小越好。一开始我们认为从零开始,然后用上式进行累加。 ②我们希望译码结果正确,即希望Pr(u1i∣y1N)的值越大越好,从而−lnPr(u1i∣y1N)越小越好。一开始我们认为从零开始,然后用上式进行累加。
③ 上 式 中 等 号 两 端 恒 为 正 实 数 , 等 号 右 边 是 一 个 近 似 值 : 如 果 u k = 0 , L N ( k ) ≥ 0 , 则 l n ( 1 + e ( − ( 1 − 2 u k ) ) ≈ 0 ; 如 果 u k = 1 , L N ( k ) ≥ 0 , l n ( 1 + e ( − ( 1 − 2 u k ) ) ≈ L N ( k ) 。 ③上式中等号两端恒为正实数,等号右边是一个近似值:如果u_k=0,L_N^{(k)}\ge 0,则ln(1+e^{(-(1-2u_k))}\approx0;如果u_k=1,L_N^{(k)}\ge 0,ln(1+e^{(-(1-2u_k))}\approx L_N^{(k)}。 ③上式中等号两端恒为正实数,等号右边是一个近似值:如果uk=0,LN(k)≥0,则ln(1+e(−(1−2uk))≈0;如果uk=1,LN(k)≥0,ln(1+e(−(1−2uk))≈LN(k)。
从 ③ 中 可 以 发 现 , 当 u k 其 符 合 L N ( k ) 硬 判 决 时 , 上 式 总 是 约 为 零 ; 反 之 , 如 果 不 能 进 行 硬 判 决 , 上 式 的 值 约 等 于 ∣ L N ( k ) ∣ 。 因 此 上 式 的 值 越 小 越 好 。 从③中可以发现,当u_k其符合L_N^{(k)}硬判决时,上式总是约为零;反之,如果不能进行硬判决,上式的值约等于|L_N^{(k)}|。因此上式的值越小越好。 从③中可以发现,当uk其符合LN(k)硬判决时,上式总是约为零;反之,如果不能进行硬判决,上式的值约等于∣LN(k)∣。因此上式的值越小越好。
2.2 基于LLR的SCL译码器的执行过程
① S C L 译 码 器 中 内 部 放 置 L 个 S C 译 码 器 , 分 别 编 号 为 第 1 , 2 , . . . , L 个 S C 译 码 器 , 记 为 S C 1 , S C 2 , . . . , S C N 所 以 , 大 致 地 , S C L 大 致 所 需 存 储 空 间 几 乎 时 S C 译 码 器 的 L 倍 2 。 ①SCL译码器中内部放置L个SC译码器,分别编号为第1,2,...,L个SC译码器,记为SC_1,SC_2,...,SC_N所以,大致地,SCL大致所需存储空间几乎时SC译码器的L倍^2。 ①SCL译码器中内部放置L个SC译码器,分别编号为第1,2,...,L个SC译码器,记为SC1,SC2,...,SCN所以,大致地,SCL大致所需存储空间几乎时SC译码器的L倍2。
② 出 L N ( 1 ) 后 , 1 号 S C 译 码 器 判 断 u 1 是 否 为 冻 结 比 特 。 如 果 u 1 是 冻 结 比 特 , 则 不 激 活 其 他 S C 译 码 器 。 直 接 令 u 1 = 0 , 并 计 算 路 径 度 量 。 然 后 1 号 译 码 器 继 续 使 用 S C 译 码 流 程 更 新 ∑ k = 1 i l n ( 1 + e − ( 1 − u k ) L N ( k ) ) , 直 到 遇 到 u i , 其 中 u i 为 极 化 码 的 首 个 信 息 比 特 。 ②出L_N^{(1)}后,1号SC译码器判断u_1是否为冻结比特。如果u_1是冻结比特,则不激活其他SC译码器。直接令u_1=0,并计算路径度量。然后1\\号译码器继续使用SC译码流程更新\sum\nolimits_{k=1}^{i} {ln(1+e^{-(1-u_k)L_N^{(k)}})},直到遇到u_i,其中u_i为极化码的首个信息比特。 ②出LN(1)后,1号SC译码器判断u1是否为冻结比特。如果u1是冻结比特,则不激活其他SC译码器。直接令u1=0,并计算路径度量。然后1号译码器继续使用SC译码流程更新∑k=1iln(1+e−(1−uk)LN(k)),直到遇到ui,其中ui为极化码的首个信息比特。
③ 此 时 S C L 译 码 器 发 现 尚 有 L − 1 个 未 激 活 的 S C 译 码 器 , 从 S s l e e p = 2 , 3... L 中 弹 出 L , 激 活 编 号 为 L 的 译 码 器 S C 译 码 器 S C L 。 S C L 继 承 全 部 数 据 , 对 于 于 上 一 章 的 u p p e r 和 l o w e r 。 ③此时SCL译码器发现尚有L-1个未激活的SC译码器,从S_{sleep}={2,3...L}中弹出L,激活编号为L的译码器SC译码器SC_L。SC_L继承全部数据,对于于上一章的upper和lower。 ③此时SCL译码器发现尚有L−1个未激活的SC译码器,从Ssleep=2,3...L中弹出L,激活编号为L的译码器SC译码器SCL。SCL继承全部数据,对于于上一章的upper和lower。
原译码路径(SC1)总是令ui=0,克隆路径(SCL)总是令ui=1。
u
1
,
1
i
与
u
1
,
L
i
分
别
对
应
度
量
值
如
下
:
u_{1,1}^i与u_{1,L}^i分别对应度量值如下:
u1,1i与u1,Li分别对应度量值如下:
P r ( u 1 , 1 i ∣ y 1 N ) = ∑ k = 1 i − 1 l n ( 1 + e − ( 1 − 2 u k , 1 ) L N ( K ) ) + l n ( 1 + e − L N ( i ) ) Pr(u_{1,1}^i|y_1^N)=\sum\limits_{k=1}^{i-1} {ln(1+e^{-(1-2u_{k,1})L_N^{(K)}})}+ln(1+e^{-L_N^{(i)}}) Pr(u1,1i∣y1N)=k=1∑i−1ln(1+e−(1−2uk,1)LN(K))+ln(1+e−LN(i))
P r ( u 1 , L i ∣ y 1 N ) = ∑ k = 1 i − 1 l n ( 1 + e − ( 1 − 2 u k , L ) L N ( K ) ) + l n ( 1 + e L N ( i ) ) Pr(u_{1,L}^i|y_1^N)=\sum\limits_{k=1}^{i-1} {ln(1+e^{-(1-2u_{k,L})L_N^{(K)}})}+ln(1+e^{L_N^{(i)}}) Pr(u1,Li∣y1N)=k=1∑i−1ln(1+e−(1−2uk,L)LN(K))+ln(1+eLN(i))
SCL译码器同时保留了ui=0和1的两种译码结果。
④
P
M
1
=
∑
k
=
1
j
−
1
l
n
(
1
+
e
−
(
1
−
2
u
k
,
1
)
L
N
,
1
(
k
)
)
,
P
M
L
=
∑
k
=
1
j
−
1
l
n
(
1
+
e
−
(
1
−
2
u
k
,
L
)
L
N
,
L
(
k
)
)
\\PM_1=\sum\limits_{k=1}^{j-1}ln(1+e^{-(1-2u_k,1)L_{N,1}^{(k)}}),\\ PM_L=\sum\limits_{k=1}^{j-1}ln(1+e^{-(1-2u_k,L)L_{N,L}^{(k)}})\\
PM1=k=1∑j−1ln(1+e−(1−2uk,1)LN,1(k)),PML=k=1∑j−1ln(1+e−(1−2uk,L)LN,L(k))
执行操作与步骤3相似,说白了SCL译码器保留了(ui,uj)=(0,0)、(0,1)、(1,0)、(1,1)四种译码结果。
⑤以上过程将一直持续,直到遇到第log2L个信息比特us1。这是一个临界点,因此当Ssleep不是空集合时,所有L个SC译码器都被激活,都获得了各自的数据(LLR和中间比特值).
如
果
发
送
端
的
所
有
信
息
比
特
在
0
,
1
上
均
匀
分
布
,
那
么
对
于
任
意
两
条
不
同
路
径
l
1
,
l
2
∈
{
1
,
2
,
.
.
.
,
L
}
,
当
且
仅
当
P
M
l
1
(
i
)
>
P
M
l
2
(
i
)
)
成
立
时
有
如
下
关
系
:
如果发送端的所有信息比特在{0,1}上均匀分布,那么对于任意两条不同路径l_1,l_2\in \{1,2,...,L\},当且仅当PM_{l_1}^{(i)}>PM_{l_2}^{(i)})成立时有如下关系:
如果发送端的所有信息比特在0,1上均匀分布,那么对于任意两条不同路径l1,l2∈{1,2,...,L},当且仅当PMl1(i)>PMl2(i))成立时有如下关系:
W N ( i ) ( y 1 N , u ^ 1 i − 1 [ l 1 ] ∣ u ^ 1 i − 1 [ l 1 ] ) < W N ( i ) ( y 1 N , u ^ 1 i − 1 [ l 2 ] ∣ u ^ 1 i − 1 [ l 2 ] ) W_N^{(i)}(y_1^N,\hat{u}_1^{i-1}[l_1]|\hat{u}_1^{i-1}[l_1])< W_N^{(i)}(y_1^N,\hat{u}_1^{i-1}[l_2]|\hat{u}_1^{i-1}[l_2]) WN(i)(y1N,u^1i−1[l1]∣u^1i−1[l1])<WN(i)(y1N,u^1i−1[l2]∣u^1i−1[l2])
由上式可见,路径对应的转移概率越大,路径值越小。对于这种关系就完全可以在对数似然比上对2L条路径进行挑选。可以得到如下公式:
KaTeX parse error: Unknown column alignment: * at position 34: …{\begin{array}{*̲{20}{c}} {PM_l^…
但考虑到译码过程中包含信息比特和冻结比特,上式可以改写成如下公式:
其 中 δ ( x ) = 1 2 ( 1 − s i g n ( x ) ) , P M l ( 0 ) = 0 。 对 于 信 息 比 特 的 判 决 有 如 下 的 公 式 其中\delta(x)=\frac{1}{2}(1-sign(x)),PM_l^{(0)}=0。对于信息比特的判决有如下的公式 其中δ(x)=21(1−sign(x)),PMl(0)=0。对于信息比特的判决有如下的公式
u ^ i = δ ( L N ( i ) ( y 1 N , u ^ 1 i − 1 ) \hat{u}_i=\delta(L_N^{(i)}(y_1^N,\hat{u}_1^{i-1}) u^i=δ(LN(i)(y1N,u^1i−1)
PM中每个元素的意义如下:PM第l列的第一行元素表示译码器SCl遵循上面的原则,保存了ut,l=0所导致的路径度量;译码器遵循上面的规矩,想要克隆出一个新的并保存ut,l=1的路径,这个新路径的度量值就是PM的第l列第二行元素。
由路径幸存定理知道,度量值越小越好,所有我们从PM中的2L个元素里选出L个小的值,此时PM会出现如下三种情况。
情况一:PM中第l,1<l<L列中的两个元素都未入选L个最小的值,此时我们宣布SCl译码器死亡;
情况二:PM中第l,l<l<L列中仅有一个元素入选最小的值,这时译码器SCl仅保存入选的值对应的比特,若第l列第1行的值入选,则保存ut,l=0,并更新路径度量如下:
P
M
l
=
P
M
l
+
l
n
(
1
+
e
−
L
N
,
l
(
t
)
)
PM_l=PM_l+ln(1+e^{-L_{N,l}^{(t)}})
PMl=PMl+ln(1+e−LN,l(t))
若第l列的第2行的值入选,则保存ut.1,并更新路径度量如下:
P
M
l
=
P
M
l
+
l
n
(
1
+
e
L
N
,
l
(
t
)
)
PM_l=PM_l+ln(1+e^{L_{N,l}^{(t)}})
PMl=PMl+ln(1+eLN,l(t))
情况三:PM中第l,1<l<L列中两个元素均入选L个最小的值,这时译码器SCl仅保存入选的值对应的比特。如果此情况出现,则情况一必出现。否则幸存路径就多于L个。这时SCl遵循上面的原则,保留判决值ut,l=0,并更新路径量为:
P
M
l
=
P
M
l
+
l
n
(
1
+
e
−
L
N
,
l
(
t
)
)
PM_l=PM_l+ln(1+e^{-L_{N,l}^{(t)}})
PMl=PMl+ln(1+e−LN,l(t))
随后,SCl需要进行克隆。这时我们从Ssleep中弹出一个元素,设这个弹出元素为p,则唤醒SCp:把SCl的所有存储都赋值给SCp,但是SCp保留ut,p=1,同时令
P
M
p
=
P
M
l
+
l
n
(
1
+
e
L
N
,
l
(
t
)
)
PM_p=PM_l+ln(1+e^{L_{N,l}^{(t)}})
PMp=PMl+ln(1+eLN,l(t))
⑥当完成译码后,获得L个译码结果,选择对应最小路径度量值的译码结果作为SCL译码器的输出。
3.举个例子来说明SCL执行过程
AWGN信道,Eb/No=4dB.
码长N=8,信息比特K=4,码率R=K/N=0.5,列表数量L=4。
信息比特集合A={4,6,7,8},冻结比特全部取0。
4个信息比特为(1,1,1,1),则u=(00010111),编码之后x=uF=(01101001)。
对应的BPSK序列为s=(1,-1,-1,1,-1,1,1,-1)
用matlab随机产生一个噪声序列n=(-1.4,0.5,0.2,-0.8,-0.3,0.2,2.3,1.7)
接收信号为y=s+n=(-0.4,-0.5,-0.8,0.2,-1.3,1.2,3.3,0.7)
接收对数似然比为L=2/sigma^2y=(-2.0,-2.5,-4.0,1.0,-6.5,6.0,16.6,3.5)。
接下来我们开始介绍SCL的执行过程。
其
中
P
[
i
]
表
示
位
于
二
叉
树
第
i
层
(
叶
节
点
是
第
一
层
)
的
存
储
L
L
R
数
组
,
P
[
i
]
的
大
小
为
2
i
−
1
×
L
。
P
[
i
]
的
第
l
列
是
S
C
l
对
应
的
L
L
R
存
储
。
P
[
i
]
的
每
一
列
用
竖
线
隔
开
,
表
示
它
们
隶
属
于
各
个
S
C
译
码
器
P
i
,
j
[
i
]
表
示
第
i
行
第
j
列
元
素
。
而
P
:
,
j
[
i
]
表
示
P
[
i
]
的
第
j
列
。
其中P^{[i]}表示位于二叉树第i层(叶节点是第一层)的存储LLR数组,P^{[i]}的大小为2^{i-1}\times L。P^{[i]}的第l列是SC_l对应的 LLR存储。\\P^{[i]}的每一列用竖线隔开,表示它们隶属于各个SC译码器P_{i,j}^{[i]}表示第i行第j列元素。而P_{:,j}^{[i]}表示P^{[i]}的第j列。
其中P[i]表示位于二叉树第i层(叶节点是第一层)的存储LLR数组,P[i]的大小为2i−1×L。P[i]的第l列是SCl对应的LLR存储。P[i]的每一列用竖线隔开,表示它们隶属于各个SC译码器Pi,j[i]表示第i行第j列元素。而P:,j[i]表示P[i]的第j列。
C [ i ] 表 示 位 于 二 叉 树 第 i 层 ( 叶 节 点 是 第 1 层 ) 的 存 储 中 间 比 特 值 的 数 组 , C [ i ] 的 大 小 为 2 i − 1 × 2 L 。 C [ i ] 的 第 2 l − 1 和 第 2 l 列 是 S C l 对 应 的 中 间 比 特 存 储 。 C [ i ] 每 两 列 用 竖 线 隔 开 , 表 示 它 们 隶 属 于 各 个 S C 译 码 器 。 C i , j [ i ] 表 示 C [ i ] 第 i 行 第 j 列 的 元 素 , C : , j [ i ] 表 示 C [ i ] 的 第 j 列 。 由 此 S C l 拥 有 存 储 C : , 2 l − 1 [ i ] 和 C : , 2 l i 。 C^{[i]}表示位于二叉树第i层(叶节点是第1层)的存储中间比特值的数组,C^{[i]}的大小为2^{i-1}\times 2L。C^{[i]}的第2l-1和第2l列是SC_l对应的中间比特存储。\\ C^{[i]}每两列用竖线隔开,表示它们隶属于各个SC译码器。C_{i,j}^{[i]}表示C^{[i]}第i行第j列的元素,C_{:,j}^{[i]}表示C^{[i]}的第j列。由此SC_l拥有存储C_{:,2l-1}^{[i]}和C_{:,2l}^{i}。 C[i]表示位于二叉树第i层(叶节点是第1层)的存储中间比特值的数组,C[i]的大小为2i−1×2L。C[i]的第2l−1和第2l列是SCl对应的中间比特存储。C[i]每两列用竖线隔开,表示它们隶属于各个SC译码器。Ci,j[i]表示C[i]第i行第j列的元素,C:,j[i]表示C[i]的第j列。由此SCl拥有存储C:,2l−1[i]和C:,2li。
g函数的计算为:
p i , l [ m + 1 ] = ( 1 − 2 C i , 2 l − 1 [ m + 1 ] ) P i , L C m + 2 , l m + 1 + P i + 2 m , L C m + 2 , l [ m + 2 ] , 1 ≤ i ≤ 2 m + 1 p_{i,l}^{[m+1]}=(1-2C_{i,2l-1}^{[m+1]})P_{i,LC_{m+2,l}}^{m+1}+P_{i+2^m,LC_{m+2,l}}^{[m+2]},1\le i\le 2^{m+1} pi,l[m+1]=(1−2Ci,2l−1[m+1])Pi,LCm+2,lm+1+Pi+2m,LCm+2,l[m+2],1≤i≤2m+1
f函数的计算为:
p i , l [ s ] = s i g n ( P i , l [ s + 1 ] ) s i g n ( P i + 2 s − 1 , l [ s + 1 ] ) m i n { ∣ p i , l [ s + 1 ] ∣ ∣ P i + 2 s − 1 , l [ s + 1 ] ∣ } , 1 ≤ s ≤ m , 1 ≤ i ≤ 2 s − 1 p_{i,l}^{[s]}=sign(P_{i,l}^{[s+1]})sign(P_{i+2^{s-1},l}^{[s+1]}) min\{|p_{i,l}^{[s+1]}| |P_{i+2^{s-1},l}^{[s+1]}|\},1\le s\le m,1\le i\le 2^{s-1} pi,l[s]=sign(Pi,l[s+1])sign(Pi+2s−1,l[s+1])min{∣pi,l[s+1]∣∣Pi+2s−1,l[s+1]∣},1≤s≤m,1≤i≤2s−1
① 在 为 C : , 2 l [ s ] , 2 ≤ s ≤ m 。 码 规 则 如 下 : C i , 2 l [ s ] = C i . 2 L C s − 1 , l − 1 [ s − 1 ] ⊕ C i , 2 l [ s − 1 ] C i + 2 s − 2 , 2 l [ s ] = C i , 2 l [ s − 1 ] 2 ≤ s ≤ m , 1 ≤ i ≤ 2 s − 2 ①在为C_{:,2l}^{[s]},2\le s\le m。码规则如下:\\ C_{i,2l}^{[s]}=C_{i.2LC_{s-1,l-1}}^{[s-1]}\oplus C_{i,2l}^{[s-1]}\\ C_{i+2^{s-2},2l}^{[s]}=C_{i,2l}^{[s-1]}\\ 2\le s\le m,1\le i\le 2^{s-2} ①在为C:,2l[s],2≤s≤m。码规则如下:Ci,2l[s]=Ci.2LCs−1,l−1[s−1]⊕Ci,2l[s−1]Ci+2s−2,2l[s]=Ci,2l[s−1]2≤s≤m,1≤i≤2s−2
② 在 为 C : , 2 l − 1 [ m + 1 ] , 2 ≤ s ≤ m 。 码 规 则 如 下 : C i , 2 l [ m + 1 ] = C i . 2 L C m , l − 1 [ m ] ⊕ C i , 2 l [ m ] C i + 2 m − 1 , 2 l [ m + 1 ] = C i , 2 l [ m ] 1 ≤ i ≤ 2 m − 1 ②在为C_{:,2l-1}^{[m+1]},2\le s\le m。码规则如下:\\ C_{i,2l}^{[m+1]}=C_{i.2LC_{m,l-1}}^{[m]}\oplus C_{i,2l}^{[m]}\\ C_{i+2^{m-1},2l}^{[m+1]}=C_{i,2l}^{[m]}\\ 1\le i\le 2^{m-1} ②在为C:,2l−1[m+1],2≤s≤m。码规则如下:Ci,2l[m+1]=Ci.2LCm,l−1[m]⊕Ci,2l[m]Ci+2m−1,2l[m+1]=Ci,2l[m]1≤i≤2m−1
SCL译码代码如下:
//与之前的想法有点不同,如果遇到冻结比特不展开,直到遇到信息位再展开!
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
//#include "mex.h"
double f(double a,double b);
double g(double a,double b,int c);
int sign(double a);
void sort(double *a,int length,int *b);
int *decode(double *llr,int *CBR,int N,int n,int L);
/*int main(){
int N=16;
int n=4;
int L=16;
int CBR[16]={0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1};
double llr[16]={
-7.07930199214985, 2.76554580800147, 3.51458457353357, -4.60789834653299, 5.51983505923934,
-2.89081837437499 ,-1.86824633897555, 9.01423107332865, -0.535281082445535, 0.365229775696605,
-2.58894675800013, -1.44250051044581, -1.19529248833795, -3.80193134240250 ,-3.89029241831878 ,10.2824416871326};
int *u;
u=decode(llr,CBR,N,n,L);
for(int i=0;i<N;i++){
printf("%d ",u[i]);
}
//xx=0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0
}*/
int *decode(double *llr,int *CBR,int N,int n,int L){
//mod执行次数
int A[N];
for(int i=0;i<N;i++){
int j=i+1;
int layer=0;
while(j%2==0){
j/=2;
layer+=1;
}
A[i]=layer;
}
//f执行次数
int B[N];
B[0]=0;
for(int i=1;i<N;i++){
int j=i;
int layer=0;
while(j%2==0){
j/=2;
layer+=1;
}
B[i]=layer;
}
double P[N][n+1][2*L];//P数组存放中间似然比的值
double Q[N][n+1][2*L];//存放P转换值
int C[N][n+1][2*L];//C数组存放bit值
int E[N][n+1][2*L];//存放C数值转换值
for(int j=0;j<2*L;j++){
for(int i=0;i<N;i++){
P[i][n][j]=llr[i];
// printf("%.2f ",P[i][n][0]);
}
}
//printf("%.2f ",P[0][n][0]);
//printf("\n");
for(int l=0;l<2*L;l++){
int h=N;
for(int j=n-1;j>=0;j--){
for(int i=0;i<h/2;i++){
P[i][j][l]=f(P[i][j+1][l],P[i+h/2][j+1][l]);
}
h/=2;
}
}
//printf("%.2f ",P[0][0][0]);
double PM[2*L];
for(int i=0;i<2*L;i++){
PM[i]=0;
}
int flag=1;//判断是否到达路径最大值
double delta[2*L];
delta[0]=P[0][0][0];//实际值与估计值
//第一位是冻结位
if(!CBR[0]){
C[0][0][0]=0;
if(C[0][0][0]==sign(delta[0])){
PM[0]=0;
}
else{
PM[0]=fabs(delta[0]);
}
}
//printf("%.2f ",PM[0]);
//从第二位开始找规律
double Temp[2*L];
for(int i=0;i<flag;i++){
Temp[i]=PM[i];
// printf("%.2f ",Temp[i]);
}
for(int k=1;k<N;k++){
/*********奇数运算********/
if(k%2==1){//奇数运算执行g+mod运算
//判断是否为冻结位
if(!CBR[k]){//冻结比特不需要展开
for(int i=0;i<flag;i++){
delta[i]=g(P[k-1][1][i],P[k][1][i],C[k-1][0][i]);
C[k][0][i]=0;
if(C[k][0][i]==sign(delta[i])){
PM[i]=Temp[i];
}
else{
PM[i]=Temp[i]+fabs(delta[i]);
}
}
for(int i=0;i<flag;i++){
Temp[i]=PM[i];
}
}
//信息位需要展开啦!
else{
flag*=2;
if(flag<2*L){//小于2*L
for(int i=0;i<flag/2;i++){
delta[i]=g(P[k-1][1][i],P[k][1][i],C[k-1][0][i]);
//printf("%.2f ",delta[i]);
}
for(int l=0;l<flag;l++){
if(l%2==0){
C[k][0][l]=0;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
else{
C[k][0][l]=1;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
}
for(int i=0;i<k;i++){
for(int l=0;l<flag;l++){
E[i][0][l]=C[i][0][l/2];
}
}
for(int i=0;i<k;i++){
for(int l=0;l<flag;l++){
C[i][0][l]=E[i][0][l];
}
}
/*if(k==7){
for(int i=0;i<=k;i++){
printf("%d ",C[i][0][1]);
}
}*/
//给Temp赋值
for(int i=0;i<flag;i++){
Temp[i]=PM[i];
}
//赋值
for(int l=0;l<flag;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
Q[i][j][l]=P[i][j][l/2];
}
}
}
for(int l=0;l<flag;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
P[i][j][l]=Q[i][j][l];
}
}
}
/* if(k==9){
printf("%.2f ",P[9][1][1]);
}*/
}
else{//大于2*L 进行删分枝操作
for(int i=0;i<flag/2;i++){
delta[i]=g(P[k-1][1][i],P[k][1][i],C[k-1][0][i]);
// printf("%.2f ",delta[i]);
}
for(int l=0;l<flag;l++){
if(l%2==0){
C[k][0][l]=0;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
else{
C[k][0][l]=1;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
//
}
//开始删分枝
int D[2*L];
int D_1[2*L];
for(int i=0;i<2*L;i++){
D[i]=i;
}
//排序
sort(PM,2*L,D);
for(int i=0;i<flag;i++){
D_1[i]=D[i];
//printf("%d ",D_1[i]);
}
for(int i=0;i<2*L;i++){
Temp[i]=PM[i];
}
for(int i=0;i<k;i++){
for(int l=0;l<L;l++){
E[i][0][l]=C[i][0][D_1[l]/2];
}
}
for(int i=0;i<k;i++){
for(int l=0;l<L;l++){
C[i][0][l]=E[i][0][l];
}
}
for(int l=0;l<L;l++){
E[k][0][l]=C[k][0][D[l]];
}
for(int l=0;l<L;l++){
C[k][0][l]=E[k][0][l];
}
//交换P数值的值
for(int l=0;l<flag/2;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
Q[i][j][l]=P[i][j][D[l]/2];
}
}
}
for(int l=0;l<flag/2;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
P[i][j][l]=Q[i][j][l];
}
}
}
flag/=2;
}
}
//mod运算操作如下
int n1=pow(2,A[k]);
int n2=n1;
for(int j=0;j<A[k];j++){
for(int e=k-n1+1;e<=k;e=e+(2*n1)/n2){
for(int i=e;i<e+n1/n2;i++){
for(int l=0;l<flag;l++){
C[i][j+1][l]=(C[i][j][l]+C[i+n1/n2][j][l])%2;
C[i+n1/n2][j+1][l]=C[i+n1/n2][j][l];
}
}
}
n2/=2;
}
}
else{//偶数 g+f运算
//printf("%d \n",flag);
int num3=B[k];
int j=num3;
int num4=pow(2,num3);
for(int r=0;r<num4;r++){
for(int l=0;l<flag;l++){
P[k+r][j][l]=g(P[k-num4+r][j+1][l],P[k+r][j+1][l],C[k-num4+r][j][l]);
}
}
/* if(k==8){
for(int i=0;i<8;i++){
printf("%.2f ",P[i+8][3][1]);
}
}*/
//f运算
for(int y=0;y<flag;y++){
for(int q=j;q>0;q--){
int num5=pow(2,q-1);
for(int i=0;i<num5;i++){
P[k+i][q-1][y]=f(P[k+i][q][y], P[k + num5+i][q][y]);
}
}
}
/* if(k==10){
for(int i=0;i<flag;i++){
printf("%.2f ",P[k][1][i]);
}
}*/
//判断是否为冻结比特
if(!CBR[k]){
for(int l=0;l<flag;l++){
C[k][0][l]=0;
if(C[k][0][l]==sign(P[k][0][l])){
PM[l]=Temp[l];
}
else{
PM[l]=Temp[l]+fabs(P[k][0][l]);
}
}
for(int i=0;i<flag;i++){
Temp[i]=PM[i];
}
}
else{//信息位 需要展开
flag*=2;
if(flag<2*L){//小于2*L
for(int i=0;i<flag/2;i++){
delta[i]=P[k][0][i];
}
for(int l=0;l<flag;l++){
if(l%2==0){
C[k][0][l]=0;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
else{
C[k][0][l]=1;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
}
for(int i=0;i<k;i++){
for(int l=0;l<flag;l++){
E[i][0][l]=C[i][0][l/2];
}
}
for(int i=0;i<k;i++){
for(int l=0;l<flag;l++){
C[i][0][l]=E[i][0][l];
}
}
//给Temp赋值
for(int i=0;i<flag;i++){
Temp[i]=PM[i];
}
//赋值
for(int l=0;l<flag;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
Q[i][j][l]=P[i][j][l/2];
}
}
}
for(int l=0;l<flag;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
P[i][j][l]=Q[i][j][l];
}
}
}
}
else{//路径大于2*L 进行删分枝操作
for(int i=0;i<flag/2;i++){
delta[i]=P[k][0][i];
}
/* if(k==10){
for(int i=0;i<flag/2;i++){
printf("%.2f ",delta[i]);
}
}*/
for(int l=0;l<flag;l++){
if(l%2==0){
C[k][0][l]=0;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
else{
C[k][0][l]=1;
if(C[k][0][l]==sign(delta[l/2])){
PM[l]=Temp[l/2];
}
else{
PM[l]=Temp[l/2]+fabs(delta[l/2]);
}
}
}
//开始删分枝
int D[2*L];
int D_1[2*L];
for(int i=0;i<2*L;i++){
D[i]=i;
}
//排序
sort(PM,2*L,D);
for(int i=0;i<2*L;i++){
Temp[i]=PM[i];
//printf("%.2f ",Temp[i]);
}
for(int i=0;i<flag;i++){
D_1[i]=D[i];
// printf("%d ",D_1[i]);
}
//删分枝+排序C数组
for(int i=0;i<k;i++){
for(int l=0;l<flag/2;l++){
E[i][0][l]=C[i][0][D_1[l]/2];
}
}
for(int i=0;i<k;i++){
for(int l=0;l<flag/2;l++){
C[i][0][l]=E[i][0][l];
}
}
for(int l=0;l<flag/2;l++){
E[k][0][l]=C[k][0][D[l]];
}
for(int l=0;l<flag;l++){
C[k][0][l]=E[k][0][l];
}
//重新赋值P数组的值
for(int l=0;l<flag/2;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
Q[i][j][l]=P[i][j][D[l]/2];
}
}
}
for(int l=0;l<flag/2;l++){
for(int j=1;j<=n;j++){
for(int i=0;i<N;i++){
P[i][j][l]=Q[i][j][l];
}
}
}
flag/=2;
}
}
}
// printf("%.2f ",PM[1]);
}
/*for(int i=0;i<N;i++){
printf("%d ",C[i][0][0]);
}*/
int *u_d;
u_d=(int*)malloc(sizeof(int)*N);
for(int i=0;i<N;i++){
u_d[i]=C[i][0][0];
}
return u_d;
}
//f函数
double f(double a, double b) {
double z = a * b > 0 ? 1 : -1;
z = fmin(fabs(a), fabs(b)) * z;
return z;
}
//g函数
double g(double a, double b, int c) {
return (1 - 2 * c) * a + b;
}
//sign函数
int sign(double a){
if(a>0){
return 0;
}
else{
return 1;
}
}
//排序
void sort(double *a,int length,int *b){
double temp1;
int temp2;//序号
for(int j=0;j<length;j++){
for(int i=0;i<length-1-j;i++){
if(a[i]>a[i+1]){
temp1=a[i];
a[i]=a[i+1];
a[i+1]=temp1;
//
temp2=b[i];
b[i]=b[i+1];
b[i+1]=temp2;
}
}
}
}
//接口函数
/*void mexFunction (int nlhs,mxArray *plhs[] ,int nrhs,const mxArray *prhs[]){
//与matlab中function类似
//右边输入需要四个参数、分别是11r、CBR(冻结比特)、N、n(log2(N))
double *a=mxGetPr(prhs[0]);
double *CB=mxGetPr(prhs[1]);
int N=mxGetScalar(prhs[2]);
int n=mxGetScalar(prhs[3]);
int L=mxGetScalar(prhs[4]);
double *llr=(double*)malloc(sizeof(double)*N);
int *CBR=(int*)malloc(sizeof(int)*N);
for(int i=0;i<N;i++){
llr[i]=a[i];
CBR[i]=(int)CB[i];
}
int *u_d;
u_d=decode(llr,CBR,N,n,L);
plhs[0]=mxCreateDoubleMatrix(1,N, mxREAL);
double *u=mxGetPr(plhs[0]);
for(int i=0;i<N;i++){
u[i]=u_d[i];
}
}*/
matlab仿真代码如下
clc
clear
addpath('GA/')
n=7;%层数
N=2^n;
K=N/2;
SNR=2;
Ns=2^10*1000;%信源比特数
ListSNR=1:5;%信噪比
NListSNR=size(ListSNR,2);%长度
s=randi([0,1],1,Ns);%信源序列
BER1=zeros(1,NListSNR);%存放SC译码误码率
tic
for i=1:NListSNR
snr=ListSNR(i);
%GA构造
count =0;
sigma=10^(-snr/20);
[channels, ~] = GA(sigma, N);
[~, channel_ordered] = sort(channels, 'descend');%降序
info_bits = sort(channel_ordered(1 : K), 'ascend');
frozen_bits = ones(N , 1);
frozen_bits(info_bits) = 0;%把1当成冻结比特
info_bits_logical = logical(mod(frozen_bits + 1, 2))';
CBR=double(info_bits_logical);
xx=CBR;
%sigma=10^(-snr/20);
for j=1:Ns/K
u=s(1+(j-1)*K:K*j);%每K个为一组
for l=1:K
xx(info_bits(l))=u(l);
end
%编码
%uu=mod(xx*G(n),2);
uu=encode(xx);
%调制
u1=1-2*uu;
%加噪
% nn=randn(1,N);
% nn1=nn*sigma;
% %叠加
% y=u1+nn1;
%%%%%%%%%%%%%%%%%%%%%%%%%%%PLC信道%%%%%%%%%%%%%%%%%%%
% A=0.1;
% T=0.1;
% sigma_B=1/(2*0.5*snr)/(1+T);
% sigma_I=sigma_B/T;
% lambda=A;
% pr=poissrnd(lambda,1,N);
% R1=sqrt(sigma_B)*randn(1,N)+sqrt(sigma_I*pr).*randn(1,N);
% y=u1+R1;
% llr=2*y*min(log10(T)*sigma_B,(1+1/(A*T))*sigma_B)+...
% y/2*abs(log10(T)*sigma_B-(1+1/(A*T))*sigma_B);
%%%%%%%%%%%%%%%%%%awgn%%%%%%%%%%%%%%%%%%%%
y=awgn(u1,snr);
% %转换为对数域
llr=2*y/(sigma^2);
u_d=SCL(llr,CBR,N,n,4);
% u_d=demo(llr,CBR,N,n);
for ll=1:N
if u_d(ll)~=xx(ll)
count=count+1;
end
end
end
BER1(i)=count/(2*Ns);
end
toc
semilogy(ListSNR,BER1,'b-o',LineWidth=1.5);
xlabel("SNR(dB)");
ylabel("BER");
title("N=128,K=64");