プローブを補正すれば元の回路が見える?
目標
補償した画面が正確だという事実と、元の回路をほとんど変えなかったという事実を、分けて検証します。実際のngspiceのファイルを読み、プローブの選択根拠を再現するPythonのCLIを書きます。
なぜ重要なのか
前のフィルター応答の単元と、Pythonの関数・ファイル・複素数・list・dict・例外を理解してから始めてください。ラボの想定所要時間は120分です。基本の60分が終わる前に、+時間で延長でき、最大は180分です。セッションが終わるとファイルが消えるので、必要なコード・レポートを、別に保管してください。このラボは、理想的な1V回路のシミュレーションだけを使い、実際の機器・高電圧・接地の接続は扱いません。
環境と材料
成果物は、/root/probe-loading/analyze.pyです。Python3とngspice(バージョン42)はイメージにあり、外部からのダウンロードや追加の権限は必要ありません。/opt/lab/fixtures/probe_loadingをsys.pathに追加すれば、simulatorをimportできます。提供されるcapture(cfg,新しいフォルダー)は、回路を実際に実行して、そのフォルダーのPathを返します。親フォルダーはすでにある必要があり、既存の出力フォルダーは上書きしません。input.cir・config.json・solver.log・ac.tsv・step.tsvを残し、失敗した新しい証拠も消しません。
回路の構造と値は、前の理論の理想モデルです。同じ理想入力から、別々のRsを通して、参照のrefと、測定対象のtipを駆動します。2つのノードそれぞれのDUTは、100kΩ∥20pFです。プローブは、tip側にだけ付きます。unloadedは、追加の負荷がなく、meter=tip、one-xは1MΩ∥100pF、activeは1MΩ∥1pFと、理想のmeter=tipです。ten-xは、tip→meterに9MΩ∥comp_pf、meter→接地に1MΩ∥90pFがあります。表示値は、ten-xではmeter×10、それ以外はmeterです。
AC入力は、ac_vの振幅・17度の位相です。ステップは、0–1µsに0V、その後5nsで1Vに上昇し、50µsまで維持されます。ac_vは、AC解析にだけ適用されます。activeの無限の帯域幅・理想的な出力は、教育用のモデルであり、市販の製品の仕様ではありません。
設定の契約
configは、正確に以下の5つのキーを持つdictだけを受け付けます。数値は、intとfloatだけを許容し、bool・文字列・NaN・無限大・floatの変換範囲の超過は、ValueErrorです。数値はfloat、kindはstr、補償がない場合のcomp_pfはNoneとして返します。入力は変更しません。
| キー | 許容される値 |
|---|---|
| kind | unloaded、one-x、ten-x、active |
| rs_ohm | 10000または50000 |
| comp_pf | ten-xなら5、10、20。他はNoneだけ |
| dt_s | 1.25e-9または6.25e-10 |
| ac_v | 0.5、1、2 |
AC入力と応答の契約
read_acは、通常のファイル・最大1MiBを受け付けます。ヘッダーは、空白で区切ったfrequency v(in) v(in) v(ref) v(ref) v(tip) v(tip) v(meter) v(meter)です。各組は、実部・虚部の順です。空行を無視し、正確に241行の、有限のfloat9個を読みます。電圧成分の絶対値は1e6以下、入力・ref・tipの複素の大きさは1e-12以上でなければなりません。meterは0でもかまいません。周波数は、正の数で厳密に増加し、各i=0..240で、10*10**(i/40)と、相対1e-10または絶対1e-9以内で等しくなければなりません。10Hz–10MHzの内部の格子も、すべて確認してください。内容のエラーはValueError、OSのファイルエラーは、そのまま伝えてもかまいません。戻り値は、9個のfloatのtupleのlistです。
responseは、設定を検証し、上の契約どおりに検証済みのrowsを受け取ります。行を変えずに、同じ順序のdictのリストを返します。R=Vref/Vin、T=Vtip/Vin、D=倍率*Vmeter/Vinとするとき、各フィールドは次のとおりです。
- frequency_hz: 元の周波数。
- reference、tip、display: R、T、Dの[実部,虚部]のリスト。
- chain_error: abs(D/T−1)。単純な大きさの差ではなく、複素誤差です。
- loading_error: abs(T/R−1)。
- loading_gain: abs(T/R)。
- loading_phase_deg: degrees(cmath.phase(T/R))。主位相です。
モデルとステップ観測の契約
transferは、configで設定を検査し、0≤freq≤1e9の有限の数値を受け付けます。bool・文字列・範囲外はValueErrorです。この周波数範囲は、理想的な式の計算領域であり、プローブの実際の1GHzの帯域幅を意味しません。シミュレーションファイルの格子は、上の10Hz–10MHzで、別に制限します。出力の丸めで、10MHzの端点がごくわずか大きくなっても、有効なACファイルを、モデル関数が拒否しないように、2つの契約を区別してください。
戻り値は、reference・tip・meterをキーとする、complexのdictです。s=2jπf、Ydut=1/100000+s20e-12、R=1/(1+RsYdut)です。unloadedは、3つの値すべてがRです。one-x・activeは、Yprobe=1/1e6+sCprobeで、Cprobeはそれぞれ100e-12、1e-12です。T=1/(1+Rs(Ydut+Yprobe))、M=Tです。ten-xは、Za=1/(1/9e6+scomp_pf1e-12)、Zb=1/(1/1e6+s90e-12)、T=1/(1+Rs(Ydut+1/(Za+Zb)))、M=T*Zb/(Za+Zb)です。meterには、表示倍率をまだ適用しません。
提供されるload_step(path)は、通常のファイル・最大16MiB、time v(in) v(ref) v(tip) v(meter)のヘッダーの、5列のtupleのリストを返します。2–200000行、すべて有限の数値、電圧成分の絶対値≤1e6、時間は0以上・厳密に増加、最初の時間≤1ns、最後は50µsから1e-12秒以内です。内容のエラーはValueErrorです。このローダーは、再実装する必要はありません。
observeは、設定を検査し、load_stepを使って、t=1.005e-6+i1e-8(i=0..1999)で、ref・tip・meterを線形補間します。ちょうど同じ時刻の行は、そのまま読み、外挿はValueErrorです。戻り値は、reference_v・tip_v・display_v(それぞれ2000個の電圧のリスト)、grid_step_s=1e-8、observation_end_s=1.005e-6+19991e-8、chain_error_v=max|display−tip|、loading_error_v=max|tip−reference|、display_error_v=max|display−reference|です。displayにだけ、表示倍率を適用します。これは、有限の観測格子での比較であり、連続時間全体の最大値の証明ではありません。
判定とレポートの契約
assessは、設定を検証し、正常なresponseのリストと、observeのレポートを受け取ります。中間レポートの構造の検証を、繰り返す必要はありません。次の要求は、このラボで宣言した設計契約であり、業界標準の合格ラインではありません。
- max_model_error: AC241点それぞれのreference・tip・displayと、transferのreference・tip・倍率*meterの間の、複素差の大きさの最大値。単位はゲインです。
- model_consistent: 上の誤差≤1e-8。
- chain_ok: 100kHzのsweep[160]のchain_error≤.01。
- loading_ok: 同じ点のloading_error≤.02。
- step_ok: display_error_v≤.03V。
- eligible: kindがunloadedではないこと。
- all_pass: model_consistent・chain_ok・loading_ok・step_ok・eligibleが、すべてTrue。
analyze(value,folder)は、config、read_ac(folder/ac.tsv)、response、observe(folder/step.tsv)、assessをつなぎます。戻り値は、schema=1、config、sweep、step、assessmentです。元の設定とファイルは保存し、エラーは伝えます。
条件比較とCLIの契約
campaign(values,runner)は、正確にlistの、2–6個の設定を、すべて先に検証します。すべての入力のdt_sは、既定の1.25e-9でなければならず、1つでも違えば、runnerの呼び出しの前にValueErrorです。各条件ごとに、runner(既定の設定のコピー)→analyze、dt_sだけを6.25e-10に変えた新しい設定で、runner→analyzeを、順に行います。1つの条件を終えた後に、次の条件に進みます。元の入力は変更せず、runnerのエラーは伝えます。
戻り値は、schema=1、runs、candidate_indices、scope='ideal-probe-chain-and-loaded-circuit'です。runsは入力の順に、coarse・fine(それぞれanalyzeのレポート)、difference_v(3つの電圧リストの、同じ時刻どうしの差の最大値)、converged(difference_v≤1e-5V)を持ちます。表示値だけでなく、reference_v・tip_vも比べます。candidate_indicesは、収束していて、coarse・fineのassessment.all_passが、どちらもTrueの条件の、0始まりのインデックスのリストです。空の候補は正常な結果であり、実行エラーとは違います。
main(argv)は、設定リストのJSONファイルと、まだ存在しない出力フォルダーのパスを受け取ります。引数の数・すべての設定・既定のdtを確認してから、新しいフォルダーを作ります。親は、すでにある必要があり、既存のフォルダーは拒否します。runnerの呼び出し順に、run-00、run-01、...で、提供されるcaptureを実行します。結果を、stdoutに有効なJSON1行で出力して、0を返します。引数・設定・ファイル・実行のExceptionには、{"error":"analysis_failed"}の1行と2を返し、tracebackは出力しません。失敗しても、すでに作った新しい証拠は消しません。importのときは、CLIは実行されず、直接実行するときだけ、mainの戻り値で終了します。
提供される/opt/lab/fixtures/probe_loading/cases.jsonの6つの条件を、次のように新しい名前で実行します。レポートのリダイレクトも、既存のファイルを上書きしないパスを選んでください。
python3 /root/probe-loading/analyze.py /opt/lab/fixtures/probe_loading/cases.json /root/probe-loading/trial-01 > /root/probe-loading/report-01.json
ステップ
- 実行の前にプローブ条件を検証する: config(value)を実装します。以下の設定の契約を検査し、数値をfloatに変えた新しいdictを返してください。元の入力は保存し、不正な値はValueErrorで拒否します。
- 入力と3つのノードの複素電圧を読む: read_ac(path)を追加します。以下の9列・241行・周波数格子の契約を検査し、floatのtupleのリストを返してください。
- 画面の誤差と負荷の誤差を分ける: response(value,rows)を追加します。入力で正規化したreference・tip・display、および複素比の誤差・大きさ・位相を、以下の形式で返してください。
- プローブが付いた回路を計算する: transfer(value,freq)を追加します。理論の、負荷を含むモデルで、reference・tip・meterの伝達関数を、complexの値で返してください。
- 同じ時刻で、3つの波形を比べる: observe(value,path)を追加します。提供されるload_stepで波形を読み、指定された2000個の時刻の、3つの電圧と最大の差を計算してください。
- モデルの一致と設計への適合性を区別する: assess(value,sweep,step)を追加します。全体の複素モデルの検証、100kHzのチェーン・負荷の要求、ステップの要求、候補の資格を、別々に判定してください。
- 元のファイルから分析レポートをつなぐ: analyze(value,folder)を追加します。設定・AC・ステップの分析と判定をつないで、中間結果まで保存したレポートを返してください。
- 2つの精度と、実際の実行を突き合わせる: campaign(values,runner)、main(argv)、CLIのエントリーポイントを追加します。設定をすべて先に検証してから、基本・精密の計算の、3つのノードの収束と、両方の適合性を満たす候補を選んでください。
参考
採点は、独立した数式・合成ファイルを使う関数の検査と、実際のngspice・別のCLIの検査を、区別します。学習者のコードとフォルダーは変更しません。既定の条件の候補のインデックスをハードコードすると、別のソース抵抗・振幅・補償条件で失敗します。このモデルで、実際のプローブの安全等級・接地・ノイズ・帯域幅・温度の信頼性を、認証することはできません。
実行の前にプローブ条件を検証する
config(value)を実装します。以下の設定の契約を検査し、数値をfloatに変えた新しいdictを返してください。元の入力は保存し、不正な値はValueErrorで拒否します。
boolはintのサブタイプですが、この契約の数値ではありません。補償Cは、ten-xにだけ存在します。
入力と3つのノードの複素電圧を読む
read_ac(path)を追加します。以下の9列・241行・周波数格子の契約を検査し、floatのtupleのリストを返してください。
参照ノードとtipも、割り算の分母です。ヘッダーと両端だけでなく、すべての内部の周波数を確認してください。
画面の誤差と負荷の誤差を分ける
response(value,rows)を追加します。入力で正規化したreference・tip・display、および複素比の誤差・大きさ・位相を、以下の形式で返してください。
10倍の表示は、meterにだけ適用します。大きさの比が1でも、位相が違えば、複素誤差は0ではありません。
プローブが付いた回路を計算する
transfer(value,freq)を追加します。理論の、負荷を含むモデルで、reference・tip・meterの伝達関数を、complexの値で返してください。
補償の時定数が同じでも、プローブの入力インピーダンスは無限大ではありません。DUTと並列のプローブ負荷を計算してください。
同じ時刻で、3つの波形を比べる
observe(value,path)を追加します。提供されるload_stepで波形を読み、指定された2000個の時刻の、3つの電圧と最大の差を計算してください。
入力電圧の列を、参照電圧として読まないでください。元の時間のリストを1回だけ作れば、補間の探索が速くなります。
モデルの一致と設計への適合性を区別する
assess(value,sweep,step)を追加します。全体の複素モデルの検証、100kHzのチェーン・負荷の要求、ステップの要求、候補の資格を、別々に判定してください。
unloadedは、比較の基準です。誤差が最も小さくても、購入したり接続したりするプローブの候補ではありません。
元のファイルから分析レポートをつなぐ
analyze(value,folder)を追加します。設定・AC・ステップの分析と判定をつないで、中間結果まで保存したレポートを返してください。
ten-xをunloadedに置き換えてステップの分析に渡すと、画面の倍率が消えます。同じ設定を最後まで渡してください。
2つの精度と、実際の実行を突き合わせる
campaign(values,runner)、main(argv)、CLIのエントリーポイントを追加します。設定をすべて先に検証してから、基本・精密の計算の、3つのノードの収束と、両方の適合性を満たす候補を選んでください。
精密な計算で脱落した結果を、基本の計算の成功で上書きしません。生成した元の資料とレポートの一致も、検査します。