移動平均フィルタとサンプル & ホールド
はじめに
サンプリング周期がであるサンプル & ホールド(S&H)の伝達関数は,近似的に
と書けることが知られています。 これは移動平均フィルタ(moving average filter, MAF)の伝達関数と完全に一致します。 何となくそうなりそうな気もしますし,本当にそうなのという疑念もあります。
そもそもS&Hに正弦波を入力しても,サンプリングするから出力はカクカクしているじゃないか❓ 高調波が含まれるけど,基本波成分だけを抽出するとそうなるということ─❓
時間領域での波形を見てみると…確かに基本波成分は似ているように思えます。
という訳,LTspice XVIIで試してみることにしました。
まずはいきなり結果のボード線図を
後述の方法でボード線図を描くと,図2となります。
移動平均フィルタ(y_MAF,赤)とサンプル & ホールド(y_SH,青)のゲイン・位相がともに概ね一致しており,(1)式が成立していることを伺わせます。 y_SHが若干ギザギザしている理由は,入力信号の周期とサンプリング周期が整数倍になっていない周波数がほとんどであるため, 解析の最初と最後がつながらない波形となってしまうためと理解しています。
S&Hはサンプリング周期の半分 = 5 kHz以降はエイリアシングが起きているはずですが,基本波成分のみを抽出すると,MAFと一致して見えるんですね🎵
さて,これをどうやって描くのでしょうか❓
非線形なシステムのボード線図をどうにかして描く
線形なシステムのボード線図であれば,LTspice(に限らずSPICE全般)の.AC解析ですぐに求まります。 しかし,S&Hのような非線形の場合は? そもそも非線形なシステムではボード線図という概念は存在しないのですが, とりあえず,出力信号の中に入力信号の正弦波と同じ周波数成分(基本波成分)が含まれているのであれば, 出力信号からフーリエ解析で基本波成分を抽出してゲインと位相を求めることができ, ボード線図(のようなもの)を描くことができます。
LTspiceでは,概ね以下のような方法で非線形なシステムのボード線図を描くことができます*1。
- 過渡(.TRAN)解析において,入力信号(正弦波)と出力信号を得る
- .measコマンドを用いて,出力信号の基本波成分の実部と虚部(または振幅と位相)をフーリエ級数の基本波の係数を得る要領で抽出する(後述)
- 入力信号の周波数を.step paramコマンドで所望の範囲で変化させ,以上を繰り返す(.TRAN解析を繰り返すので時間を要します)
- 回路図(schematic)上で右クリックし,View -> SPICE Error Logをクリックしてエラーログを表示する
- .measコマンドで得た基本波成分が.step paramで設定した各周波数について得られていることが分かる
- エラーログ上で右クリックし,Plot .step'ed .meas dataをクリックする
- 複素数として統合できるデータ(後述)がある場合は統合するか問われるので「はい(Y)」をクリックする
- プロットウィンドウが表示されるので,右クリックしてAdd tracesを選び,.measコマンドで得た出力信号の基本波成分を選択する
- ボード線図が表示される
端折っていますが,このような流れです。 ちょっと難しいのは,.measコマンドにて基本波成分を抽出する部分ですね。 また,求めたい伝達関数の入力信号自体が独立した電圧源ではない場合, 入力信号についても.measコマンドでその実部と虚部(または振幅と位相)を抽出する必要があります。
シミュレーション
実際に,MAFとS&Hを並べて比較してみました。 MAFは連続時間線形システムなので,本来は上述の方法を使わなくても.AC解析でボード線図を描けるのですが, S&Hと比較するために,同じく.TRAN解析を使う周波数応答解析(frequency response analysis, FRA)を適用します。
今回は入力信号が1 Vの正弦波電圧源(初期位相を90°に設定してcos波としています)として既知なので, ボード線図を求める際に入力信号で割る(振幅: 割る,位相: 引く)ということはしていません。
図1に置いたSPICE directive(ドットコマンド(dot command)とも)は以下の通りです。
.tran 0 {110/f} {10/f} uic .param Ts=100u ; f=7k .save V(u) V(y_MAF) V(y_SH) .step dec param f 1k 100k 100 .meas y_MAFave AVG V(y_MAF) .meas y_MAFre AVG 2*(V(y_MAF)-y_MAFave)*cos(360*f*time) .meas y_MAFim AVG -2*(V(y_MAF)-y_MAFave)*sin(360*f*time) .meas y_SHave AVG V(y_SH) .meas y_SHre AVG 2*(V(y_SH)-y_SHave)*cos(360*f*time) .meas y_SHim AVG -2*(V(y_SH)-y_SHave)*sin(360*f*time)
1行目では.TRAN解析する時間を設定しています。 パラメータfは入力信号の周波数です。 波形保存の開始を10/fすなわちシミュレーション開始から10周期後, 波形保存の終了を110/fすなわち同じく110周期後としています。 したがって都合100周期分のデータを集めています。 また,設定しないとMAFの挙動がおかしくなるため,uicを付しています。
2行目ではサンプリング周期Tsを100 μsに設定しました。f=7k
はコメントアウトしています。
3行目では,保存する値として入力電圧V(u),MAFの出力電圧V(y_MAF),S&Hの出力電圧V(y_SH)の3つのみを指定しています。
4行目では.step paramコマンドにて周波数fを1 kHzから100 kHzまで,100ケース/decで振っています。
5 ~ 7行目ではMAFの出力電圧V(y_MAF)の基本波成分の実部(cos成分)と虚部(sin成分)を求めています。 5行目では,MAFの出力電圧V(y_MAF)の平均値(直流成分)を演算しています。 今回は「ある動作点で運転しているシステムに摂動を重畳し,小信号特性を得る」といった使い方ではないため,この行は不要かもしれません。 6行目でV(y_MAF)から直流成分を減じたものと基本波のcos波を乗算し,その平均値を計算することでcos成分,いわゆるフーリエ級数のを得ます。 7行目で同じくsin成分,フーリエ級数のを得ますが,ボード線図では位相が遅れている方を負に取りたいので符号を反転しています。 ここでは,1行目で設定したように,100周期にわたるデータから係数を求めています。
8 ~ 10行目では同じくS&Hの出力電圧V(y_SH)の実部(cos成分)と虚部(sin成分)を求めています。
ここで重要なのが,.measコマンドの結果のラベルの末尾に「re」,「im」を付しておくことです。 これをしていないと,後でボード線図を描く際に,1つの複素数として統合されません。 LTspiceのヘルプファイルにも文献*1にも記載が無いので,どのような条件で複素数として統合されるのか分からなかったのですが, どうやらラベル名の末尾文字に「re」と「im」とついている信号が1セットあれば,これを1つの複素数として統合してくれるようです。
また,今回は使いませんでしたが「mag」,「phi」を付していれば,極座標表示の複素数として統合されるようです。 この場合,絶対値は[dB]表記を前提としており,元の振幅がならばあらかじめとしておかなければならないようです。
準備ができたらRunします。
ボード線図を表示するまで
図3の場合,.step paramで設定したように201ケースの.TRAN解析が走りますので,数分の時間を要します。 すべての.stepの解析が完了したら,前述のように回路図上で右クリックし,View -> SPICE Error Logを選択します。
特に「エラー」ではないので,単にSPICE Logと呼んでほしいですね…💦
表示されたエラーログ上でさらに右クリックすると,図5のようにPlot .step'ed .meas dataが表示されますのでクリックします。
すると,前述のように複素数として統合できるデータが存在するので,図6のように統合してよいかを問われます。
「はい(Y)」をクリックすると,プロットウィンドウが表示されるので,後は普段通りAdd Tracesでプロットするデータを選択します。 結果が前述の図2となります。
ちなみに,基本波100周期ではなく,20周期のみのデータから基本波成分を抽出してボード線図を描いてみると,
このようになります。 かなりギザギザしていますが,これは解析の最初と最後でつながらない波形となっているためと考えられます。