Wikipedia の LDPC の項だけ読むとそんな難しくなさそうに見えるけど、実際に実装しようと思うと、むちゃくちゃ難しい。

H行列 (パリティ検査行列) が難しい

LDPC符号の設計では、性能に優れたパリティ検査行列(H行列)を用意するのがまず難しい。ここにいろんな要素がある。

  • 正則(regular)か(各ノードの次数が一定)
  • 構造的な性質(たとえば巡回構造をもつ QC-LDPC など)を持つか (復号効率に影響する)
  • 系統的符号化 が可能な構造(systematic) を持つか(これは生成行列側の問題)
  • girth(ループの最小長): Tannerグラフにおいて短いサイクルは復号性能を劣化させるため、girthが大きい方が望ましい。

数学的素養がないと難しすぎる。そして自力で設計するのは考えたくない。

Protographが難しい

そんなH行列、例え1つ設計できたとしても、任意のデータ長・符号化率を持つH行列をいくつも作ろうと思うと何倍も大変になってしまう。

そこで Protograph (原始グラフ) という性質の良い原型となるような小さなグラフをまず設計し、それを何らかの方法で拡大して任意の大きさのH行列を得るという設計方法がある。

パンクチャリングが難しい

パンクチャリングは性質の良いH行列を使うために,多少の計算効率を犠牲にしつつ柔軟な送信ビット長/符号化率を得るための方法といえる

良い性質の Protograph を得られたとしても、それを拡大するプロセスには制約がある。整数倍の行列しか作れないとか。

そうなると求めるデータ長・符号化率ぴったりの行列というのは結局作れない。

これを解決するのがパンクチャリング。符号化率の低い(0.4など)のProtographを拡大し、欲しい符号化率 (0.5など)になるまでパリティビットの一部を送信しないことで、ちょうどいいサイズを作れる。

ぴったりよりも大きい行列を使うので計算コストは増えるが、高性能なH行列設計を流用できるという利点がある。

エンコードもデコードも難しい

エンコードは既知の操作するだけやろ? という気持ちを打ち砕く。どっちも難しい。なんならデコードのほうが簡単かもしれない

  • エンコードは生成行列(G行列)を得る必要がある。任意のH行列に対してG行列を導出するのが難しい。
  • デコードには、確率伝播(Belief Propagation)アルゴリズムに基づく Sum-Product 法や、近似的な Min-Sum 法などがある。どちらもTannerグラフ上での繰り返し計算を必要とし、実装や収束性で難しい
  1. トップ
  2. tech
  3. LDPC難しすぎる

ただの時報

https://play-morse.lowreal.net/jiho.html

むかーーし作った時報のコードを発掘した。今なら Voicevox つけたらちゃんと喋る時報にできるぞと思ったのでガっとやった。正午だけ特殊なのでレアです。

短波JJYの再現

https://play-morse.lowreal.net/vhf-jjy.html

VHF JJYの再現スクリプトのほうも時報音声を入れるようにした。こっちは10分ごとにしか喋らないのでレアです。

文字スクロール動画ジェネレーターというのを作った。

別のプロジェクトでffmpeg.wasmを使ってて面白かったので、もうちょっとわかりやすい応用を作ってみようという感じ。

Twitter はほぼそのまま再生されるけど、 Bluesky だとフレームレートが低くなっちゃうっぽい?

MediaRecorder vs ffmpeg.wasm

このジェネレータでは使ってないが、MediaRecorderというブラウザでcanvasを録画する標準機能がある。面白い機能なんだけどいくつか問題がある

  • 出力フォーマットがブラウザ依存かつ限られる
    • Chrome だと vp9+webm とか
    • ダウンロードして編集ソフトに持っていくと読みこめなかったりする
  • フレームレート可変になる
    • これもブラウザ依存だけど、canvas の dirty さを監視してて dirty なフレームしか記録しないようだ
    • ダウンロードして編集ソフトに持っていくと読みこめなかったりする
  • リアルタイムでしか収録できない
    • n秒録画するためにはn秒レンダリングして待つ必要がある
  • 尻切れ
    • なんかよくわからないが stop() したタイミングでうまく canvas を読んでくれない? みたい

