ラベル 固定小数点演算回路 の投稿を表示しています。 すべての投稿を表示
ラベル 固定小数点演算回路 の投稿を表示しています。 すべての投稿を表示

2012年7月17日火曜日

固定小数点演算信号処理の極意シリーズ (その9) 符号付き乗算回路

前回までで加算回路(減算回路)の設計方法については説明終了しました.今回は乗算回路です.

簡単な乗算回路(割り算回路)はつぎのようなbit shiftで実現できます.
wire [8:0] y = {x[7:0],1'b0};     // 2倍する
wire [7:0] z = y[8:1];    // 1/2する
wire [15:0] M256 = {x[7:0],8'b0};    //  256倍する

このように、bit shiftならば2のべき乗のかけ算割り算が簡単にできますので、ノイズ除去のために平均化するような処理をする場合は、加算回数を256回にして、8bit shiftで1/256にする、のような簡便な回路で済むように設計するのが吉となります.そういうことはよくやります.


つぎに符号付き2進数で整数・小数の桁を考慮してbit shiftを考えてみます.原理は同じです.

例1)   x(1.7.8)を入力し、4倍し、y(1.9.8)を出力する
wire [17:0] y = {x[15:0],2'b0};   // (1.9.8)

例2)  x(1.7.8)を入力し、1/4倍し、y(1.5.8)を出力する
wire [13:0] y = x[15:2];  // (1.5.8)

例3)  x(1.7.8)を入力し、8倍し、y(1.10.1)を出力する
wire [18:0] tmp = {x[15:0],3'b0};  // (1.10.8)
wire [11:0] y = tmp[18:7] // (1.10.1)

例4)  x(1.7.8)を入力し、1/8倍し、y(1.4.11)を出力する
wire [15:0] y = x[15:0]; // (1.4.11)

この例を見て考えて法則性を理解できますでしょうか? ①とりあえず小数桁は無視して倍数ぶんのbit shiftを行う、②小数桁を考慮して出力bitを切り詰める、そんなかんじの操作をします.

例4は謎のbit shiftせずで面食らってませんか?  例4は1/8したけど入出力のbit幅が同じなので、回路的にはなにもしません.でも変わるのは、おなじ16bit数値を、(1.7.8)と区分するか、(1.4.11)と区分するかの差違でしかありません.設計者であるアナタの心の目で小数点位置を変更した気持ちになるだけなのです.固定小数点演算のえもいわれぬかったるいところです.

ここまでは、2のべき乗の乗算割り算回路でしたが、13倍とか721倍とかはどうするんでしょうか? それは「乗算器」という回路を使って実現します.乗算器の回路規模は大きく、速度も遅いです.リッチな回路です.

乗算器の設計については、次回で説明します.今回はこのへんでおしまい.

つぎへ       前へ

人気ブログランキングへ

2012年7月13日金曜日

固定小数点演算信号処理の極意シリーズ (その8) bit削減方法

前回は符号付き固定小数点の加算を説明しました.今回は、前回で説明がしりきれになってしまった「膨らんだbitを削減する方法」を説明します.

設定はこのような場面です.前回説明した加算回路出力Dが18bitであるが、RAMは16bitしかないので、bit削減してからRAMに書かなくちゃイケナイという場面.

Dの信号がフルbit振幅の正弦波だと仮定して波形を描いたのが下図です.
グリーンが加算回路出力である符号付き18bitです.小数点は無視して(1.17.0)としてプロットしてあるので、最大/最小値は±131071になっていて、どう考えても16bit RAMにはストアできっこありません.さて、どうしましょうか? 2通りのbit削減方法があります.
bit削減方法その1は赤いラインのように、下2bitを捨ててしまう方法があります.つまりverilogでは、
     wire [15:0] E = D[17:2];
このように表記します.D[1:0]を消滅させます.分解能が悪化する副作用があります.

bit削減方法その2は青いラインのように、16bit2進数の表現範囲±32767を超えたエリアをクリップさせる方法です.すなわち18'h07FFFを超えさせなくする、かつ18'h38001を下回らせなくするという対処をしたいわけです.
   :
18'h08001     7FFFにclip
18'h08000     7FFFにclip
18'h07FFF    スルー
18'h07FFE    スルー
   :
18'h38001     スルー
18'h38000     8001にclip       ←なんで8001なのかはこちらの「不便なこと1」を参照
18'h37FFF    8001にclip
18'h37FFe    8001にclip
   :
