[ Main Page ]

Scilab / Octave 使用例 - M系列と畳み込み

インパルス応答の測定方法の一つとして使われている M系列を題材にScilabやOctaveを使いこなしてみる。後の項目では、前の項目の関数に依存している部分もあるので、最初から順に実行する。

M系列の生成

MLSの生成方法は他に色々なページで述べられているので、ここではScilabとOctaveでの一例を挙げる。 この例では、ScilabとOctaveの両方ともで同じ記述となった。

Scilab

	  function list = mls(n)
	  switch n
	  case 2
	     taps=2;   tap1=1;   tap2=2;
	  case 3
	     taps=2;   tap1=1;   tap2=3;
	  case 4
	     taps=2;   tap1=1;   tap2=4;
	  case 5
	     taps=2;   tap1=2;   tap2=5;
	  case 6
	     taps=2;   tap1=1;   tap2=6;
	  case 7
	     taps=2;   tap1=1;   tap2=7;
	  otherwise
	     disp('input bits not supported (must be between 2~7)');
	     return
	  end

	  buff = ones(1,n);
	  list = zeros(1,2^n-1);

	  for i = (2^n)-1:-1:1
	    xorbit = bitxor(buff(tap1),buff(tap2));
	    buff = [xorbit buff(1:n-1)];
	    list(i) = xorbit;
	  end
	  endfunction

	  mls(3)
	  mls(4)
	
	  --> mls(3)
	   ans  =
	  
	     1.   1.   1.   0.   0.   1.   0.
	  
	  
	  --> mls(4)
	   ans  =
	  
	     1.   1.   1.   1.   0.   0.   0.   1.   0.   0.   1.   1.   0.   1.   0.
	

Octave

	  function list = mls(n)
	  switch n
	  case 2
	     taps=2;   tap1=1;   tap2=2;
	  case 3
	     taps=2;   tap1=1;   tap2=3;
	  case 4
	     taps=2;   tap1=1;   tap2=4;
	  case 5
	     taps=2;   tap1=2;   tap2=5;
	  case 6
	     taps=2;   tap1=1;   tap2=6;
	  case 7
	     taps=2;   tap1=1;   tap2=7;
	  otherwise
	     disp('input bits not supported (must be between 2~7)');
	     return
	  end

	  buff = ones(1,n);
	  list = zeros(1,2^n-1);

	  for i = (2^n)-1:-1:1
	    xorbit = bitxor(buff(tap1),buff(tap2));
	    buff = [xorbit buff(1:n-1)];
	    list(i) = xorbit;
	  end
	  endfunction

	  mls(3)
	  mls(4)
	
	  >> mls(3)
	  ans =
	  
	     1   1   1   0   0   1   0
	  
	  >> mls(4)
	  ans =
	  
	     1   1   1   1   0   0   0   1   0   0   1   1   0   1   0
	

畳み込みの準備とMLS matrixの生成

MLSを順に並べて生成した行列をMLS matrixと呼ぶことがあり、アダマール行列(Hadamard matrix)と似た性質がある。こちらについては別項目を参照。

Scilab

	  // only for n=2,3,4,5
	  function mmat = mlsmatrix(n)
	  seq = mls(n);
	  mmat = zeros((2^n)-1,(2^n)-1);
	  for i = 1:1:(2^n)-1
	    mmat(i,:) = seq;
	    seqd = bin2dec(strcat(string(seq)));
	    seqd = bitand( bitor( seqd*2, int(seqd/2^(2^n-2)) ), (2^(2^n-1))-1);
	    seq = strtod(strsplit(dec2bin( seqd ,(2^n)-1)))'
	  end
	  endfunction
	  
	  mlsmatrix (3)
	
	  --> mlsmatrix (3)
	   ans  =
	  
	     1.   1.   1.   0.   0.   1.   0.
	     1.   1.   0.   0.   1.   0.   1.
	     1.   0.   0.   1.   0.   1.   1.
	     0.   0.   1.   0.   1.   1.   1.
	     0.   1.   0.   1.   1.   1.   0.
	     1.   0.   1.   1.   1.   0.   0.
	     0.   1.   1.   1.   0.   0.   1.
	