ということで面白いけど使いにくい機能になっている。

「ダウンロードして編集ソフトに持っていくと読みこめなかったりする」を解決するために、MediaRecorder で録画したファイルを ffmpeg.wasm に読みこませてトランスコードする、という方針をとったりしていたけど、だったら直接 ffmpeg.wasm にフレーム画像全部渡せばいいとなり、MediaRecorder を使うのをやめてしまった。

MediaRecorder の使い道はストリーミングとかなんだろう。

  1. トップ
  2. tech
  3. 文字スクロール動画ジェネレーター

UHS-II 対応で USB 3.2 Gen1 接続し、最大 200MB/s ぐらいの読み込み速度が出るはずなのに、速度が出ないときの原因

40MB/s ぐらいで止まる

USB2.0 が 480Mbps(60MB/s)なので、実効速度40MB/s程度ぐらいで止まりうる。

原因

  • USB Type-A をゆっくりさしこむと USB2.0 で接続されてしまうことがある
    • 3.0 用の接点が奥にあるため
  • ケーブルが USB3.0 に対応していない (無結線)
    • 充電用ケーブルはダメです。柔らかいケーブルはだいたいダメです
  • ケーブルのコネクタとデバイスの相性が悪い (接触不良)
    • デバイス側コネクタが劣化してたりするとありうる
  • ケーブルの品質が低い
    • ケーブル品質が低すぎてUSB3.0のネゴシエーションに失敗すると USB2.0 にフォールバックします。

試してみること

  • Type-A なら一気に刺しこむ
  • Type-C で接続する
  • ケーブルをいろいろ変える
  • デバイスを変えてみる

90MB/s ぐらいで止まる

SD カードが UHS-I動作(104MB/s理論値)している可能性がある

原因

  • カードリーダーが非対応
  • カードリーダーの接触不良
  • カードの接点不良

試してみること

  • カードリーダーを変える
  • 接点復活剤をかけてみる
  1. トップ
  2. tech
  3. SDカードリーダーの速度が出ないときの挙動チェックリスト

5Gbps / 10Gbps 対応の通信用ケーブルは購入したら必ずベンチをとるべき。

というのも粗悪品であっても再送制御などで実行速度が下がるだけで通信できることが多いため、気付きにくいから。

1GB/s で読める SSD なのに、400MB/s でしか読めないということが起こりうる (10Gbps でリンクできず、5Gbpsにフォールバックしている)。一見動いてしまうので気付きにくいが実行速度が半分以下なのは相当信号状態が悪い。まずできるだけ短くて信頼できるメーカーの通信ケーブルを買うべき。

ケーブルやコネクタの見た目がよくても騙されてはいけない。うちでいろいろ検証した結果、エレコムの見た目しょぼいケーブルのほうが一番まともだった。

エレコム USBケーブル Type C (USB A to USB C) 1.0m USB3.1認証品 3A出力 最大10Gbps ブラック USB3-AC10NBK - エレコム(ELECOM)

エレコム(ELECOM)

5.0 / 5.0

スループットの目安

  • USB 2.0 480Mbps ~35-40MB/s
  • USB 3.2 Gen1 5Gbps ~400-450MB/s
  • USB 3.2 Gen2 10Gbps ~800-1000MB/s
  • USB 3.2 Gen2x2 20Gbps ~1600-1700MB/s

USB3はLTSSM(Link Training and Status State Machine)のトレーニングプロセスでリンクスピードを決めている。ここで10Gbpsでリンクできる品質にないと判断されると下の規格にフォールバックする。

10Gbps 以上は特に物理的に厳しい

1m以上で 10Gbps を謳っているものはまず嘘なので買うべきではない。10Gbps のパッシブな「延長ケーブル」もありえない。

  1. トップ
  2. tech
  3. 粗悪品のUSBケーブルが多いので買ったら必ずベンチをとるべき