これをverilogで書くと、
     wire [15:0] E = (D[17]==0 && D[16:0]>17'h7FFF) ? 16'h7FFF :  // +clip
                            (D[17]==1 && D[16:0]<17'h18001) ? 16'h8001 : // -clip
                             D[15:0];    // through
このclipping処理は、目がチカチカするのでわたしはcodingするたびになにかしらバグってしまい、simulationで気づくというヘタレなことをやってしまいます.上のcodeもバグっているやもしれぬ...固定小数点信号処理のめんどくさいところの一つです.

もしも、分解能低下も嫌だし、clippingも嫌ならば、RAMを18bitに拡張するしかないってことになります.

では今回はこのへんで、                   つぎへ             前へ

人気ブログランキングへ

2012年7月7日土曜日

固定小数点演算信号処理の極意シリーズ (その7) 符号付き2進数加算法

前回は加算回路でbit幅が増えてゆくのをどう設計すればよいかを説明しました. ------乗算回路はまたこんど------

今回は、
 1)符号付き2進数の加算方法
 2)verilog code
 3)膨らんだbit幅を削減する方法
を説明します.

1)符号付き2進数の加算方法
符号なしの加算はたとえばこんなです.そんなに困ったことはないです.(0.6.0)+(0.4.0)=(0.7.0)となりますのは前回で解説したとおりです.
  36+13 = 49     100100 + 1101 = 0110001

ところが、つぎのような符号付きの加算は注意が必要です.
  (-36)+(-13)=(-49)
やってみます.
まず、-36を符号付き2進数に変換します.関数電卓で変換すりゃ簡単ですが、ここでは手でやってみます.
①+36の2進数100100に符号bitを追加する.0100100    ←(1.6.0)になった
②各bitを反転させた1011011に+1して、1011100 を得る     ←これが-36
つぎに、-13を符号付き2進数に変換します.
①+13の2進数1101に符号bitを追加する.01101    ←(1.4.0)になった
②各bitを反転させた10010に+1して、10011 を得る     ←これが-13

では加算します.
      1011100 + 10011 = 1101111
この右辺が-49になっているのかを確かめます.
③1101111の各bitを反転して、 0010000を得る
④0010000に+1して、0010001 を得る
⑤0010001を10進数に変換すると17です.つまり、上記の計算は-17という間違った答えを導き出してしまっています.
ムムッこれはイカン!   どこで間違ったんだ?
その答えは、
符号付き2進数を加算するときには、符号拡張をしなくちゃいけない
という法則があります.

符号拡張の例を示します.上で説明したマイナス数値の加算の式とbit構成はこうでした.
  式: (-36)+(-13)=(-49)            bit構成: (1.6.0) + (1.4.0) = (1.7.0)
符号付き加算回路を構成するには、出力のbit幅で入力を統一しなくちゃいけません.そういう操作を符号拡張と呼びます.つまりこうゆうbit構成にて計算します.
  式: (-36)+(-13)=(-49)            bit構成: (1.7.0) + (1.7.0) = (1.7.0)
-36の符号拡張のしかたはこうです.
     -36=1011100=(1.6.0)     →   -36=11011100=(1.7.0)
-13の符号拡張のしかたはこうです.
     -13=10011=(1.4.0)     →   -13=11110011=(1.7.0)
符号拡張でやることは、符号bitを必要なだけMSB側に並べることです.憶えましょう.
そして計算します.
11011100 + 11110011 = 11001111              bit構成: (1.7.0) + (1.7.0) = (1.7.0)
この右辺が-49になっているのかを確かめます.
③ 11001111 の各bitを反転して、 00110000を得る
④ 00110000 に+1して、 00110001 を得る
⑤ 00110001  を10進数に変換すると49です.    やったー正答を得た!

ここまでの知見を元に verilog codeを書きますと、実は意外に簡単です.
変数にS36+S13=A49と名付けしますと、
// S36 (1.6.0) + S13 (1.4.0) = A49 (1.7.0)
wire [6:0] S36;  // (1.6.0)    -36
wire [4:0] S13;  // (1.4.0)    -13
wire [7:0] A49 = {S36[6],S36[6:0]} + {S13[4],S13[4],S13[4],S13[4:0]}; // (1.7.0)  -49

赤いところが符号拡張です.符号付き加算にはこの操作が必ず必要です.かったるいですねー.
符号付き数値であっても、必ず正数だと判っているなら符号拡張は不要です.ゼロを符号拡張してもゼロですから.

 2)verilog code