Octave

	  function mmat = mlsmatrix(n)
	  seq = mls(n);
	  mmat = zeros((2^n)-1);
	  for i = 1:1:(2^n)-1
	    mmat(i,:) = seq;
	    seqd = bin2dec(char(seq+'0'));
	    seqd = bitand(bitor(bitshift(seqd,1),bitshift(seqd,(2^n-2)*-1)),(2^(2^n-1))-1);
	    seq =  dec2bin(seqd,(2^n)-1)-'0';
	  end
	  endfunction
	  
	  mlsmatrix (3)
	
	  >> mlsmatrix (3)
	  ans =
	  
	     1   1   1   0   0   1   0
	     1   1   0   0   1   0   1
	     1   0   0   1   0   1   1
	     0   0   1   0   1   1   1
	     0   1   0   1   1   1   0
	     1   0   1   1   1   0   0
	     0   1   1   1   0   0   1
	

積が単位行列に近い形となる。これを利用して、畳み込みによりインパルス応答を演算できることがわかる。但し、DC成分が乗ってしまうのが注意点である。

Scilab

	  mlsmatrix(3)*mlsmatrix(3)
	  mlsmatrix(3)*mlsmatrix(3) / 2^(3-2) -1
	  norm(mlsmatrix(4)*mlsmatrix(4) / 2^(4-2) -1 - eye(2^4-1,2^4-1))
	  norm(mlsmatrix(5)*mlsmatrix(5) / 2^(5-2) -1 - eye(2^5-1,2^5-1))
	
	   ans  =

	     4.   2.   2.   2.   2.   2.   2.
	     2.   4.   2.   2.   2.   2.   2.
	     2.   2.   4.   2.   2.   2.   2.
	     2.   2.   2.   4.   2.   2.   2.
	     2.   2.   2.   2.   4.   2.   2.
	     2.   2.   2.   2.   2.   4.   2.
	     2.   2.   2.   2.   2.   2.   4.

	   ans  =

	     1.   0.   0.   0.   0.   0.   0.
	     0.   1.   0.   0.   0.   0.   0.
	     0.   0.   1.   0.   0.   0.   0.
	     0.   0.   0.   1.   0.   0.   0.
	     0.   0.   0.   0.   1.   0.   0.
	     0.   0.   0.   0.   0.   1.   0.
	     0.   0.   0.   0.   0.   0.   1.

	   ans  =

	     0.

	   ans  =

	     0.
	
	  [d,e]=convol(mls(3),flipdim(mls(3),2));
	  [d,e]=convol(mls(3),flipdim(mls(3),2),e);
	  disp(d([2^3-1,1:2^3-2]))
	  
	  [d,e]=convol(mls(4),flipdim(mls(4),2));
	  [d,e]=convol(mls(4),flipdim(mls(4),2),e);
	  disp(d([2^4-1,1:2^4-2]))
	
	     4.   2.   2.   2.   2.   2.   2.
	  
	     8.   4.   4.   4.   4.   4.   4.   4.   4.   4.   4.   4.   4.   4.   4.
	

MLSと畳み込みを利用したインパルス応答の演算

MLSとその順序を逆にしたものを使って巡回畳み込みを行うと、インパルス応答が演算できる。時間領域で畳み込みを行うとかなり時間がかかるので、FFTを利用した高速な畳み込み方を使う事が多い。 その他に高速アダマール変換を利用する方法もあり、これは後述する。

Scilab

	  testsig0 = [10,2,1,-1,0,5,2,1,-3,0,0,-1,8,1,-2]
	  mls4 = mls(4)*2-1; // 0/1 to -1/+1
	  [f,e]=convol(mls4,testsig0);
	  [f,e]=convol(mls4,testsig0,e); // testsig(*)mls
	  
	  // deconvolution:
	  // convolve with backward sequence to get original signal
	  [g,e]=convol(f,flipdim(mls4,2));
	  [g,e]=convol(f,flipdim(mls4,2),e); // circular convolution
	  
	  h = (g([2^4-1,1:2^4-2]) + sum(g)) / 2^4;
	  h = round(h) // omit arithmetic error
	  if ( testsig0 == h ) then
	      disp('MLS deconvolution was successful.');
	  else
	      disp('MLS deconvolution was unsuccessful.');
	  end
	
	   testsig0  = 
	  
	     10.   2.   1.  -1.   0.   5.   2.   1.  -3.   0.   0.  -1.   8.   1.  -2.
	  
	   h  = 
	  
	     10.   2.   1.  -1.   0.   5.   2.   1.  -3.   0.   0.  -1.   8.   1.  -2.
	  
	   MLS deconvolution was successful.
	

アダマール変換を使用した畳み込みの演算