https://www.uwe-sieber.de/usbtreeview_e.html USB Device Tree Viewer を使うのが早い。Windows 標準機能ではわからない。クソ (macOS のあなたは「システム情報」→「ハードウェア」→「USB」でわかります。良かったですね)

USB Device Tree Viewer の表示もそれほど分かりやすいとはいえない。以下が頭に入ってないといけない。

  • Low Speed = 1.5 Mbps (USB 1.0+)
  • Full Speed = 12 Mbps (USB 1.1+)
  • High Speed = 480 Mbps (USB 2.0)
  • SuperSpeed = 5 Gbps (USB 3.0 = USB 3.1 Gen1 = USB 3.2 Gen1)
  • SuperSpeed+ = 10 Gbps (USB 3.1 Gen2 = USB 3.2 Gen2)

アイコンにSがついてればSuperSpeed以上、HはHigh Speed、F は Full Speed

そして USB3系と USB2系は完全に別レイヤーで二重になっているという点を理解している必要がある。例えば USB3 のハブを繋いだら、必ず USB3 のハブと USB2 のハブが2つ表示され、ポートもそれぞれ別々に表示される。


3.2 Gen 2 (10Gbps) のハブ

       ========================== Summary =========================
 Vendor ID                : 0x05E3 (Genesys Logic, Inc.)
 Product ID               : 0x0625
 USB Version              : 3.2 Gen 2
 Port maximum Speed       : SuperSpeedPlus or higher
 Device maximum Speed     : SuperSpeedPlus or higher
 Device Connection Speed  : SuperSpeedPlus or higher
 Self powered             : yes
 Demanded Current         : 0 mA
 Used Endpoints           : 2

USB 2.0 のハブ (ただし USB3.0 のハブと物理的にポートを共有している)

       ========================== Summary =========================
 Vendor ID                : 0x1397 (Behringer Spezielle Studiotechnik GmbH)
 Product ID               : 0x0507
 USB Version              : 2.0
 Port maximum Speed       : High-Speed (Companion Port 1-20-4 is doing the SuperSpeed and SuperSpeedPlus or higher)
 Device maximum Speed     : High-Speed
 Device Connection Speed  : High-Speed
 Self powered             : no
 Demanded Current         : 500 mA
 Used Endpoints           : 1

USB 2.0 でポートスピードと接続スピードが違う場合

USB 3系と USB 2系は完全に分離しているので、Port maximum Speed が SuperSpeed で Device Connection Speed が Full-Speed ということは起こらない。

       ========================== Summary =========================
 Vendor ID                : 0x045E (Microsoft Corporation)
 Product ID               : 0x07A5
 USB Version              : 2.0 -> but Device is Full-Speed only
 Port maximum Speed       : High-Speed
 Device maximum Speed     : Full-Speed
 Device Connection Speed  : Full-Speed
 Self powered             : no
 Demanded Current         : 100 mA
 Used Endpoints           : 4
  1. トップ
  2. tech
  3. WindowsでのUSBリンクスピード

こういうのが500円で売っている。なんとなく買ってみた。

設定ツール (MINI KeyBoard.exe) が Google Drive で共有されて、そのQRコードがマニュアルにはってある。どう考えても実行するのは怖いので、まずは解析して設定ツールを自分で書くところからはじめる。

まぁそもそも、信頼できないデバイスをUSBで繋ぐなというのが正論だと思うが……

ILSpyで解析

MINI KeyBoard.exe は .NET アプリのようなので、ILSpy でデコンパイルできる。変なコードはとりあえず含まれていない。たぶん HID Report でなんかしてるだろうから、デコンパイルしたやつを Claude Code に読ませてプロトコルを解析してもらった。といってもそんなに精度高く解析はしてくれないので、結局自分でかなり勘を働かせて指示してやる必要があったけど……

WebHIDで再実装