前回の例題であったこの回路をverilog codeで書いてみます.赤が符号拡張です.
wire [13:0] A1;  // (1.7.6)
wire [14:0] A2;  // (1.7.7)
wire [15:0] A = {A1[13],A1[13],A1} + {A2[14],A2}; // (1.8.7)
reg [15:0] B1;   // (1.8.7)
always @(posedge clk or negedge xrst)   if(!xrst) B1<=0;   else B1<=A;
wire [14:0] B2;  // (1.7.7)
wire [16:0] B = {B1[15],B1[15:0]} + {B2[14],B2[14],B2[14:0]}; // (1.9.7)
reg [16:0] C1;   // (1.9.7)
always @(posedge clk or negedge xrst)   if(!xrst) C1<=0;   else C1<=B;
wire [14:0] C2;  // (1.7.7)
wire [16:0] C = {C1[15],C1[15:0]} + {C2[14],C2[14],C2[14:0]}; // (1.9.7)
reg [16:0] D1;   // (1.9.7)
always @(posedge clk or negedge xrst)   if(!xrst) D1<=0;   else D1<=C;
wire [13:0] D2;  // (1.7.6)
wire [17:0] D = {D1[16],D1[16:0]} + {D2[13],D2[13],D2[13],D2[13],D2[13:0]}; // (1.10.7)

↑どうですか? 意外に簡単なcodeでホッとしたんじゃないかと思います.でも、目がチカチカして間違いやすいです.固定小数点演算回路はこのようにかったるい設計なんです.

 3)膨らんだbit幅を削減する方法

すまんが長くなってしまったのでこれは次回にさしてくれ.     つぎへ       前へ

人気ブログランキングへ

2012年7月5日木曜日

固定小数点演算信号処理の極意シリーズ (その6) 加算で増えるbit幅

前回はverilogの記述方法について簡単に説明しました.今回は、加算したらbit幅が増えることについて説明します.

4bit+4bitの加算をしてみます.
   3+8 = 11        0011+ 1000 = 1011
この例では4bit+4bitは4bitに収まっていて、bit幅は増えません.
けれど、この例ではどうでしょうか?
  12+13 = 25      1100 + 1101 = 11001
あら~答えが5bitになっちゃった.でもまぁ和が25なんだったら5bitに増えるのはやむを得まい.一般的にどう対処したらいいんだろう?

↑これが今回解決したい問題点です.つまり、
     4bit+1bitは何bitになるのか?  4bit+2bit+2bitは何bitになるのか?
こういうことを法則として理解できてないと、固定小数点演算回路を設計することはできません.答えが18bitになるはずなのに、16bitで設計しちゃったらオーバーフローして計算結果がバグバグになってしまいますからね.

いきなり難しい実例ですが、下記の加算回路の各部分のbit幅を求めてみましょう.
この回路は、左側から(1.7.6)の符号付き固定小数点信号が入力されます.(1.7.6)の意味は、1が符号、7が整数部bit数、6が小数部bit数の意味です.------こちらのページの下の方で説明しました-------    それに加算されるのは(1.7.7)が3つと(1.7.6)が1つという複雑な加算構造になってます.
では、A~Dまで順に追ってゆきます.

A:  初段なので簡単です. (1.7.6) + (1.7.7)  = (1.8.7) になります.
出力法則は ①小数部は大なる桁数で統一する  ②整数部は大なる桁が1桁増える  ③符号は両方が符号付きでも1桁のまま  ③符号は片方が符号付きなら1桁充てる  ③符号は両方とも符号なしなら0桁
つまりこの例では、
①小数部は片方が6bit、片方が7bitですから、出力は7bitです.
②整数部は両方とも7bitですから、出力は8bitになります.
③符号は1bitのまま.
すなわち (1.8.7)になります.出力Aを(1.8.7)という桁サイズに受けておけば、どんな数値が入力されても数値的にオーバーフローしなくて済むというわけです.

そしてverilog codeはこうなります.A1[13]とかA2[14]はなんだろ?と思うでしょうね.それは次回解説しますので、今回はverilog codeはこれ以上はお見せしません.
wire [13:0] A1;  // (1.7.6)
wire [14:0] A2;  // (1.7.7)
wire [15:0] A = {A1[13],A1[13],A1} + {A2[14],A2}; // (1.8.7)

B: 2段目以降は複雑化します.そもそも式を書くのがかったるい.なぜなら、AとBで登場する項を全部書かなくちゃいけないからです.すなわちこうなります.  (1.7.6) + (1.7.7) + (1.7.7) とこう書きます.この式をどうやって料理するか? 同じ桁数の項同士を最初に足します. 2つある(1.7.7)を足すと(1.8.7)になる法則はAで示しました.そのおかげで、(1.7.6) + (1.8.7) と2項に簡素化できました.2項を足す法則はAで示しました.結果はBが(1.9.7)になります.

C: もっとめんどくさくなります.AとBとCで登場する項を全て書きますと、 (1.7.6) + (1.7.7) + (1.7.7) + (1.7.7) になります.末尾の同じ桁数の項同士を最初に足しますと、 (1.7.6) + (1.7.7) + (1.8.7) になります.さらに、左側の2項を足しますと、(1.8.7) + (1.8.7) になります.最後にCが (1.9.7) を得ます.おもしろいことになりました.BもCも(1.9.7)で同じです.これはBは余裕があったからです.

