固定小数点DSP演算
浮動小数点ユニットを持たない安価なDSPやMCUでも、Qフォーマットで小数を整数演算に落とせば高速に信号処理できます。飽和・丸め・係数量子化の落とし穴を原理から押さえ、破綻しない実装を選べるようになります。
- 1.固定小数点は整数のビット位置に暗黙の小数点を固定する表現で、QmはLSBの重みが2^-mの小数を意味する。Q15なら16ビット整数を1でスケールした -1〜+1-2^-15 の範囲を表し、乗算はハードの整数乗算そのままで浮動小数点より高速・低電力・低コストになる。
- 2.積は桁が倍増しオーバーフローしやすい。ラップアラウンドは符号が反転して致命的なので、上限・下限でクリップする飽和演算を使う。Q15×Q15はQ30になるため、結果を左1ビットシフトしてQ31に整えるフラクショナルモードや、アキュムレータのガードビットで桁溢れを吸収する。
- 3.係数を有限ビットに丸めると極・ゼロがグリッド上の最寄り点へ移動し、遮断周波数のずれ・通過帯域リプレの増大・IIRでは不安定化を招く。高次を直接形で組まず2次のbiquad縦続に分解し、各段の極を安定領域に収めるのが実務の定石。
なぜ整数で小数を扱うのか
信号処理の核は乗算と加算の繰り返しです。浮動小数点ユニット(FPU)を持つプロセッサなら小数をそのまま扱えますが、安価なDSPコアや低消費電力のマイコンにはFPUがないか、あっても整数演算より遅く消費電力も大きいことが多いです。そこで固定小数点表現を使い、小数を整数のハードウェア乗算器・加算器だけで処理します。整数演算は1サイクルで完結しパイプラインも乱れないため、同じ電力・面積で桁違いのスループットが得られます。ここではその表現法・オーバーフロー対策・丸め・係数量子化の影響を原理レベルで開けます。数式は LaTeX を使わずプレーンな式で表します。
固定小数点の本質は、整数のビット列に対して小数点の位置を暗黙に固定する約束を置くことです。ビット列そのものはただの整数で、CPUは小数点を知りません。小数点位置を決めるのはプログラマの解釈だけであり、これが実行速度と誤差特性の両方を決めます。
Qフォーマット:小数点の位置を宣言する
固定小数点のビット配分を表す記法が Qフォーマット です。Qm.n は整数部 m ビット・小数部 n ビットを意味し、符号ビットを別に数えるか含めるかで流儀が分かれます。DSPで最頻出の Q15(=符号付き Q1.15)は、16ビットのうち符号1ビット+小数15ビットで、最下位ビット(LSB)の重みが 2 の -15 乗の小数を表します。
Q15 の値 = 整数値 / 2^15
範囲 : -1.0 〜 +1.0 - 2^-15 (= +0.999969...)
分解能 : 2^-15 ≒ 3.05e-5
例 : 0.5 → 0.5 × 32768 = 16384(整数として格納)
-1.0 → -32768
実数 x を Qm 表現に変換するには round(x × 2^m) で整数化し、戻すときは 2^m で割ります。整数どうしの加算・減算はスケールが同じならそのまま行えます(0.5 + 0.25 は 16384 + 8192 = 24576 = 0.75 × 32768)。信号を -1〜+1 に正規化して Q15 で扱うのがオーディオDSPの標準的な流儀で、フルスケールを 1.0 に固定することで後段のスケーリングが単純化します。
Q15 も Q31 も、CPUから見れば普通の16/32ビット整数です。同じビット列でも Q15 と解釈すれば約1、Q7 と解釈すれば約256を表します。したがって異なるQの値を混ぜて加算すると意味が壊れます。演算のたびに「いまオペランドは何Qか、結果は何Qか」を追跡することが固定小数点プログラミングの中心作業で、誤差やオーバーフローの多くはこのスケール管理ミスから生じます。
乗算とスケーリング:積は桁が倍になる
固定小数点で最も注意を要するのが乗算です。整数として掛けると小数部の桁が足し合わさるため、Qが変化します。
Q15 × Q15 の積:
(a × 2^15) × (b × 2^15) = (a×b) × 2^30 → 結果は Q30
16bit × 16bit = 32bit の積が得られ、
そのうち小数部は 30 ビットになる(Q30、符号2ビット相当)
Q15 どうしを掛けると結果は Q30 になり、16ビット×16ビット=32ビットの積が生じます。これを再び Q15 の16ビットに戻すには、15ビット右シフトしてから下位を丸め、上位16ビットを取り出します。多くのDSPには積をそのまま Q31 に整えるフラクショナルモード(積を自動で左1ビットシフトし Q30→Q31 化)があり、1.0 × 1.0 = 1.0 が符号ビットを侵さず表せるよう設計されています。
積和演算(MAC)を繰り返すFIRフィルタでは、32ビットや40ビットのアキュムレータに積を足し込み、最後にまとめてシフト・丸めするのが定石です。途中結果を毎回16ビットに丸めると誤差が累積しますが、広いアキュムレータに貯めれば中間のオーバーフローと丸め誤差の両方を抑えられます。DSPコアが40ビットアキュムレータ(32ビット+8ガードビット)を持つのは、256回程度の積和で桁上がりが上位へ溢れても吸収するためです。
オーバーフローと飽和:ラップは事故、クリップで守る
整数演算の桁が容量を超えるとオーバーフローします。通常の2の補数演算では上位ビットが捨てられてラップアラウンドし、最大値の少し上が一気に最小値(大きな負数)へ飛びます。信号処理でこれが起きると、ピークで波形が正から負へ反転し、原信号と無関係な巨大なパルス性の歪みになります——聴感上も制御上も破滅的です。
これを防ぐのが飽和演算(サチュレーション)です。結果が表現範囲を超えたら、ラップさせずに上限値または下限値でクリップします。
飽和(Q15, 16bit):
result > 32767 → 32767 にクリップ
result < -32768 → -32768 にクリップ
ラップ: 32768 → -32768(符号反転・破滅的)
飽和 : 32768 → 32767 (+1.0 で頭打ち・穏やか)
飽和でも情報は失われますが、波形は上端で平らに潰れるだけで符号は保たれ、過大入力時のアナログのクリップと同じ穏やかな歪みで済みます。多くのDSPは飽和を1命令・ゼロオーバーヘッドで行うハードを持ち、加算器・アキュムレータに飽和モードを備えます。この差は /dsp-control/fir-iir-filters/ の帰還を持つIIRで特に重要で、飽和がリミットサイクル(後述)を有界に抑える安全弁にもなります。
飽和は最後の防波堤であって、常用すれば信号が潰れ精度が落ちます。本筋は事前スケーリング——係数や信号をあらかじめ小さめに正規化し、積和の途中でアキュムレータ範囲を超えないよう設計することです。FIRなら「係数の絶対値総和 × 入力フルスケール」が取りうる最大出力なので、これがアキュムレータに収まるよう入力側で右シフト(ダウンスケール)しておきます。溢れる可能性を静的に見積もり、飽和が発火しない運用点に置くのが定石です。
丸め誤差:切り捨てはバイアスを生む
積を短いQへ戻すときの下位ビット処理には、**切り捨て(truncation)と四捨五入(rounding)**があります。切り捨ては単にビットを捨てるだけで速いのですが、2の補数では常に負方向へ丸まるため、平均が -0.5 LSB だけ偏る直流バイアスが生じます。フィルタを多段縦続すると各段のバイアスが積み上がり、無視できない直流オフセットになります。
丸め方式(下位ビット破棄時):
切り捨て : 常に下方向 → 平均 -0.5 LSB のバイアス(安価だが偏る)
四捨五入 : 破棄前に +0.5 LSB 加算してから切り捨て → 偏りゼロ(1加算のコスト)
四捨五入は破棄する直前に最上位破棄ビットへ +0.5 LSB を足してから切り捨てる操作で、バイアスを消せますが加算1回ぶんのコストが要ります。丸め誤差自体は最終的に丸め雑音として現れ、/dsp-control/quantization-adc-noise/ の量子化ノイズと同じく、1 LSB 幅の一様分布とみなせば電力は q^2/12(q はLSBの重み)で近似できます。バイアス(平均のずれ)と分散(雑音電力)は別物で、四捨五入はバイアスを消しますが分散はゼロにはなりません。
係数量子化:極・ゼロがグリッドに吸着する
設計時に計算したフィルタ係数は連続値ですが、実装では有限ビットに丸めます。この係数量子化が、フィルタの周波数特性を設計値から歪ませます。係数が離散グリッド上の最寄り値へ移ると、伝達関数の極とゼロが本来の位置から最寄りの格子点へ移動します。
FIRでは極を持たないため影響は緩やかで、通過帯域リプルの増大や遮断周波数の微小なずれにとどまり、安定性は保たれます(極が無いので発散しようがない)。一方 IIRは深刻です。極が単位円の内側ぎりぎりに置かれた高次フィルタを直接形で実装すると、係数のわずかな丸めで極が大きく動き、**単位円を越えて不安定化(発散)**しかねません。極の感度は次数が高いほど、また極が密集するほど跳ね上がります。
極の位置は分母多項式の係数に対して非線形かつ高感度に依存し、次数が高いほど1ビットの係数丸めが極を大きく動かします。対策は分解——高次伝達関数を2次のbiquadに因数分解して縦続(カスケード)し、各段は2つの極だけを扱います。2次なら極位置と係数の対応が直接的で、丸め後も各極を単位円内の狙った位置に保ちやすい。実務ではIIRを必ずbiquad段の積として実装し、段の順序やスケーリング(縦続配置の並べ替え)でオーバーフローと雑音も最適化します。詳細は /dsp-control/z-transform-systems/ の極・零点と単位円の議論と合わせて押さえてください。
さらに固定小数点IIR特有の現象がリミットサイクルです。入力がゼロや一定値になっても、帰還ループ内の丸め・切り捨ての非線形性が原因で、出力が小振幅の周期振動として居座り続けることがあります。丸めによる微小誤差が帰還で自分自身を養い、静止すべき出力が数LSB幅で振動する現象で、飽和や特定の丸め則(大きさ切り捨て等)で有界化・抑制します。
| 観点 | 固定小数点 | 浮動小数点 |
|---|---|---|
| 表現 | 整数+暗黙の固定小数点(Qm) | 仮数+指数(動く小数点) |
| ダイナミックレンジ | 狭い(Qで固定、要スケーリング) | 広い(指数で自動追従) |
| 速度・電力・面積 | 高速・低電力・小面積・安価 | 遅い/FPU分の電力・面積・コスト |
| オーバーフロー | 頻発。飽和とスケーリングで管理 | 指数が吸収しほぼ起きない |
| 丸め誤差の見積り | 全域一様(LSB固定)で解析しやすい | 値の大きさに比例(相対誤差一定) |
| 主な用途 | MCU・DSPコア・低消費電力な組込み | 高精度計算・PC・GPU・DSP上位機 |
実装の勘所
固定小数点DSPを破綻させないための要点をまとめます。第一にスケールの追跡——全オペランドと結果のQを常に把握し、加算はスケールを揃え、乗算はQの加算を意識して結果を正しいQへシフトで戻します。第二に溢れの静的見積り——係数総和や信号のピークからアキュムレータの必要ビット幅を算出し、事前スケーリングで飽和が常態化しない運用点に置きます。第三に構造の選択——IIRはbiquad縦続、必要なら広いアキュムレータとガードビットで中間精度を確保します。
- Qフォーマット:
QmはLSB重み2^-m。Q15は16ビットで -1〜+1-2^-15、値は整数/2^15。 - 乗算のQ:
Q15 × Q15 = Q30。16bit×16bit=32bit積。15ビットシフトで Q15 に復帰、フラクショナルモードで Q31 化。 - 飽和 vs ラップ:ラップは符号反転で破滅的、飽和は上下限クリップで穏やか。過大入力の安全弁。
- 丸め:切り捨ては -0.5 LSB のバイアス、四捨五入は +0.5 LSB 加算で偏り除去。丸め雑音電力は
q^2/12。 - 係数量子化:極・ゼロが最寄り格子点へ移動。FIRは緩やか、IIRは不安定化リスク。高次は biquad 縦続で回避。
- リミットサイクル:固定小数点IIRの帰還×丸めで生じる小振幅の残留振動。飽和・丸め則で抑制。
まとめ
固定小数点DSP演算は、FPUを持たない安価・低電力なプロセッサで信号処理を高速に回すための技術です。核心は、整数のビット列に暗黙の小数点を固定するQフォーマットで小数を整数演算に落とすこと。加算はスケールを揃えれば整数加算そのままですが、乗算は桁が倍増して Q15×Q15=Q30 となりシフトと丸めでQを整える必要があります。桁溢れは符号反転を招くラップではなく上下限でクリップする飽和で守り、本筋は事前スケーリングで溢れさせない設計です。下位ビットの処理では切り捨ての直流バイアスを避け四捨五入を選び、係数の有限ビット化は極・ゼロを格子点へ吸着させて特性を歪ませます——FIRは緩やかでもIIRは不安定化やリミットサイクルの危険があるため、必ず2次biquadの縦続に分解します。速度・電力・コストと引き換えに、狭いダイナミックレンジをスケーリングとオーバーフロー管理で御するのが固定小数点実装の本質です。/dsp-control/filter-design-windowing/ で設計したフィルタを実チップに載せる最終段が、この固定小数点化に他なりません。
信号処理・制御 Article
固定小数点DSP演算を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
固定小数点
比較で見る軸
難易度: advanced / カテゴリ: 信号処理・制御 / タグ数: 6
導入後に効く点
積は桁が倍増しオーバーフローしやすい。ラップアラウンドは符号が反転して致命的なので、上限・下限でクリップする飽和演算を使う。Q15×Q15はQ30になるため、結果を左1ビットシフトしてQ31に整えるフラクショナルモードや、アキュムレータのガードビットで桁溢れを吸収する。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- 信号処理・制御
- タグ数
- 6
判断チェックリスト
- 自社の用途が「固定小数点 / Qフォーマット」に近いか確認する。
- 強みである「固定小数点は整数のビット位置に暗黙の小数点を固定する表現で、QmはLSBの重みが2^-mの小数を意味する。Q15なら16ビット整数を1でスケールした -1〜+1-2^-15 の範囲を表し、乗算はハードの整数乗算そのままで浮動小数点より高速・低電力・低コストになる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。