手習ひデジタル信号処理(109) Scilab、ゼロ・ビット・インサート、リムーブ

Joseph Halfmoon

このところビット列、バイト列の生成、復元などを練習しており、前回は巡回冗長検査(CRC)でした。今回はHDLC(High-Level Data Link Control)などで使われるゼロビット・インサーションとリムーバルを練習してみたいと思います。「原理」実装は動いた、けれども分量が多いとダメだなこれは。どうする?

※「手習ひデジタル信号処理」投稿順 Indexはこちら

※Windows11上で、Scilab6.1.1およびScilab上のツールボックス Scilab Communication Toolbox 0.3.1(以下comm_tbx)を使用させていただいとります。

ゼロビット挿入

0と1のビット列が長くなってくると、連続して1や0のシーケンスが出現する確率も当然上がってきます。通信の元祖か御本家か?HDLCでは、ヘッダ(1が7個連続したもの)とそうでないデータを識別するために、データ部分では1が5個連続したらば次に0を挿入して5個以上続かないようにする「仕組み」が求められています。当然「ゼロビット挿入」されたビット列から元のデータ列を復元する場合には、上の逆で1が5個連続した後の0は挿入された0なので取り除く操作が必要です。

ゼロビット挿入の自前Scilab関数

0と1のビット列(行ベクトル)のために作成した自前関数(効率悪いので「原理実装」じゃといいわけ)が以下に。第一引数に01の行ベクトル、第2引数に検出する1の連続数を与えるもの(HDLCの場合は5を与える。)

// zero-bit insertion (by J.Halfmoon Nov. 30, 2023)
// blis: bit data list
// cone: number of consecutive 1s to detect
// b: bit data list(zero-bit inserted)
function b=zeroBitIns(blis, cone)
  b = []
  counter = 0
  for bi = blis do
    if bi == 0 then
      counter = 0
      b = [b 0]
    else
      counter = counter + 1
      if counter == cone then
          counter = 0
          b = [b 1 0]
      else
          b = [b 1]
      end
    end
  end
endfunction
ゼロビット削除の自前Scilab関数

上記で生成したゼロビット挿入されたビット列(行ベクトル)から挿入されたゼロビットを削除して元に戻す自前関数(これまた効率悪いので「原理実装」じゃといいわけ)が以下に。

// zero-bit Removal (by J.Halfmoon Nov. 30, 2023)
// blis: bit data list(zero-bit inserted)
// cone: number of consecutive 1s to detect
// b: bit data list(zero-bit removed)
// err: error flag
function [b, err]=zeroBitRem(blis, cone)
  err = %f
  b = []
  counter = 0
  for bi = blis do
    if counter == cone then
      if bi==1 then
        err = %t
        counter = 1
        b = [b 1]
      else
        counter = 0
      end
    else
      if bi == 0 then
        b = [b 0]
        counter = 0
      else
        b = [b 1]
        counter = counter + 1
      end
    end
  end
endfunction
動作検証と問題点

上記の挿入、削除関数と、過去回で作成したビット列の比較関数を使って短いパターンで動作検証してみるコードが以下に。

a = [1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0]
b = zeroBitIns(a, 5)
[c, err] = zeroBitRem(b, 5)
[nerr, ber, flag] = calcBER(a, c)

上記を実際に実験したものが以下に。zeroinsertTest0

ちゃんと0挿入され、そして元に戻っておるようです。

今度は少し長いランダムシーケンスに対して処理する場合。なお、ランダムビット列生成に使っているcomm_tbxのprbs()関数は列ベクトルを返すので「転置」してます。

d=prbs(1000);
e=zeroBitIns(d', 5);
length(e)
[f, err] = zeroBitRem(e, 5);
length(f)
[nerr, ber, flag] = calcBER(d', f)

実行結果は以下に。zeroinsertTest1a

挿入して削除して元に戻ったようです。

1000個くらいのビットであれば全然問題なく動いているように見える。けど調子に乗って100万ビット食わせてみたら全然戻ってこないです。double型のデータ100万個、たかだか8Mバイトっす。でも「ズボラなリスト処理」をしているせいで、リストの挿入やら削除やらの手間がとっても大きいのだと思います。まあ、実際にHDLCするならScilabでやらんか。。。どうする?

手習ひデジタル信号処理(108) Scilab、CRC8の計算、Pythonから移植 へ戻る

手習ひデジタル信号処理(110) Scilab、包絡線検波の自前関数作成 へ進む