D: 究極的にかったるいです.ABCDで登場する項を全て書きますと、 (1.7.6) + (1.7.7) + (1.7.7) + (1.7.7) + (1.7.6) になります.左右の(1.7.6)を片づけますと(1.8.6)ですから、(1.8.6) + (1.7.7) + (1.7.7) + (1.7.7) になります.末尾の(1.7.7)を片付けますと(1.8.7)ですから、(1.8.6) + (1.7.7) + (1.8.7)になります.(1.8.6)と(1.8.7)を片付けると(1.9.7)ですから、(1.9.7) + (1.7.7)になります.最後にDが(1.10.7)を得ます.

⑤の法則性はかっちりと書きにくいのですが、上手いこと考えて2項ずつ消してください.

このように、入力では(1.7.6)の14bitだったのが、出力では(1.10.7)の18bitに膨らんだという結果を得ました.逆に言うと、上図の構成でオーバーフローを生じさせない安全な回路を設計するには、出力18bitが必要ですよということです

なお、ここでは加算回路を例にしましたけれど、減算回路でも同じです.マイナス符号の加算と思えば同じですから.

読者の中には、加算結果がどんどん増えて行くのを困ったなぁと考えている方もいらっしゃると思います.たとえば、この加算回路の出力をどうしても16bitのメモリに格納しなくちゃいけないときなどです.そういうときは、たとえ値がサチッてもいいから、16bitに丸めたいわけです.

丸めるやり方を次回で説明します.次回はverilog codeが出まくりです.

つぎへ            前へ

人気ブログランキングへ

2012年7月1日日曜日

固定小数点演算信号処理の極意シリーズ (その5) verilog記述法

その4にひきつづきまして、今回はverilogについてすこし説明します.わたしはVHDLを知らないのでverilogだけしか使えません.以下、全然体系的ではありませんが、ダーッと説明します.

●C言語に似たverilogですが、intはあるけどfloatとかdoubleはありません.代わりに、レジスタを宣言するregと、配線の宣言をするwireがあり、regとwireを区別して宣言しなくてはいけません.

reg   a;
1bitのフリップフロップを設けてその出力にaと名付ける.reg宣言した時点では、clockとかresetについてはまだ何も言及していません.
reg   [3:0]  abc;
4bitのフリップフロップを設けてその出力にabcと名付ける.変数を使うときはabcと略記するとabc[3:0]の4bitバスを意味します.律儀にabc[3:0]と表記してもOKです.バスの1本1本を表現したいときはabc[2]のように表記します.abc[1:0]のように一部でもOKです.
wire [4:0] sum;
フリップフロップではなく、ゲート回路(組み合わせ回路ともいう)の出力にsumと名付ける.wire宣言した時点では「なにかの回路」がなんなのかにはまだ何も言及してません.

●regやwireを宣言した後には、a,abc,sumをつかって「なにかの回路」を言及できるようになります.それにはassignを使います.
assign sum = a + abc;
     または
wire [4:0] sum = a + abc;
これらは式を読んでそのまんま加算の意味です.assignというのが面食らいますが、配線をつなぐ意味があります.後者はwire宣言と同時に配線をつないでいるのでassignを省略できてます.
ここまでの記述で、下図のように、フリップフロップ出力を加算したsumという値を得ることができています.
しかし、これではまだ動く回路とは言えません.clockを配線してないし、出力をフリップフロップでバッファしてないので不完全です.

●下図のような完全な回路にするにはフリップフロップの実体を記述しなくてはいけません.フリップフロップの実体とは、clock,reset,入力,出力です.
まずフリップフロップaの実体を記述します.
wire ain;
always @(posedge clock or negedge reset)
if(!reset) a<=0;
else a<=ain;
フリップフロップにはverilog特有の記述がいろいろあります.
posedge clockは、clockの立ち上がりエッジで動作させる意味です.
negedge resetは、resetがLOW activeである意味です.
if(!reset) a<=0;は、resetがLOWならaをゼロにする意味です.
a<=ain;は、clockの立ち上がりでainをラッチしてaに出力する意味です.
if文は上の行が高プライオリティですので、resetが高優先度です.
<=はreg宣言した変数に代入する時のおきまりの表記です.=だとエラーになります.
reg宣言した変数にはalways文の中でしか代入できません.
要するにこれは、reset付きのDフリップフロップです.

次にフリップフロップabcの実体を記述します.
wire [3:0] abcin;
always @(posedge clock or negedge reset)
if(!reset) abc<=0;
else abc<=abcin;

