卷積碼

3. 卷積碼

卷積碼指Convolutional Code宇整。

卷積碼连舍,將k位信息編碼成n位(當前組),這n個bit的生成不僅和這k位有關盼玄,還和之前的N-1個組的信息有關潜腻∪诨粒總共關聯的有N * n 個bit。 我們一般記為 (n,k,N) 卷積碼 剃斧。

可以看出來忽你,當N增加時,糾錯能力也增加根蟹,差錯率隨著N增大而指數下降。我們記N為卷積碼的約束長度球散。

編碼

(n,k,N) 卷積碼由下面部分組成散庶。

  • N組k級輸入移位寄存器 (一個長度為N * k 的存儲空間,理解成一維數組接收數據輸入嘁灯,或理解成N * k 的二維數組暫存狀態(tài)信息)
  • n級輸出移位寄存器 和 n個模二加法器 (每一級輸出寄存器對應一個加法器)
image

如上圖,每個異或(模二加法器)對應的輸入是輸入序列(N組k級寄存器)中的某些特定位性雄。這些位是在編碼中固定的秒旋。卷積碼的生成矩陣就是在描述 N * K 位輸入移位寄存器和每個模二加法器的連接關系。

一開始輸入寄存器里全是0. 然后第一組k個bit輸入煤蚌,接著輸出n個bit细卧,再接著輸入第二組bit,再輸出第二組bit ...

一般來說蜘犁,卷積碼都是 (n,1,N) 的形式止邮。在閱讀了一些論文發(fā)現采用的都是 (2,1,N) 的形式导披,如(2,1,3),(2,1,6)等 (為什么)
很明顯,當k=1時撩匕,每一個bit都要編碼成n個bit去傳輸,流量 * n. 所以n不能太大并村,2哩牍、3可能就已經是極限。

libcorrect 的編碼實現

我們可以對 https://github.com/quiet/libcorrect 的源碼做分析丸边。

// \src\convolutional\encode.c 

