暢談無線通信系統物理層之CRC(三)實現方式之逐比特計算法、並行計算法

四、實現方式

實現方式主要有逐比特計算法、並行計算法和查表法,逐比特計算法有2種方法,第一種是按照標準除法流程進行計算,第二種是按照標準除法等效的移位寄存器進行計算;並行計算法是一次進行多位bit的CRC計算,通過多位bit串聯的CRC計算公式得到整個發送序列的CRC;查表法把整個發送序列的CRC值存在一張表中,通過查詢即可得到CRC,發送序列太大時需要巨大的存儲空間,所以這種方法只適用於發送序列較短的情況,或者可以作爲並行計算算法的一部分,在進行多位bit的CRC計算時使用查表法,查表法不再敘述。

a)逐比特計算法

按照標準除法流程進行計算時的算法如下:

(1)在待傳輸的k比特數據後面加入(n-k)個0,即x^(n-k)M(x)

(2)取x^(n-k)M(x)的前(n-k+1)個數作餘式r(x)的初始值

(3)While (數據未處理完),次數爲k次

 Begin

        If (r(x)首位是1)

            r(x)= r(x)XOR g(x)

     else

          r(x)= r(x)

       end

         r(x)寄存器左移一位,按順序讀入一個新的x^(n-k)M(x)數據於r(x)寄存器的0 bit的位置。

  End

(4)  r(x)寄存器就是我們所要求的餘數。

MATLAB腳本程序如下:

function crc_out = CRC_direct(g,din,InitialState,FinalXOR)  %%% g:生成多項式,din:數據輸入
lg = length(g);      %%%%% g(x)的長度,爲n-k+1
ld = length(din);     %%%%%%M(x)的長度,爲k
din_addzeros = [din;zeros(lg,1)];  %%%%%在待傳輸的k比特數據後面加入(n-k+1)
%%個0,多加一個是爲了爲後一步時,r(x)的長度保持爲n-k+1
r = din_addzeros(1:lg);  %%%%%取x^(n-k)M(x)的前(n-k+1)個數作餘式r(x)的初始值
r(1:lg-1) = mod(din_addzeros(1:lg-1) +InitialState.',2) ;%%% r(x)的初始值和輸入初始值異或
for ii=1:ld                           %%%%次數爲k次 
    if r(1) ==0                       %%%If (r(x)首位是0)
        r(1:lg-1) = r(2:lg);             %%% r(x)寄存器左移一位
        r(lg)=din_addzeros(ii+lg);       %%%%讀入一個新的x^(n-k)M(x)數據
    else                             %%%If (r(x)首位是1)  
        r(1:lg-1) = mod(r(2:lg) + g(2:lg).',2); %%% r(x)= r(x)XOR g(x),首位爲0,移除
        r(lg)=din_addzeros(ii+lg);         %%%%讀入一個新的x^(n-k)M(x)數據
    end
end
r(1:lg-1) =mod(r(1:lg-1) + FinalXOR.',2);           %%%與“結果異或值”進行異或
crc_out = [din;r(1:lg-1)];             %%%組成信息序列和CRC值

按照標準除法等效的移位寄存器進行計算的算法結構如下圖所示:

算法流程如下:

(1) 設置CRC寄存器,如果有初值,並給其賦值爲“餘數初始值”;

(2) 將M(x)的第一個bit 與CRC寄存器最高位進行異或,該結果與g(x)的最低位到次高位進行相乘(g(x)的階數比CRC高一階,所以長度與CRC相同),記爲rd,CRC寄存器最低位添0,向高位移位,在和rd異或後成爲新的CRC寄存器;

(3)      M(x)下一個bit進行(2)操作;

(4)      M(x)最後一個bit進行(2)操作後,CRC寄存器即爲CRC值;

(5)      最終CRC寄存器的內容與“結果異或值”進行或非操作後即爲最終的CRC值。

原理閱了Peterson和Brown寫的《Cyclic Codes for Error Detection》,除法如下圖:

可以把輸入數據拆開進行等效計算,輸入數據爲[1 1 1 0 1 0],如下所示,

[1 1 1 0 1 0] =[1 0 0 0 0 0 ] + [0 1 0 0 0 0] + [0 0 1 0 0 0] + [0 0 0 0 0 0] +

[0 0 0 0 1 0]  + [0 0 0 0 0 0]

 第一個先求[1 0 0 0 0 0 ]的餘式,初始餘式爲全0,場景回到上一個餘式,即此時的餘式爲全0,記爲rx0=[0 0],rx0和[1 0 0 0 0 0 ]的高2位[1 0]異或後即爲下一個餘式的高2位[1 0],場景回到當前,[1 0]添0爲[1 0 0],再處以[1 0 1],此時商1,[1 0 0]異或[1 0 1],餘式爲[0 0 1],高位捨棄,餘式爲[ 0 1],即[1 0 0 0 0 0 ]的最終餘式爲[0 1];

第二個求[0 1 0 0 0 0 ]的餘式,上一個餘式爲[0 1],場景回到上一個餘式,記爲rx1=[0 1],rx1和[0 1 0 0 0 0 ]的2位[1 0]異或後即爲下一個餘式的高2位[1 1],場景回到當前,[1 1]添0爲[1 1 0],再處以[1 0 1],此時商1,[1 1 0]異或[1 0 1],餘式爲[0 1 1],高位捨棄,餘式爲[ 1 1],即[0 1 0 0 0 0 ]的餘式爲[11];

第三個求[0 0 1 0 0 0 ]的餘式,上一個餘式爲[1 1],場景回到上一個餘式,記爲rx2=[1 1],rx2和[0 0 1 0 0 0 ]的2位[1 0]異或後即爲下一個餘式的高2位[0 1],場景回到當前,[0 1]添0爲[0 1 0],再處以[1 0 1],此時商0,[0 1 0]異或[0 0 0],餘式爲[0 1 0],高位捨棄,餘式爲[1 0],即[0 0 1 0 0 0 ]的餘式爲[10];     

以此類推,所以當前的輸入與上一個的餘式最高位的異或決定了當前的商值,異或爲1,商爲1,異或爲0,商爲0。

https://blog.csdn.net/u011639609/article/details/51464773中有過解釋,參考如下圖,g(x)=x3+x2+1。

信息序列還是1001,初始狀態時,D1~D3三個寄存器的值都爲0,輸入的第一個信息比特是1,與D3的異或是1,這裏爲什麼輸入序列與D3做異或呢?其實這裏隱含了一個選擇操作,D1~D3代表當前的餘式,D3表示餘式的最高位。

場景回到上一個餘式,此時,D3爲上一個餘式的次高位,上一個餘式計算時,次高位與當前的下一個輸入的異或值,即爲下一個餘式的初始的最高位,若最高位爲1,下一個商爲1,若最高位爲0,下一個商爲0。

場景回到當前,所以如果當前的輸入與餘式最高位D3相同的話,則當前輸入與餘式的模2加爲0,即當前輸入更新使得餘式最高位爲0,則此時商上面上0,不用對生成多項式做模2加運算,餘式只要右移一位完成餘式的更新操作(一個比特與0異或等於自身,所以這種情況下,電路中異或不起作用);另一種情況是,餘式最高位D3與當前輸入序列異或爲1,表示當前輸入更新後餘式包含最高位,需要對生成多項式求餘,求餘操作通過電路中的異或進行,完成D1~D3的更新。具體步驟如下:

 (1) 初始狀態:輸入ui             D1    D2    D3            輸出uo

                                        0       0        0

        (2)               1                     1       0        1                         1

        (3)                0                     1       1        1                         0

        (4)                0                     1       1        0                         0

        (5)                1                     1       1        0                         1

        D1~D3剩下的011即爲監督比特,剩下3拍,逐比特輸出:

        (6)               0                     0       1        1                         0

        (7)               0                     0       0        1                         1

        (8)               0                     0       0        0                         1

MATLAB腳本程序如下:

function crc_out = CRC_direct_LFSR(g,din,InitialState,FinalXOR)
lg = length(g);  
ld = length(din);
r = InitialState.';   %%%初始化
for ii=1:ld 
    rd = mod(r(1) + din(ii),2); %%%當前的輸入與上一個的餘式最高位的異或
    r(1:lg-2) = mod(r(2:lg-1) + rd*g(2:lg-1).',2); %%%按g(x)的多項式更新
    r(lg-1)=rd;    %%%%最低位爲rd
end
 r(1:lg-1) =mod(r(1:lg-1) + FinalXOR.',2);
crc_out = [din;r(1:lg-1)]; 

按照標準除法等效的移位寄存器進行計算的算法還有一種結構,如下圖所示:

b)並行計算法

並行計算法是一次進行多位bit的CRC計算,通過多位bit串聯的CRC計算公式得到整個發送序列的CRC,多位bit可以爲4位、8位或者16位。

以16位CRC爲例介紹,如果要計算16位CRC,如下2種方式:

  • 一次可以進行8位CRC計算,再通過8位bit串聯的CRC計算公式得到整個發送序列的CRC;
  • 一次可以進行16位CRC計算,計算方法即爲正常CRC的方法:將本組CRC的值和下一組16位數據值異或後,重新計算得到下一組的CRC值,順序執行即可得到整個發送序列的CRC;

8位bit的CRC計算值可以查表得到,用逐比特計算法計算得到表值 ;

8位bit串聯的CRC計算公式如下,參見《通信系統中的CRC算法的研究和工程實現_廖海紅》:

MATLAB腳本程序如下:

function crc_out = CRC_Paraller16_8(g,din,InitialState,FinalXOR,direct)
lg = length(g);
ld = length(din);
din(1:lg-1) = mod(din(1:lg-1) +InitialState.',2) ;
M = 8;
Num = ld/M;
    din_1 = din(1:M);  %%%第一組8bit
      if direct == 1
        r_M(:,1) = CRC_direct_LFSR(g,din_1,zeros(1,lg-1),FinalXOR);%%%直接法
      else
        r_M(:,1) = CRC_table(din_1);      %%%查表法
      end
    r = r_M(end-lg+2:end,1);
for ii=2:Num    %%%第二組到最後一組8bit
     rL = [r(9:16);zeros(8,1)];  %%低8位左移
     din_ii= mod(din(ii*M-M+1:ii*M) +r(1:8),2) ; %%取高8位
      if direct == 1
        r_M(:,ii) = CRC_direct_LFSR(g,din_ii,zeros(1,lg-1),FinalXOR); %%%直接法
     else
        r_M(:,1) =  CRC_table(din_1) ;   %%%查表法
      end   
    r = mod(rL + r_M(end-lg+2:end,ii),2);   %%%相加
end
 r(1:lg-1) =mod(r(1:lg-1) + FinalXOR.',2);
crc_out = [din;r(1:lg-1)];

獨立16位bit的CRC計算公式可以根據生成多項式進行推導或者查表得到。

根據生成多項式進行推導16位bit的CRC計算公式的結構如下圖所示:

對應的MATLAB腳本程序(在Zhao Baozhu的基礎上修改的)如下:

para =16;   %%%%並行位數
gen = [1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1];  %%%生成多項式,x^16+x^15+x^2+1
crc_value = [diag(ones(1,length(gen)-1)),zeros(length(gen)-1,para)];%%%初始值
%%%%%% crc_value含義:第1行爲CRC新值0的表達式,其中前16bit爲CRC舊值,從低到高依次爲CRC舊值0,1,…15,爲1表示需要異或,爲0表示不需要異或,17-32bit爲輸入bit,分別爲d0,d1,…d15,d15表示第1個輸入,d15表示第16個輸入,依次類推,第2行爲CRC新值1的表達式,…,第16行爲CRC新值15的表達式。所以前16*16矩陣爲diag,後16*16爲全0,表示初始值。
%%%%%%
%%%%%%
    for i=1:para   
        dataXORcrc_value_end = crc_value(length(gen)-1,:);  %%%先取CRC舊值最高位
        dataXORcrc_value_end(length(gen)+para-i) = 1; %%%%輸入bit置爲1,相當於異或
        for j=length(gen)-1:-1:2             %%%%%%必須逆序,先把高位置爲新值
            if gen(j)==1
                crc_value(j,:) = crc_value(j-1,:)+dataXORcrc_value_end;
            else
                crc_value(j,:) = crc_value(j-1,:);
            end
        end
        crc_value(1,:) = dataXORcrc_value_end;
    end
crc_value = mod(crc_value,2);
for i = 1:length(gen)-1
    s=sprintf('crc_new(%d) =',i-1);
    for j = 1:length(gen)+para-1
        if crc_value(i,j) == 1
            if j <length(gen)
                str=sprintf(' crc_old(%d)',j-1);
            else
                str=sprintf(' data_new(%d)',j-length(gen));
            end
            s=strcat(s,' +',str);
        end
    end
    simplepoly{i,1}=s;
end

運行後得到x^16+x^15+x^2+1的CRC16bit並行計算公式如下所示:

其中,crc_new(0) = + crc_old(0) + crc_old(4) + crc_old(8) + crc_old(11) + crc_old(12) + data_new(0) + data_new(4) + data_new(8) + data_new(11) + data_new(12),CRC舊值和data新值的序號一模一樣,所以CRC舊值和data新值可以先進行異或成爲新的data_new,再通過公式算出CRC,公式只取data_new相關的部分,例如:

crc_new(0) = data_new(0) + data_new(4) + data_new(8) + data_new(11) + data_new(12)。

以16位bit爲單位連續bit的CRC計算的MATLAB腳本程序如下:

function crc_out = CRC_Paraller16_16(g,din,InitialState,FinalXOR,direct)
lg = length(g);
ld = length(din);
din(1:lg-1) = mod(din(1:lg-1) +InitialState.',2) ;
M = 16;
Num = ld/M;
    din_1 = din(1:M);  %%%第一組16bit
    if direct == 1
    r_M(:,1) = CRC_direct_LFSR(g,din_1,zeros(1,lg-1),FinalXOR); %%%直接法,也可以用根據生成多項式進行推導的公式或者查表法
    end
    r = r_M(end-lg+2:end,1);
for ii=2:Num 
    din_ii= mod(din(ii*M-M+1:ii*M) +r,2) ;  %%%和上一組的餘式進行相加
    if direct == 1
     r_M(:,ii) = CRC_direct_LFSR(g,din_ii,zeros(1,lg-1),FinalXOR); %%%直接法,也可以用根據生成多項式進行推導的公式或者查表法
    end
    r = r_M(end-lg+2:end,ii);
end
 r(1:lg-1) =mod(r(1:lg-1) + FinalXOR.',2);
crc_out = [din;r(1:lg-1)];

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章