最後にフリップフロップsumoutの実体を記述します.
reg [4:0] sumout;
always @(posedge clock or negedge reset)
if(!reset) sumout<=0;
else sumout<=sum;

●最後にサブルーチンみたいなmoduleという単位に閉じ込めます.
module adder (
  input clock,
  input reset,
  input ain,
  input [3:0] abcin, 
  output [4:0] sumout
);
   上記の全てのcodeをここに転記する.......
endmodule
こうしたことで、adderという名前のmoduleをいくつでも呼び出して使うことができます.

●上記でフリップフロップでバッファされた演算回路の完全な記述をひとまず解説しました.つぎは、verilogならではの小技を解説します.

4bitバスを2つ連結して8bitバスにする
wire [3:0]  P, Q;       このように連続して宣言もできます.
wire [7:0]  R = {P,Q};      
こまかく書くとこういうこと→R={P[3],P[2],P[1],P[0],Q[3],Q[2],Q[1],Q[0]};

論理反転する
wire [7:0]  POS;
wire [7:0]  NEG = ~POS;         POSが11001010ならNEGは00110101になります.

MSBだけ反転する
wire [7:0]  MSBREV = {~POS[7],POS[6:0]};

引き算
wire [8:0] sub = POS - NEG;

かけ算
wire [15:0] mul = POS * NEG;

割り算
source codeに/演算子を記述することはできますが、論理合成してくれないのでhardware化できません.なのでverilogでhardwareを記述するときには/演算子は使いません.ただし、純粋softwareであるテストベンチを記述するには/演算子を使えるので使います.注意しましょう.

8bitシフトレジスタ
wire in;
reg [7:0] shift;
always @(posedge clk or negedge xrst)
if(!xrst) shift<=0;
else shift <= {shift[6:0],in};       LSBからMSBへ向けてshiftする

レジスタのenable動作
wire en;
wire [31:0] in;
reg [31:0] out;
always @(posedge CLOCK or negedge RESET)
if(!RESET) out<=0;
else if(en) out<=in;       en=1の時だけinをラッチする、それ以外はダンマリ.

これでverilogがバシバシ使えるかというと、そうではありませんけど、これくらいを理解すれば、次のステップの解説へ進むことができると思います.

つぎへ           前へ

人気ブログランキングへ

2012年6月27日水曜日

固定小数点演算信号処理の極意シリーズ (その4) 符号付き2進数

前回は、浮動小数点と固定小数点の話をしました.といっても、固定小数点の位取りの話までは達していないので固定小数点数値がどういうものなのかを理解できた人はまだいないと思います.今回は固定小数点数値の位取りの話と符号の話をするので、以下を読めば固定小数点数値の意味をわかっていただけると思います.

位取りとは、たとえば5bit binaryを、3+2bitに分けて、上位3bitを整数桁、下位2bitを小数桁とみなす、などと自分で決めることです.3+2bitに分けたときは、その表現可能範囲は下表のとおりになります.binaryは2進数です.decimalは10進数です.------位取りは設計者であるアナタの気持ち次第ですのでご注意のほど-------

3+2bitに分けたので、上位3bitで0~7の整数を表現できます.下位2bitの小数部は1を2bitで4分割するので0.25刻みの小数を表現できます.したがって、0~7.75の数値を表現できます.
binary    decimal
111.11    7.75
111.10    7.5
111.01    7.25
111.00    7.0
110.11    6.75
110.10    6.5
110.01    6.25
110.00    6.0
101.11    5.75
101.10    5.5
101.01    5.25
101.00    5.0
100.11    4.75
100.10    4.5
100.01    4.25
100.00    4.0
011.11    3.75
011.10    3.5
011.01    3.25
011.00    3.0
010.11    2.75
010.10    2.5
010.01    2.25
010.00    2.0
001.11    1.75
001.10    1.5
001.01    1.25
001.00    1.0
000.11    0.75
000.10    0.5
000.01    0.25
000.00    0.0

さてここからが本日の本題の符号付き2進数の話になります.負の数値をどうやって表現するんだい?っていう話です.

符号付き2進数の表現方法にはいろいろあるのですが、ここでは最も一般的に用いられている2の補数表現というのを解説します.一般的に用いられているの意味は、ADCやDACやFPGAの演算回路がこの2の補数表現で設計されているので、我々もそれに従うのがよいということです.もしも労を惜しまなければあなた独自の演算体系を作り上げても構いませんが相当かったるいでしょう.