... 
size_t correct_convolutional_encode(correct_convolutional *conv,
                                    const uint8_t *msg,
                                    size_t msg_len,
                                    uint8_t *encoded) {
    ...
    for (size_t i = 0; i < 8 * msg_len; i++) {
            // shiftregister has oldest bits on left, newest on right
            shiftregister <<= 1;
            shiftregister |= bit_reader_read(conv->bit_reader, 1);
            shiftregister &= shiftmask;
            // shift most significant bit from byte and move down one bit at a time
            //  - 移位寄存器左移妹窖,留出空位(右側最低位)存儲新的bit收叶。舊bit在最高位通過掩碼shiftmask完成刪除。 shiftmask = (1 << conv->order) - 1;


            // we do direct lookup of our convolutional output here
            // all of the bits from this convolution are stored in this row
            unsigned int out = conv->table[shiftregister];
            bit_writer_write(conv->bit_writer, out, conv->rate);
            // 注意到完成多次模二加法(異或)也是需要時間的,改用查表即可蜓萄。預先將結果放在table里即可澄峰。
        }

注意到上面代碼中的 *conv 俏竞,是一個卷積對象,我們可以進入其頭文件查看相關的定義玻佩。


// \include\correct\convolutional\convolutional.h
struct correct_convolutional {  
    const unsigned int *table;  // size 2**order 
    // 空間換時間漱牵,因為是N個bit,所以對應2^N個空間
    size_t rate;                // e.g. 2, 3... 
    // 明顯的刁赦,這里的rate 指的是 (n,1,N) 中的n, 即模二加法器的個數 或是每次編碼的bit數
    
    size_t order;               // e.g. 7, 9... 
    // 明顯的, 這里的order 指的是 (n,1,N) 中的N甚脉,即狀態(tài)寄存器的個數铆农。又因為
    unsigned int numstates;     // 2**order
    
    bit_writer_t *bit_writer;
    bit_reader_t *bit_reader;
    // 讀寫操作
    ...
};

考慮如何預填寫table狡耻。


// src\convolutional\lookup.c
void fill_table(unsigned int rate,
                unsigned int order,
                const polynomial_t *poly, // 每個模二加法器的輸入位關聯關系可以用一個多項式來表示夷狰,
                unsigned int *table) {
    for (shift_register_t i = 0; i < 1 << order; i++) { // N位bit從全0到全1郊霎,用i循環(huán)來表示
        unsigned int out = 0;
        unsigned int mask = 1;
        for (size_t j = 0; j < rate; j++) {
            out |= (popcount(i & poly[j]) % 2) ? mask : 0;
            /*
                注意到模二加法器的多項式本質上是一個系數只有0和1的式子
                所以我們可以用一個二進制串(整數)來表示這個多項式
                那么rate(n)個加法器對應著n個整數书劝,存儲在poly[]數組里
                
                tmp = i&poly[j] 
                tmp 表示i狀態(tài)對第j個模二加法器運算后的每一位串聯的結果
                但是我們想要的是每一位的異或,所以本質上還是要tmp的每一位異或起來
                
                可以統(tǒng)計tmp中1的個數猾昆,若為偶數個則異或結果為0.
                統(tǒng)計個數可以用popcount函數骡苞。這是一個魔法函數,能O(1)算出來。
                利用mask放到out對應的位上么抗。從低位到高位,依次對應的是j個加法器螟加。
            */
            mask <<= 1;
        }
        table[i] = out;
    }
}

這說明這里實現的是一個(n,1,N)的卷積碼編碼捆探。

樹狀圖 網格圖

樹狀圖與網格圖可以直觀的體現所有碼字的可能性,更可以幫助設計解碼算法曾雕。

由于k=1助被,每次新輸入一個bit,取值只能為0或1搔弄,所以我們可以將 前N-1個 寄存器串聯看成一個狀態(tài)節(jié)點丰滑,根據新輸入的不同可得兩個分叉,分別對應兩個新的狀態(tài)節(jié)點... 如此往復炫刷,可以構造出一個二叉狀態(tài)樹浑玛。(其實是每次輸入k個bit,對應一個節(jié)點有 2^k 個分叉 )

以(2,1,3) 卷積碼為例

1.png

如上圖失晴,寄存器初始狀態(tài)全為0拘央,所以狀態(tài)根節(jié)點a=00.

如果此時輸入的新bit為0,則下一步狀態(tài)節(jié)點還是a=00 拆又,但如果輸入的是1栏账,則下一步狀態(tài)節(jié)點就變成b=01.(從保存數據最舊的寄存器開始看,或者說從右往左記錄為狀態(tài)) 同理類推竖般。因為是前N-1個茶鹃,所以總共可能出現的狀態(tài)就 2^{k(N-1)} 種闭翩,之后的狀態(tài)必定是循環(huán)回去了。

2.png

注意上圖的樹邊兑障,所標記的數字表示的是輸出流译。即在當前這個狀態(tài)下肤无,根據新輸入bit的不同而輸出的不同宛渐。

例如a=00狀態(tài)時眯搭,輸入的新比特為0鳞仙,三個寄存器全為0的輸出是"00"笔时。 再例如狀態(tài)b=01,如果新比特輸入的是0 (即010)借笙,輸出是10较锡;若新比特輸入的是1(即011)蚂蕴,輸出的是01。(輸出從左往右看熔号,這是根據加法器編號從小到大來看的)鸟整。

同理,我們只需要保證每個狀態(tài)以及其后續(xù)變化都出現過就行了吃嘿,所以像樹的上方遞歸3層的a狀態(tài)可以省略不畫兑燥,因為本質上是一樣的琴拧。

3.png

我們可以將同種狀態(tài)剝離合并(同狀態(tài)的后續(xù)變化過程與之前狀態(tài)無關)蚓胸,畫成網格形式。

4.png

網格圖內每一次的狀態(tài)變化被稱為“一節(jié)”扔枫。像右邊的紅框內每一次狀態(tài)可能變化都是一樣的短荐,被稱為穩(wěn)態(tài)。根據網格圖可以進行編碼痕貌。如輸入的bit依次是1100糠排,則經過狀態(tài)分別是abdcb,輸出11010100哺徊。

譯碼

卷積碼有多種譯碼算法乾闰,如維特比譯碼(Viterbi decoding algorithm)汹忠,序列譯碼,門限譯碼等谣膳。其中維特比譯碼性能是接近最優(yōu)的铅乡,但實現起來也很復雜。 libcorrect 也是用的維特比譯碼算法花履,這里著重介紹這個算法挚赊。

先考慮網格圖譯碼過程荠割。例如接受的碼字是11010100,我們可以根據網格圖進行對比夺克『啃啵可以直接得出結果哟忍。

5.png

如果出現誤碼陷寝,我們可以選擇與接收序列更接近的一種變化繼續(xù)下去盼铁。但也可能出現所有變化都等距的情況(例如收到的是10尝偎,兩個變化分別是00和11)致扯。一種樸素的想法是:考慮往后幾步的多種變化,再選最小距離的鲤看。然而這會導致延時與性能問題耍群,故引入到維特比譯碼算法蹈垢。

維特比算法是基于最大似然譯碼算法(通過概率推導出應該是哪個碼最接近),(通過一陣復雜的概率公式推導得出)在這里它等效于最小距離譯碼溉瓶。

記狀態(tài)變化的路徑量度(可理解成一條邊的權值)為該路徑輸出與收到序列之間的距離谤民。(一般是漢明距離)张足。整條路徑的路徑量度是各邊的權值和。

維特比算法是一種類似 動態(tài)規(guī)劃思想 的算法嗅榕。本質上是用動態(tài)規(guī)劃在這個特殊圖上求最短路問題吵聪。

  1. 初始狀態(tài)為 a=00
  2. 當前是第i步譯碼吟逝,前i-1步譯碼后停留在狀態(tài)j時的最小路徑度量值是f[i-1][j]
  3. 考慮f[i][j]的變化赦肋。選擇一個可以使f[i][j]值最小的狀態(tài)j',由其狀態(tài)j'變化而來囱井。
  4. 每種狀態(tài)都確定好之前由哪一個狀態(tài)變化而來庞呕,也意味著有多少個狀態(tài)就有多少個不同的路徑。這些路徑被稱為“幸存路徑”
  5. 若幸存路徑中有相同重疊的部分地啰,則可以直接輸出這部分(作為部分譯碼結果)亏吝。
  6. 若譯碼未結束返回到第2步盏混。若譯碼結束且有多種相同度量值的路徑可供選擇,則隨機選擇一種止喷。否則選擇度量值最小的那個路徑启盛。

例如:

6.png
  1. 接收的第一段是11僵闯,一開始狀態(tài) a藤滥,可能的兩種變化分別是:
  • 輸出00 到狀態(tài)a (aa,累計路徑度量 = 2)
  • 輸出11 到狀態(tài)b (ab向图,累計路徑度量 = 0)

注意到這里兩條路徑(aa,ab)都是“幸存路徑”标沪,且沒有重合部分金句,所以繼續(xù)譯碼。

  1. 接收的第二段是01贞瞒,在第一步之后的兩個幸存路徑分別對應狀態(tài)是aa,ab.
  • aa狀態(tài)
    • 輸出00,到狀態(tài)a(aaa棕洋,累計路徑度量=2+1=3)
    • 輸出11掰盘,到狀態(tài)b(aab簇抵,累計路徑度量=2+1=3)
  • ab狀態(tài)
    • 輸出10碟摆,到狀態(tài)c(abc, 累計路徑度量=0+2=2)
    • 輸出01断盛,到狀態(tài)d(abd,累計路徑度量=0+0=0)

如下圖左側

7.png

到譯碼第三段時愉舔,可以發(fā)現:f[3][a]即第三段譯碼后狀態(tài)是a的可能性有兩種钢猛,即 aaa-aabc-a,分別對應路徑度量值是4和3轩缤。所以這里保留abc-a這條路路徑命迈,而不是aaa-a

同理火的,其他狀態(tài)經過同樣操作后壶愤,剩余的幸存路徑都用紅色標出。他們有重合部分即最開始的 a-b馏鹤,對應的譯碼結果是1。而最開始的a-a 路徑分支就被舍棄了湃累。

8.png

到譯碼第四段 接收到10時勃救,也有如下變化,最后每種狀態(tài)保留一條幸存路徑治力。注意蒙秒,在上一步輸出譯碼為1后,這四條幸存路徑并沒有新的重合部分宵统。 所以需要繼續(xù)讀取并進行譯碼税肪。

最后結果如下:

9.png

注意到最后四條路徑里以d狀態(tài)結尾的轉移路徑的度量值最低,所以選擇這條路徑做為譯碼結果。即11001111. 并且這也可以推出是第4段和第7段產生了誤碼益兄。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市箭券,隨后出現的幾起案子净捅,更是在濱河造成了極大的恐慌,老刑警劉巖辩块,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛔六,死亡現場離奇詭異,居然都是意外死亡废亭,警方通過查閱死者的電腦和手機国章,發(fā)現死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豆村,“玉大人液兽,你說我怎么就攤上這事≌贫” “怎么了四啰?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長粗恢。 經常有香客問我柑晒,道長,這世上最難降的妖魔是什么眷射? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任匙赞,我火速辦了婚禮,結果婚禮上妖碉,老公的妹妹穿的比我還像新娘涌庭。我一直安慰自己,他們只是感情好嗅绸,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布脾猛。 她就那樣靜靜地躺著,像睡著了一般鱼鸠。 火紅的嫁衣襯著肌膚如雪猛拴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天蚀狰,我揣著相機與錄音愉昆,去河邊找鬼。 笑死麻蹋,一個胖子當著我的面吹牛跛溉,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼芳室,長吁一口氣:“原來是場噩夢啊……” “哼专肪!你這毒婦竟也來了?” 一聲冷哼從身側響起堪侯,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嚎尤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伍宦,有當地人在樹林里發(fā)現了一具尸體芽死,經...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年次洼,在試婚紗的時候發(fā)現自己被綠了关贵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡卖毁,死狀恐怖揖曾,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情势篡,我是刑警寧澤翩肌,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站禁悠,受9級特大地震影響念祭,放射性物質發(fā)生泄漏。R本人自食惡果不足惜碍侦,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一粱坤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓷产,春花似錦站玄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尔邓,卻和暖如春晾剖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梯嗽。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工齿尽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灯节。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓循头,卻偏偏與公主長得像绵估,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卡骂,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內容