ソフトは複数のミニキーボードに対応するものっぽいが、自分が持ってるのだけ設定できるツールを WebHID を使って作ってみた。というか Claude Code に作ってもらった。これに関しては完全に指示しかしてないはず。

https://github.com/cho45/webhid-mini-keyboard-configurator

WebHIDのセキュリティ……

Windows の Chrome / Edge で WebHID つかって動くことは確認済みなのだが、残念なことに動かないことがある。Chrome は WebHID に制限をかけていて、汎用キーボードっぽいものとかに対してはレポートの送受信ができないようになっている。この制限にひっかかったりひっかからなかったりする。

開発しはじめて動くまではまったくひっかからなかったのだが、できてからいろいろ試しはじめたらエラーが出たり出なかったりするように。Edge だと動いたり、しばらくたつと動かなかったり。かなりおかしな挙動をする。わけわかんない。

WebHID で作れば変なソフトインストールしないですむやん、というのが嬉しいポイントだけど、こんな挙動だと使えない。こまったねえ

関係ありそうなgithub project

カスタムファームウェア

そもそもファームから変えちゃおうってやつ

  1. トップ
  2. tech
  3. Aliexpress で買ったミニキーボードを WebHID で設定する

昨今の QNAP には Container Station というコンテナイメージを実行するためのオフィシャルなアプリケーションが提供されている。これを使えば特にQNAP用というわけではないコンテナイメージも自由に動かせて嬉しい。

例えば VOICEVOX のAPIを自宅内で自由に使えたらな~ と思うと、サーバとして常時動いていて、CPU的にも比較的遊びのある QNAP で動かせると嬉しい。HTTP リクエストさえできれば自宅内の Raspberry PI だろうがなんだろうが低スペPCからも音声合成ができる。

https://hub.docker.com/r/voicevox/voicevox_engine

Docker Hub にオフィシャルなイメージがあるので、これを pull する

Create Container で Publish New Port して 50021 を指定する。これで 192.168.5.250:50021 でアクセス可能になる。これだけ

 curl -X 'GET' \
   'http://192.168.0.177:50021/speakers' \
   -H 'accept: application/json'
   
   [
     {
       "name": "四国めたん",
       "speaker_uuid": "7ffcb7ce-00ec-4bdc-82cd-45a8889e43ff",
       "styles": [
         {
           "name": "ノーマル",
           "id": 2,
           "type": "talk"
         },
         {
           "name": "あまあま",
           "id": 0,
           "type": "talk"
         },
         {
           "name": "ツンツン",
           "id": 6,
           "type": "talk"
         },
         {
           "name": "セクシー",
           "id": 4,
           "type": "talk"
         },
         {
           "name": "ささやき",
           "id": 36,
           "type": "talk"
         },
         {
           "name": "ヒソヒソ",
           "id": 37,
           "type": "talk"
         }
       ],
       "version": "0.15.9",
       "supported_features": {
         "permitted_synthesis_morphing": "SELF_ONLY"
       }
     },
     {
         "name": "ずんだもん",
         "speaker_uuid": "388f246b-8c41-4ac1-8e2d-5d79f3ff56d9",
         "styles": [
           {
             "name": "ノーマル",
             "id": 3,
             "type": "talk"
           },
           {
             "name": "あまあま",
             "id": 1,
             "type": "talk"
           },
           {
             "name": "ツンツン",
             "id": 7,
             "type": "talk"
           },
           {
             "name": "セクシー",
             "id": 5,
             "type": "talk"
           },
           {
             "name": "ささやき",
             "id": 22,
             "type": "talk"
           },
           {
             "name": "ヒソヒソ",
             "id": 38,
             "type": "talk"
           },
           {
             "name": "ヘロヘロ",
             "id": 75,
             "type": "talk"
           },
           {
             "name": "なみだめ",
             "id": 76,
             "type": "talk"
           }
         ],
         "version": "0.15.9",
         "supported_features": {
           "permitted_synthesis_morphing": "SELF_ONLY"
         }
       },
  1. トップ
  2. tech
  3. QNAP を VOICEVOX 音声合成サーバにする