まず、簡単な3bit binaryで2の補数表現をしてみます.要点は、
① MSB=0なら正の数値、MSB=1なら負の数値
② 数直線的に並べるには、MSB=0の数値を上に、MSB=1の数値を下に並び替える
③ 000ならゼロ
④ ゼロを中心に上下に絶対値を増やしてゆく
⑤ 正数は+3までなのに対し、負数が-4まである非対象さは我慢する   (あとでめんどくさいことになるんだこれが)
な~んか不思議な感じしかしませんが、でも2の補数とはこういうもんだ、と思ってもらうしかないです.桁数が増えても、小数を扱っても基本的な考え方は同じです.
binary   decimal
0 11       +3
0 10       +2
0 01       +1
0 00         0
1 11       -1
1 10       -2
1 01       -3
1 00       -4

次に、5bit binaryを、符号1bit+整数2bit+小数2bitに分割した符号付き固定小数点の表現可能範囲を下表に示してみます.青い正の範囲は上で描いたのと同じです.全然違うのは赤い負の範囲です.111.11が-0.25になってしまうんです.この変な感じは慣れで克服しましょう.結果的に、表現範囲は+3.75~-4.0となります.
binary    decimal
0 11.11    3.75
0 11.10    3.5
0 11.01    3.25
0 11.00    3.0
0 10.11    2.75
0 10.10    2.5
0 10.01    2.25
0 10.00    2.0
0 01.11    1.75
0 01.10    1.5
0 01.01    1.25
0 01.00    1.0
0 00.11    0.75
0 00.10    0.5
0 00.01    0.25
0 00.00    0.0
1 11.11    -0.25
1 11.10    -0.5
1 11.01    -0.75
1 11.00    -1.0
1 10.11    -1.25
1 10.10    -1.5
1 10.01    -1.75
1 10.00    -2.0
1 01.11    -2.25
1 01.10    -2.5
1 01.01    -2.75
1 01.00    -3.0
1 00.11    -3.25
1 00.10    -3.5
1 00.01    -3.75
1 00.00    -4.0

2の補数についての基本的なことは、だいたいこれで全部なのですが、便利なことを2つと、不便なことを2つ挙げておきます.

便利なこと1:
最初に示した3+2bit符号なしbinaryは、ADCのデータシートでよく見かけます.ADCの出力データ形式はたいていこの形式です.この形式をstraight binaryと呼称します.一方すぐ上の1+2+2bit符号付きbinaryは、2's complemetaryと呼称されます.2's complementaryのADCもたまにあります.
で、straight binaryを、2's complementaryに変換するのはとても簡単なんです.それは、 MSB を 符号反転するだけ でよいんです.このことは憶えておきましょう.

便利なこと2:
符号反転が簡単です.実際にやってみますと、
101.11    -2.25   これを符号反転してみます
各bitを反転します   010.00
LSBに1を足します     010.00 + 000.01 = 010.01
④ 010.01    2.25   そしたらあーら不思議、+2.25になりました

不便なこと1:
じつはこの符号反転には危険な罠があります.それは、マイナスの最小値を符号反転するとトラブることです.2の補数表現では+4.0が定義不可能なので、-4.0を符号反転しようとするとできません.そのことを示します.
① 100.00    -4.0    これを符号反転してみます
② 各bitを反転します   011.11
③ LSBを足します     011.11 + 000.01 = 100.00
④ 100.00    -4.0    そしたらあーら不思議、-4.0に戻ってしまいました.どひさん!!
これを見過ごしたfilterを設計してしまうと、飽和入力時にデータが化けて即死します.だから、100.00が入力されたら100.01に強制的に変換するという回路を追加して100.00を禁止しなくちゃいけません.このことは憶えておきましょう.

不便なこと2:
固定小数点演算回路では、N bit binaryにどういう位取りを持たせるかを設計者であるアナタの心の目で行わなくてはなりません.なので、ここの数値の位取りは何々だというのをコメントでいちいち記述しておかないとわけがわからなくなります.そのコメントの書き方について、ヒラサカが好きでやっている表記なんですが、こんな風に書いてはいかがでしょうか?
   (0.3.2)      符号なし5bit     整数3bit      小数2bit
   (1.2.2)      符号つき5bit     整数2bit      小数2bit
   (0.32.0)    符号なし32bit   整数32bit    小数0bit
   (1.15.16)  符号付き32bit   整数15bit    小数16bit
以後のこのシリーズでは、この表記で進めます.

蛇足とは思いますが、5bit binaryを(1.3.1)に位取りした場合の例を示しておきます.表現範囲は7.5~-8.0になります.
binary    decimal
0 111.1    7.5
0 111.0    7.0
0 110.1    6.5
0 110.0    6.0
0 101.1    5.5
0 101.0    5.0
0 100.1    4.5
0 100.0    4.0
0 011.1    3.5
0 011.0    3.0
0 010.1    2.5
0 010.0    2.0
0 001.1    1.5
0 001.0    1.0
0 000.1    0.5
0 000.0    0.0
1 111.1    -0.5
1 111.0    -1.0
1 110.1    -1.5
1 110.0    -2.0
1 101.1    -2.5
1 101.0    -3.0
1 100.1    -3.5
1 100.0    -4.0
1 011.1    -4.5
1 011.0    -5.0
1 010.1    -5.5
1 010.0    -6.0
1 001.1    -6.5
1 001.0    -7.0
1 000.1    -7.5
1 000.0    -8.0