アダマール変換を利用した方法を使う場合、信号順を置換してアダマール変換に合う順序として高速アダマール変換等で処理した後、また信号順を置換する必要がある。 詳細については下記論文を参照すると良い。置換の数列を2つ用意するが、片方はMLS matrixの上ビット分、もう片方は上ビット分が単位行列になるように MLS matrixから列を探してビット分並べると、その2つの行列の積がMLS matrixになることがわかる。

Scilab

	  function [matr,matc] = mlsperm(n)
	  mlsmat = mlsmatrix(n);
	  matc = mlsmat(1:n,:);
	  matr = zeros((2^n)-1,n);
	  matu = eye(n,n);
	  for i = 1:1:n
	    for j = 1:1:(2^n)-1
	      if ( mlsmat(1:n,j) == matu(:,i) ) then
	       matr(:,i) = mlsmat(:,j)
	      end
	    end
	  end
	  endfunction

	  function rlist = mlspermr(matr,n)
	  rlist = bin2dec(strsplit(strcat(string(matr')),[n*(1:(2^n)-2)]))'
	  endfunction

	  function clist = mlspermc(matc,n)
	  clist = bin2dec(strsplit(strcat(string(matc)),[n*(1:(2^n)-2)]))'
	  endfunction

	  [mr,mc] = mlsperm(3)
	  cc = modulo(mr*mc,2)
	  permr = mlspermr(mr,3)
	  permc = mlspermc(mc,3)
	
	     mc  = 

	       1.   1.   1.   0.   0.   1.   0.
	       1.   1.   0.   0.   1.   0.   1.
	       1.   0.   0.   1.   0.   1.   1.

	     mr  = 

	       1.   0.   0.
	       0.   1.   0.
	       0.   0.   1.
	       1.   1.   0.
	       0.   1.   1.
	       1.   1.   1.
	       1.   0.   1.

	     cc  = 

	       1.   1.   1.   0.   0.   1.   0.
	       1.   1.   0.   0.   1.   0.   1.
	       1.   0.   0.   1.   0.   1.   1.
	       0.   0.   1.   0.   1.   1.   1.
	       0.   1.   0.   1.   1.   1.   0.
	       1.   0.   1.   1.   1.   0.   0.
	       0.   1.   1.   1.   0.   0.   1.

	     permr  = 

	       4.   2.   1.   6.   3.   7.   5.

	     permc  = 

	       7.   6.   4.   1.   2.   5.   3.
	  

先述のMLSの逆順を畳み込むことと、MLS matrixとの行列積を求めることは同義で、行列積を高速に処理したい時は例えばATLAS等のBLASのDGEMVを使ったりしても良いが、 先の論文で提案されているように、MLS matrixは上で求めた置換用の数列を使って変形することでアダマール行列にすることができるので、入力ベクトルの順序を置換すれば、 バタフライ演算を使用してO(n log(n))の計算量で処理できるようになる。 変形にはいくつか手順が必要で、アダマール行列の1と-1は0と1に置換し、MLS行列の1行目と1列目には0を追加する。ScilabやMATLABやOctaveでは、行列の置換の記述方法が非常に楽で、 左辺に置換数列を指定することもできるので、このような時は使いやすいと思う。MATLABはMatrix Laboratoryの略というのがよく分かる。

Scilab

	  function hmatrix=hadamard(n)
	  h=[1,1;1,-1]
	  hmatrix=h;
	    for n = 1:1:(log2(n)+1)-2
	      hmatrix = hmatrix.*.h;
	    end
	  endfunction

	  mls3matex = [0,zeros(1,7);zeros(7,1)mlsmatrix(3)]
	  (hadamard(8)-1)/-2
	  
	  // Hadamard matrix -> MLS matrix permutation
	  hadama8p1 = ((hadamard(8)-1)/-2)([1,permr+1],[1,permc+1])
	  hadama8p2 = ((hadamard(8)-1)/-2)([1,permc+1],[1,permr+1])
	  mls3matex - hadama8p1
	  mls3matex - hadama8p2
	
	   mls3matex  = 

	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   1.   1.   1.   0.   0.   1.   0.
	     0.   1.   1.   0.   0.   1.   0.   1.
	     0.   1.   0.   0.   1.   0.   1.   1.
	     0.   0.   0.   1.   0.   1.   1.   1.
	     0.   0.   1.   0.   1.   1.   1.   0.
	     0.   1.   0.   1.   1.   1.   0.   0.
	     0.   0.   1.   1.   1.   0.   0.   1.


	  --> (hadamard(8)-1)/-2
	   ans  =

	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   1.   0.   1.   0.   1.   0.   1.
	     0.   0.   1.   1.   0.   0.   1.   1.
	     0.   1.   1.   0.   0.   1.   1.   0.
	     0.   0.   0.   0.   1.   1.   1.   1.
	     0.   1.   0.   1.   1.   0.   1.   0.
	     0.   0.   1.   1.   1.   1.   0.   0.
	     0.   1.   1.   0.   1.   0.   0.   1.

	  --> mls3matex - hadama8p1
	   ans  =

	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.


	  --> mls3matex - hadama8p2
	   ans  =

	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	
	  // MLS matrix -> Hadamard matrix permutation
	  lmr([1,permr+1]) = 1:8
	  lmc([1,permc+1]) = 1:8
	  mls3matex(lmr,lmc) - (hadamard(8)-1)/-2
	  mls3matex(lmc,lmr) - (hadamard(8)-1)/-2
	
	  > lmr([1,permr+1]) = 1:8
	   lmr  = 

	     1.   4.   3.   6.   2.   8.   5.   7.


	  --> lmc([1,permc+1]) = 1:8
	   lmc  = 

	     1.   5.   6.   8.   4.   7.   3.   2.


	  --> mls3matex(lmr,lmc) - (hadamard(8)-1)/-2
	   ans  =

	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.


	  --> mls3matex(lmc,lmr) - (hadamard(8)-1)/-2
	   ans  =

	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	     0.   0.   0.   0.   0.   0.   0.   0.
	

演算例

Scilab

	  // [2^3] impulse input
	  n = 3;
	  [mr,mc] = mlsperm(n);
	  permr = mlspermr(mr,n);
	  permc = mlspermc(mc,n);
	  mlsmat = mlsmatrix(n);
	  hadamardMatrix = hadamard(2^n);

	  sigmlsperm = zeros(1,2^n-1)
	  sigmlsperm(permc) = mlsmat(1,:)
	  hinput = [0,sigmlsperm]
	  houtput = hinput*hadamardMatrix/(2^n)
	  hout =  houtput(2:2^3)
	  signal = hout(permr)*(-2)
	
	  --> sigmlsperm = zeros(1,2^n-1)
	   sigmlsperm  = 

	     0.   0.   0.   0.   0.   0.   0.


	  --> sigmlsperm(permc) = mlsmat(1,:)
	   sigmlsperm  = 

	     0.   0.   0.   1.   1.   1.   1.


	  --> hinput = [0,sigmlsperm]
	   hinput  = 

	     0.   0.   0.   0.   1.   1.   1.   1.


	  --> houtput = hinput*hadamardMatrix/(2^n)
	   houtput  = 

	     0.5   0.   0.   0.  -0.5   0.   0.   0.


	  --> hout =  houtput(2:2^3)
	   hout  = 

	     0.   0.   0.  -0.5   0.   0.   0.


	  --> signal = hout(permr)*(-2)
	   signal  = 

	     1.   0.   0.   0.   0.   0.   0.
	
	  // Test signal 1
	  testsig1 = [1,-1,0.5,-0.5,0.1,-0.1,0]
	  input = testsig1*mlsmat // convolution input
	  sigmlsperm = zeros(1,2^n-1);
	  sigmlsperm(permc) = input
	  hinput = [0,sigmlsperm]
	  houtput = hinput*hadamardMatrix/(2^n)
	  hout =  houtput(2:2^3)
	  signal1 = hout(permr)*(-2)
	
	  --> testsig1 = [1,-1,0.5,-0.5,0.1,-0.1,0]
	   testsig1  = 

	     1.  -1.   0.5  -0.5   0.1  -0.1   0.


	  --> input = testsig1*mlsmat // convolution input
	   input  = 

	     0.4   0.1   0.4   0.5  -1.5   1.1  -1.


	  --> sigmlsperm(permc) = input
	   sigmlsperm  = 

	     0.5  -1.5  -1.   0.4   1.1   0.1   0.4


	  --> hinput = [0,sigmlsperm]
	   hinput  = 

	     0.   0.5  -1.5  -1.   0.4   1.1   0.1   0.4


	  --> houtput = hinput*hadamardMatrix/(2^n)
	   houtput  = 

	     0.  -0.25   0.5  -0.05  -0.5   0.   0.25   0.05


	  --> hout =  houtput(2:2^3)
	   hout  = 

	    -0.25   0.5  -0.05  -0.5   0.   0.25   0.05


	  --> signal1 = hout(permr)*(-2)
	   signal1  = 

	     1.  -1.   0.5  -0.5   0.1  -0.1   0.
	
	  // Test signal 2
	  testsig2 = [4,-3,3,-9,-3,2,1]
	  input = testsig2*mlsmat // convolution input
	  sigmlsperm = zeros(1,2^n-1);
	  sigmlsperm(permc) = input
	  hinput = [0,sigmlsperm]
	  houtput = hinput*hadamardMatrix/(2^n)
	  hout =  houtput(2:2^3)
	  signal2 = hout(permr)*(-2)
	
	  --> testsig2 = [4,-3,3,-9,-3,2,1]
	   testsig2  = 

	     4.  -3.   3.  -9.  -3.   2.   1.


	  --> input = testsig2*mlsmat // convolution input
	   input  = 

	     6.  -1.  -2.   3.  -13.  -5.  -8.


	  --> sigmlsperm(permc) = input
	   sigmlsperm  = 

	     3.  -13.  -8.  -2.  -5.  -1.   6.


	  --> hinput = [0,sigmlsperm]
	   hinput  = 

	     0.   3.  -13.  -8.  -2.  -5.  -1.   6.


	  --> houtput = hinput*hadamardMatrix/(2^n)
	   houtput  = 

	    -2.5  -1.5   1.5   1.5  -2.  -0.5   4.5  -1.


	  --> hout =  houtput(2:2^3)
	   hout  = 

	    -1.5   1.5   1.5  -2.  -0.5   4.5  -1.


	  --> signal2 = hout(permr)*(-2)
	   signal2  = 

	     4.  -3.   3.  -9.  -3.   2.   1.
	
	  // [2^4]
	  n = 4
	  [mr,mc] = mlsperm(n)
	  permr = mlspermr(mr,n)
	  permc = mlspermc(mc,n)
	  hadamardMatrix = hadamard(2^n);

	  rand('seed',0)
	  testsig3 = rand(1,2^n-1)
	  input = testsig3 * mlsmatrix(n);

	  sigmlsperm = zeros(1,2^n-1);
	  sigmlsperm(permc) = input;
	  hinput = [0,sigmlsperm];
	  houtput = hinput*hadamardMatrix/(2^n);
	  hout =  houtput(2:2^n);
	  signal3 = hout(permr)*(-2)
	  if ( testsig3 == signal3 ) then
	      disp('MLS deconvolution was successful.');
	  else
	      disp('MLS deconvolution was unsuccessful.');
	  end
	
	   testsig3  = 


	           column 1 to 9

	     0.2113249   0.7560439   0.0002211   0.3303271   0.6653811   0.6283918   0.8497452   0.685731   0.8782165

	           column 10 to 15

	     0.068374   0.5608486   0.6623569   0.7263507   0.1985144   0.5442573

	   signal3  = 


	           column 1 to 9

	     0.2113249   0.7560439   0.0002211   0.3303271   0.6653811   0.6283918   0.8497452   0.685731   0.8782165

	           column 10 to 15

	     0.068374   0.5608486   0.6623569   0.7263507   0.1985144   0.5442573


	   MLS deconvolution was successful.
	
Rule of Open-Source Programming #37:

Duplicate effort is inevitable. Live with it.

    -- Shlomi Fish
    -- "Rules of Open Source Programming"

And the whole problem hinges on the little tiny decision of what IE8 should do
when it encounters a page that claims to support standards, but has probably
only been tested against IE7.

What the hell is a standard?

Dont they have standards in all kinds of engineering endeavors? (Yes.)

Dont they usually work? (Mmmm..)

Why are web standards so frigging messed up? (Its not just Microsofts
fault. Its your fault too. And Jon Postels (1943-1998). Ill explain that
later.)

There is no solution. Each solution is terribly wrong. Eric Bangeman at ars
technica writes, The IE team has to walk a fine line between tight support
for W3C standards and making sure sites coded for earlier versions of IE still
display correctly. This is incorrect. Its not a fine line. Its a line of
negative width. There is no place to walk. They are damned if they do and
damned if they dont.

    -- Joel Spolsky
    -- "Martian Headsets" ( http://www.joelonsoftware.com/items/2008/03/17.html )


Powered by UNIX fortune(6)
[ Main Page ]