NES の符号化器と最初のデコーダ
M1 の報告書。作業の後に書いた。
走行スタンプ: 2026-09-01、このリポジトリの二つ目のコミット、rustc stable、
cargo test --workspace は 33 テスト緑、clippy も綺麗、MUTATE=1 は五つの
テストバイナリすべてにわたって 17 テストを赤にする。以下のどの数字も、ここに
書いた走行から貼ったもので、期待から打ち込んだものではない。M5 がそれらを
check-self-counts のスキャンの下に置く。
閉じたもの
新しいクレートが四つ。ntsc-testgen: 決定的な生成器たち (単色、64 x 8 の
掃引のパラメータ、パリティ列が Even/OddFull/Even と Even/OddShort/Even の
色相サイクル二組、縦縞)。ntsc-source-nes: 符号化器。レベルはゲートを通した
転写から build.rs を経て流れ込み、信号の関数はあのページ自身の NTSCsignal から
移植し、水平のセグメント表はあのページのタイミング表から。単純化が二つ、
モジュールの冒頭に記録してあり、どちらも M1 のオラクルには見えない。
ntsc-decode: ラング A。クロマは生成した帯域通過フィルタで、ルマはその厳密な
補数、QAM の復調は幾何的な位相で、行列は転写したもの、表示ガンマ 2.2 を記録。
ntsc-oracle: nes_ntsc 0.2.2 をネイティブにビルドしたもの、移植したパレットの
模型、比較用のリサンプラ、記録した位置合わせ、ゴールデンのテスト。
オラクル、ピン留め
blargg の正規 URL は死んでいる (slack.net は blargg.parodius.com へ張っていて、
そこは消えている。ITU 式の直接取得は 404)。出典: 正規 URL の Wayback Machine
2011-08-12 の収集、zip の sha256 は
ca1a420d721d83b944142c366a917ba199dbc10cf91ad6f21dc712ed1069d58e。
tools/fetch-oracle.sh が取得して検証し、コミットは決してしない (LGPL 2.1、
テスト専用)。設定は build.rs が生成してそこに記録する: NES_NTSC_EMPHASIS、
OUT_DEPTH 32、IN_T は unsigned short。composite プリセット。merge_fields は行の
比較では切り (プリセットは合成するが、フレームごとの位相が試験対象だ)、それ
以外では入れる。
src/blargg_model.rs は彼の色生成を 1 行ずつ移植したもので (LGPL、出典明記)、
比較の定数はすべてオラクル自身のソースの文面から来る。移植はコンパイルした
ライブラリに押さえてある:
512 のパレット項目すべてにわたって最悪の食い違いは 1.00 カウント
(the_port_reproduces_blarggs_own_palette)。これは整数への詰め方の分だ。
位置合わせ、実測してから凍結した
examples/align.rs が計器で、その 2026-09-01 の出力:
iq map: rotation 120.000 deg (spread 0.028), scale 0.78799
port vs compiled palette: worst 1.00 counts at entry 012
dc sweep (matched tail): base colours mean-of-worst 1.47, worst 5.48 at 002;
emphasis mean 14.13, worst 45.81 at 1d2
dc sweep (full pipeline): base colours mean-of-worst 23.02, worst 64.22 at 01c;
emphasis mean 18.91, worst 68.95 at 0ac
colour-cycle row 8: best mean abs diff 5.679 counts at burst0 2 offset -14.0
stripes row 8: best mean abs diff 18.033 counts at burst0 2 offset -11.8
(surface: -15.8: 29.4, -13.8: 30.2, -11.8: 18.0, -9.8: 23.5, -7.8: 26.4)
ntsc-oracle に凍結し、走行ごとにテストが検証し直す:
- IqMap: 鏡映、回転 120.0 度、倍率 0.78799。一つの剛体回転が、復調した
十二の色相すべてを blargg の (I, Q) の上に、広がり 0.028 度で写す。
the_iq_map_refits_to_its_frozen_constantsが走行ごとに再フィットする。 鏡映は YUV に対する YIQ の向きの違いだ。倍率は、彼の半振幅という取り決めと、 復調器の 4/pi の方形波基本波との違い (予測は pi/4 x 0.34/0.335 = 0.797、 実測 0.788)。回転は、彼の cos 表の向き、UV から IQ への 33 度、そして彼が 書き下ろした std_decoder_hue の -15 度をまとめ込んでいて、分解ではなく実測 として記録してある。 - RESAMPLE_OFFSET -11.8 標本、BURST0 2。 このオフセットは縞の走査から来る。 鋭い谷を持つ計器はそれだけだ。色相サイクルの平均と帯域端の窓はオフセットに 対してほぼ平坦だが、それぞれの最小値は同じ値のところに座る (5.70 と 6.42)。 Burst0 2 はどの走査でも満場一致だ。
ゲート: どの食い違いにも帰属先がある
比較 1、末尾を合わせたもの (こちらの復調した Y/U/V に、blargg 自身の移植した 行列、色相、ガンマを着せたもの) を、DC での彼のパレットに対して:
| 組 | 最悪値の平均 | 最悪 | 帰属先 |
|---|---|---|---|
| 基本色 64 個 | 1.47 カウント | 5.48 ($02) | blargg の小数二桁の正規化レベル (-0.12/0.00/0.31/0.72、0.40/0.68/1.00/1.00) 対 実測の表 |
| 強調の項目 448 個 | 14.13 | 45.81 ($1D2) | blargg の YIQ 空間での強調の近似 (atten_mul 0.79399、atten_sub 0.0782838、tint==7 の特例) 対 実測の減衰した電圧 |
比較 2、正直なパイプライン全体 (こちらの SMPTE 行列、こちらの表示ガンマ): 基本色の平均 23.0、最悪 64.2。二つの比較の差は、デコーダの選択そのものだ。 SMPTE 170M の行列を使う等帯域の YUV 対、-15 度回した彼の古典的 YIQ 行列と彼の 二次のガンマ (係数 pow(0.1333, 0.73))。表明ではなく報告する: どちらのデコーダも 正当で、サイトはこちらを見せ、そう述べる。
行の比較 (仕様が名付けた色相サイクルの二組、六フレームすべて、それぞれ連鎖した
原点と写したバーストで): 平均絶対差 5.7 カウント、包絡 10。残差は帯域端に住んで
いて、そこでは彼が書き下ろした DSF-sinc のルマとガウシアンのクロマのカーネルが、
こちらの窓関数付き sinc と違う。縞の行は 18.0 カウント、包絡 25。ドット周波数の
成分は二つのフィルタ設計がいちばん食い違うところで、blargg のアーティファクトと
フリンジの項 (設計上ラング A には無い) が住むところだ。二フレームの繰り返しは
写しを通しても見える: Even/OddShort はフレーム 2 をフレーム 0 のバーストへ戻し、
Even/OddFull は戻さない (the_two_frame_repeat_shows_through_the_mapping)。
既知のダイバージェンスは、どれにも名前があり、隠したものは無い: レベルの丸め、
強調の模型、基本波だけのクロマ (彼は方形波の高調波を決して模型化しない。こちら
のルマの補数はそれをリプルとして保つので、DC の比較は副搬送波 1 周期にわたって
平均する。solid_dc を見てほしい)、デコーダの行列と色相、ガンマの曲線、フィルタ
の設計、そして二つのパイプラインの間にあるクロマ対ルマの数標本の遅延のずれ
(彼のカーネルは設計上非対称、PIXEL_OFFSET -9..0)。だからどの単一のリサンプラの
オフセットも、すべての計器をゼロにはしない。
MUTATE と、試験装置自身が間違えていたこと
MUTATE=1 cargo test --workspace --no-fail-fast: 17 個が赤 (幾何 8、データ 3、
符号化器 3: 摂動を加えた符号化レベルに対するページの波形、バースト、セグメントの
テスト。復号 2: 摂動を加えた中央タップと係数に対する色相ラダーの振幅と行列の
配線。オラクル 1: 1.3 倍のクロマ利得に対する DC 掃引)。リサンプラとバーストは
代わりに常時オンの赤の証明を持つ (a_wrong_resampler_or_burst_is_detected):
1 ドットのずれは、位置合わせした縞の差の 1.8 倍を超えなければならず (実測
2.1 倍から 2.3 倍)、間違ったバーストは 2.5 倍 (実測 3.0 倍から 3.2 倍)。
M1 の間に測定で見つかった試験装置の欠陥が三つ。それぞれ修正の場所に記録した:
- クロマの帯域通過は狭帯域引く広帯域で生成されていて、通過帯域の利得は -0.907 だったが、生成器の利得のプローブが大きさを返していたので、色相ラダーが 180 度回って復号されるまで符号が隠れていた。応答はいま符号付きで、ゼロ位相の 形で記録する (tools/gen-filters.py)。
- リサンプラは 2048 標本を 602 画素へ一様に写していたが、blargg の 602 画素 は 258 ドットにわたる (入力 3 / 出力 7 の塊に黒の詰めもの)。つまり 0.8% の 傾きの誤りで、1 行にわたって 16 標本の漂流になり、どのオフセットの走査面も 平坦にしてしまっていた。傾きは厳密に 24/7 だ (resample_row)。
- 最初のオフセット走査の範囲 (+/-6) は最小値を含んでいなかった。そして 最初の align の走行は merge_fields を入れたカーネルに対して走査したのに、 テストは入れていないものを比べる。両方が -11.8 にある本当の谷を隠していた。 走査はいま、merge_fields を入れないオラクルに対して +/-20 だ。
記録としてもう一つ: 間違ったバーストの位相は、単色の領域では構造上見えない (彼の correct_errors はどのバーストのカーネルも同じ DC に強制する)。だから バーストの赤の証明は、すべてが端である縞の上に置いてある。
持ち越し
- M2 でラング D (ディレクターの判断)、加えてラング B と C、カラーバー、WASM の ビルド、そして実測のスループット表。
- yuv 行列の一次資料での確認 (SMPTE 170M-2004) を M2 で。
- 512 項目すべての DC 掃引は examples/align.rs で走る。テストの中の掃引は デバッグビルドの速さのための 72 項目の代表的な部分集合で、ここに記録した。
- blargg の setup の gamma、sharpness、resolution、artifacts、fringing、bleed の パラメータは、composite プリセットの値でのみ動かす。他のプリセットは目標では ない (仕様 4.1 節)。
ビルド時に ntsc-crt/docs/m1-report.md から取り込まれる。写しはリポジトリの一つだけだ。報告は独自の作業用の言葉をいくつか使う: 報告書で使われる言葉。