次回はverilogについて少し学習します.             つぎへ            前へ
人気ブログランキングへ

2012年6月25日月曜日

固定小数点演算信号処理の極意シリーズ (その3) floatとint

前回はFPGAで固定小数点演算するのが最もチープだぜぇっていう話でした.今回は、固定小数点演算と浮動小数点演算の違いをサラッと解説します.------うまく解説できる自信はないんだが------

固定小数点演算っていう概念自体を普通は知らないと思います.なぜかというと、C言語には浮動小数点演算が実装されているので、フツーは何も考えずに
   float x;
   double y;
   x = 1.23456e-12;
   y = x / 9.87654321e-36;
などと浮動小数点演算をバシバシ使えるからです.

これ、浮動小数点演算をなにげなく使っていますけど、C言語のコンパイラが隠れて上手に処理してくれているからユーザーには簡単に見えているだけで、実際の内部処理はややこしくて、その数値のメモリへの格納だけでも下図のようにめんどくさいです.
わたしの想像ですけど、たとえばxとyを掛けるときには、①仮数部同士を掛ける→②指数部同士を加える→③指数部の桁上げ桁下げを仮数部に加える→④符号をつける という4段階の手順を経るのでしょう.答えを得るまでに要する命令step数も長くかかります.つまり、高速で動かすのは難しい.高速な信号処理が難しい、となります.

一方で、固定小数点数値のメモリ上への格納は、たとえばC言語の整数のlongだったら 単純に32bitの符号付き整数がメモリ上に置かれるだけです.上の図に似せて描くとこんな感じです.構造が簡単です.
xとyを掛けるときには、乗算回路にxとyを入力すれば1クロックでxyを取り出せます.なのでとても高速ですし、回路規模も小さくて済みます.速くて安いを享受できます.
ただし、固定小数点演算の設計が難しいのは、桁数が変わるのを設計者が管理しなくちゃいけないということです.具体的には次のように、32ビット同士を掛けると64ビットに桁数が膨らみます.32ビット同士を足すと33ビットに桁数が膨らみます.
このいけ好かない状況をどうやって処置したらいいんだよってのは当シリーズのずっと後で解説しますが、ひとまず今は、固定小数点演算回路は速くて安いけど設計は大変だ、ということだけ理解してください.

ではつづく.             つぎへ        前へ

人気ブログランキングへ

固定小数点演算信号処理の極意シリーズ (その2) チープだぜぇ

前回は「デジタル信号処理」の意義を書きました.今回はも少し細かい導入の話を.

デジタル信号処理をその実現方法で分類すると、次の4種類になると思います.

①DSPをつかう浮動小数点演算.
利点: 浮動小数点演算なので高精度.ソフト開発なのでロジック回路に較べると開発が楽.
欠点: あまり高速でない.オーディオ帯域ならOKだけど、数MHzの信号にはキツイかも.メモリとかを装備しなくちゃいけないので得てして値段が高いように思う.

②PCでゴリゴリと計算する浮動小数点演算.
利点: お手軽だとは言えるでしょう.インターフェースカードの仕様次第ではMHzオーダーの信号も扱えるでしょう.
欠点: リアルタイム処理には向かない.インターフェースカードの値段が高い.PCの値段が高い.なので、高価な測定system向きでしょう.

③専用CPUでゴリゴリ計算する浮動小数点演算.
利点: C言語でフツーに書けるのでDSPより楽かも.
欠点: メモリを載せてリアルタイムOSを載せて32bit CPUを載せて、、、、などといろいろとリソースを要求するので、結局値段が高くなりがち.

④FPGAで固定小数点演算.
利点: リソースがFPGAだけで済むので値段が最安.チープだぜぇ.10MHzぐらいまでは余裕で対応できる.量産機種向けです.
欠点: 設計はかなーりめんどくさい.

このシリーズで解説するのは④です.

数10MHzの信号を扱う必要があり、しかも値段が激安じゃないと困る~っていう用途には、④が最適です.ただし、④を設計するノウハウってあまり世の中に解説記事がないと思うので、このシリーズは貴重だと思います.ちなみに、世の中にたくさんあるのは、①と②の解説記事ばっかりだと思います.

つぎへ         まえへ


人気ブログランキングへ

2012年6月24日日曜日

固定小数点演算信号処理の極意シリーズ (その1) 意義は?

本日は清々しい五月晴れにもかかわらず------すがすがしいのスガって何だろうなぁ?-----、気分はとてもブルーなわたしです.目黒のegobarの15周年記念パーティーで今朝まで飲んでいたので二日酔いでグッタリしています.そろそろ復活してきたのでブログを書くことにしよう.

さて、なんでもシリーズ化してしまう当ブログですが、固定小数点演算による信号処理をシリーズ化しちゃおうかな.電気の知識とverilogを知らない人にはチンプンカンプンでしょうから、前もってスミマセンです

ちなみに、職業訓練住宅リフォームシリーズは未完なんです.エアコンの取付という興味深いことも習ったので、それを書かなくちゃいけないと思っています.わたしは、座学全般いわゆる習い事が退屈な人なので、小中高大と学校ってつまんねーと思って生活してきました.図工だけは燃えました.国語・体育・音楽は大嫌いでした.しかし、職業訓練は生まれて初めて楽しいと思いました.溶接を習いたかったなー.

話を固定小数点演算に戻します.

固定小数点演算信号処理についてverilog codeをごちゃごちゃ説明する前に、その存在意義とか効用を説明します.

Q: 信号処理とは?

A: デジタル信号処理が正式名称です.フィルタとか変調復調とかのようなかつてはアナログ回路で実現されていた機能を、デジタル回路でやっちゃおうということです.デジタル信号処理で実現すると、性能が10倍になって、大きさが1/10になって、価格が1/10になって、製品不良が1/10になります.

Q: 信号処理の効用は?

A1: 無線機のSSB変復調回路ですと、DBM(diode balanced mixer)でキャリアと信号をかけ算しますが、このかけ算回路が数式通りに動いてくれるわけがありませんで、offset、非直線性、gain誤差などを含んでます.すると、直流電圧が漏れてくる、キャリアが漏れてくる、スプリアスが漏れてくるなどの余計な信号まみれの汚い信号になってしまいます.
そういう汚い信号を強制的に綺麗にするために、フィルタを入れます.このフィルタがLCRで作った程度の安価なフィルタでは役に立たず、水晶をつかった高価で大型サイズのフィルタを使うしかなかったのがアナログ時代でした.
これをデジタル信号処理回路で実現すると、かけ算回路が理想的な数値処理になるので、キャリアやスプリアスが出てきません.外付け回路はDACとLCRフィルタだけで済みます.安価で小型で安定で不良も少なくなります.いまはもう昔ながらのXtal filterを使ったSSB回路は姿を消しました.

A2: デジタルオーディオですと、44.1kHzでサンプルされた信号を扱います.DACとアナログフィルタで音声に変換するのですが、フィルタの設計がかったるいことになります.fs=44.1kHzですから、22.05kHzが理論上限で、20kHzの音声帯域を確保するように設計します.したがってフィルタには20kHzまでフラットで22.05kHzで-80dBぐらいまで落とす急峻なフィルタが求められますが、そんな高性能なフィルタを設計するのはとても難しいです.
これをデジタル信号処理で一工夫してサンプルレートを10倍の441kHzに変換します.するとフィルタの要求仕様が、20kHzまでフラットで220.5kHzで-80dBまで落とせばOKという風に劇的に楽になります.いい加減な設計のフィルタで済ませられます.安価で小型で安定で不良も少なくなります.

Q: 消費電力は増えるんじゃないの?

A: 半導体製造プロセスが進歩したので、もはやこの懸念は杞憂と言える時代になったと思います.

Q: 上手に作られたアナログ回路の方が性能が良いのではないか?

A: 中にはそういう回路もあるとおもいます.

Q: ならばアナログ回路で努力しろ!

A: それがそうはいきません.アナログ回路には製造不良と市場不良がつきまとうからです.量産工場では、たかが1000台に1台の不良で関係各部署がてんやわんやしてしまいます.アナログ回路ですとその宿命から逃れられません.
なぜか? アナログ回路は、すげえ高性能にできた上澄みが10%、フツーが80%、出来の悪いのが10%のように性能が分布してしまいます.下位10%をスクリーニングする手間がかかります.せっかくスクリーニングしたのに、使用温度が高いと性能が劣化したりします.電気製品が夏に故障しやすいのはそんな理由です.
ところがデジタル回路ですと、フツーが100%になります.性能が分布しません.だから、量産が楽で、市場不良もなくなります.すげえ高性能な上位10%が姿を消してしまうことを悲しむよりも、全部がフツーでバシッと決まる予測可能性を尊ぶのが量産する人々の気持ちです.

ではまた次回.       つぎへ


人気ブログランキングへ