前回は乱数の評価基準として遷移回数だけで乱数の良しあしを評価できるのではないかという考察で終わりました。
その後Geminiと議論したところ、やはり1の出現割合は重要という結論になりました。
ハミングウェイト(1の出現割合)も使おう
例えば遷移回数(C)が期待値から大きくずれていない10回だとして、以下のような01列が書けます
乱数6:01 01 01 01 01 00 00 00 00 00 00 00
この場合、ハミングウエイトHは6となり
$P(H = 5) \approx \mathbf{0.253%}$
約400回に1回しか発生しない明確な異常・お化け反応となります。
Cが大きくなればHは必然的に期待値に近づいてゆきますが、Cが通常の値だからと言って必ずしもHが通常の値に近づくわけではないのです。
Cの値によってHの取りうる値の範囲は以下のように決まってゆきます。
C=0: 000000... 0 < H < N-0
C=1: 011111... 1 < H < N-1
C=2: 010000... 1 < H < N-1
C=3: 010111... 2 < H < N-2
C=4: 010100... 2 < H < N-2
つまり
[C/2] < H < N-[C/2]
Cを横軸、Hと縦軸として下のような三角形の内側部分がC-Hの取れる範囲となります。

そして赤く塗った、Cが著しく低い部分やHが極端に高い・低い部分がお化け反応で、青く塗った、Cが著しく高い部分がよい反応、赤や青に隣接する黄色・水色の部分がやや悪い・良い反応と定義することができます。
ついに化けたんオマージュ完成へ!
そして、この判断基準を使って RP2040-Zeroという格安マイコンに化けたんプログラムを実装することにしました。
Geminiを使って仕様を作成して、コーディングまで行わせました。
「化けたん」の再発明を目指して4年目にしてようやく納得できるものができました。
ここではRP2040のハードウェア乱数発生機を使って1秒おきに乱数を発生させ、オンボードのNeoPixelを本家「化けたん」と同じ色に光らせていますが、測定頻度や乱数発生アルゴリズムなどは自由に変えることができます。
#include <Arduino.h>
#include "pico/rand.h"
#include "hardware/clocks.h" // RP2040 クロック制御用
#include <Adafruit_NeoPixel.h>
// --- ハードウェア設定 ---
// ご使用のボードに合わせてGPIOピン番号を変更してください。
// 例: Waveshare RP2040-Zero -> GP16 / Seeed XIAO RP2040 -> GP12
#define RGB_LED_PIN 16
#define NUM_PIXELS 1
Adafruit_NeoPixel pixel(NUM_PIXELS, RGB_LED_PIN, NEO_GRB + NEO_KHZ800);
typedef enum {
COLOR_RED,
COLOR_YELLOW,
COLOR_GREEN,
COLOR_AQUA,
COLOR_BLUE
} Color;
Color evaluate_24bit(uint32_t val24);
void set_led_color(Color color);
void setup() {
// 1. 省電力化: システムクロックを標準125MHzから48MHzへ引き下げ
// (USBシリアル通信を正常維持できる最小周波数が48MHzです)
set_sys_clock_khz(48000, true);
// 2. LEDの初期化と減光設定(消費電力削減のため輝度を15%程度に制限)
pixel.begin();
pixel.setBrightness(40); // 0〜255 (輝度を下げると大幅に省電力化できます)
pixel.clear();
pixel.show();
Serial.begin(115200);
delay(1000);
}
void loop() {
// 32ビット乱数を取得し、下位24ビットをマスク抽出
uint32_t raw = get_rand_32();
uint32_t val24 = raw & 0x00FFFFFF;
Color result = evaluate_24bit(val24);
// 判定結果に応じてLEDを発光
set_led_color(result);
if (result == COLOR_RED) {
Serial.print(" RED");
} else if (result == COLOR_YELLOW) {
Serial.print(" YELLOW");
} else if (result == COLOR_AQUA) {
Serial.print(" AQUA");
} else if (result == COLOR_BLUE) {
Serial.print(" BLUE");
} else if (result == COLOR_GREEN) {
Serial.print(" GREEN");
}
Serial.println("");
// 3. 省電力なディレイ処理 (pico_sdkのsleep機能へ内部移行)
delay(1000);
}
Color evaluate_24bit(uint32_t val24) {
uint8_t H = __builtin_popcount(val24);
uint32_t diff = (val24 ^ (val24 >> 1)) & 0x007FFFFF;
uint8_t C = __builtin_popcount(diff);
Serial.print("(H, C) = (");
Serial.print(H);
Serial.print(", ");
Serial.print(C);
Serial.print(")");
if (H <= 3 || H >= 21 || C <= 3) return COLOR_RED;
if ((H <= 6 || H >= 18) && C <= 6) return COLOR_RED;
if (C >= 20) return COLOR_BLUE;
if (C >= 17) return COLOR_AQUA;
if (C <= 6 || H <= 6 || H >= 18) return COLOR_YELLOW;
return COLOR_GREEN;
}
// LEDの色設定用関数
void set_led_color(Color color) {
switch (color) {
case COLOR_RED:
pixel.setPixelColor(0, pixel.Color(255, 0, 0));
break;
case COLOR_YELLOW:
pixel.setPixelColor(0, pixel.Color(255, 200, 0));
break;
case COLOR_GREEN:
pixel.setPixelColor(0, pixel.Color(0, 255, 0));
break;
case COLOR_AQUA:
pixel.setPixelColor(0, pixel.Color(0, 255, 255));
break;
case COLOR_BLUE:
pixel.setPixelColor(0, pixel.Color(0, 0, 255));
break;
}
pixel.show();
}
以下がGeminiに書かせた化けたんの仕様です
「化けたん」オマージュ・汎用組込み実装モデル仕様書
(乱数遷移評価・空間状態検知プログラム 共通仕様書)
1. 概要
本仕様書は、各種マイコン(MCU)の内蔵ハードウェアエントロピー源(TRNG、ROSC、ADCノイズ等)から得られる物理乱数を取得し、その空間的・時間的ゆらぎ(ハミングウェイト $H$ および 1次差分XOR遷移回数 $C$)をリアルタイムに評価・分類して表示するガジェット(「化けたん」オマージュシステム)の共通設計仕様を定める。
ハードウェア依存処理を抽象化(HAL構成)することで、RP2040、ESP32シリーズ、ATTinyシリーズ、CH32シリーズ等の多種多様なアーキテクチャへ移植可能な設計とする。
2. 開発背景と動作原理
2.1 開発背景 (「化けたん」オマージュ思想)
市販のお化け検知器「化けたん」は、物理乱数の局所的な偏りや空間の熱ノイズ・電磁ゆらぎ等の「環境の異常状態」を検知して表示する概念に基づいている。
本プログラムは、この概念を現代的な組込み計算論とビット演算アルゴリズムを用いて再構築し、空間の「場(フィールド)」の状態を以下の5つのカラーモードで視覚化することを目的とする。
2.2 評価原理 (2次元状態空間 $H \times C$)
1回のサンプリングにつき $N$ ビット(標準仕様では $N = 24$)の物理乱数データ $Val_N$ を評価対象とする。
-
空間的状態量:ハミングウェイト $H$
- $N$ ビット中の 1 の総数(ビットの密度の偏り)。
- 物理ノイズ源が特定の電圧や状態に偏っているか(空間的対称性の崩れ)を判定する。
-
時間的・隣接的状態量:1次差分XOR遷移回数 $C$
- 隣接ビット間($b_i$ と $b_{i+1}$)の反転($0 \to 1$ または $1 \to 0$)の総数。
- 信号の高周波・高次相関成分や、低周波・固着傾向(フリーズ状態)を判定する。
これらを 2次元マトリックス $(H, C)$ 上に展開し、統計的期待値からの離脱度合(異常度)に応じて色評価(赤・黄・緑・水色・青)にマッピングする。
3. システムアーキテクチャ (HAL設計)
本プログラムはハードウェア依存部とアルゴリズムロジック部を分離し、移植性を最大化する。
+-------------------------------------------------------+
| アプリケーションロジック (共通) |
| - evaluate_Nbit(Val_N) -> Color |
| - 2次元マトリックス判定演算 |
+-------------------------------------------------------+
|
(HAL Interface)
|
+-------------------------------------------------------+
| ハードウェア抽象化層 (HAL) |
| - hal_get_random32() : 32bit乱数取得 |
| - hal_set_indicator() : 状態出力 (RGB LED / 単色) |
| - hal_sleep_ms() : 省電力待機 |
+-------------------------------------------------------+
|
+-------------------------------------------------------+
| ターゲットハードウェア |
| - RP2040 / ESP32 / ATTiny / CH32 / etc. |
+-------------------------------------------------------+
4. 詳細アルゴリズムおよび数理仕様 ($N=24$ 標準仕様)
4.1 乱数抽出とマスク処理
任意の32ビット乱数 $Val_{32}$ から下位24ビットをマスク抽出する。
$$Val_{24} = Val_{32} \ \& \ \mathtt{0x00FFFFFF}$$
4.2 ハミングウェイト $H$ の算出
$Val_{24}$ 内のビット 1 の総数 $H$ を算出する。
$$H = \sum_{i=0}^{23} b_i \quad (b_i \in \{0, 1\})$$
- 値域: $0 \le H \le 24$
- 一様ランダム時の理論期待値: $E[H] = 12$
- 分散: $V[H] = 6$
- 標準偏差: $\sigma_H = \sqrt{6} \approx 2.449$
4.3 1次差分 XOR 23bit 遷移回数 $C$ の算出
隣接ビット間の変化の有無を評価するため、1ビット右シフトデータとの排他的論理和(XOR)を計算し、下位23ビットをポップカウントする。
$$Diff = (Val_{24} \oplus (Val_{24} \gg 1)) \ \& \ \mathtt{0x007FFFFF}$$
$$C = \sum_{i=0}^{22} (b_i \oplus b_{i+1})$$
- 値域: $0 \le C \le 23$
- 一様ランダム時の理論期待値: $E[C] = 11.5$
- 分散: $V[C] = 5.75$
- 標準偏差: $\sigma_C = \sqrt{5.75} \approx 2.398$
4.4 2次元マトリックス評価条件 (色判定規則)
$(H, C)$ のペアに対し、以下の優先順位に従い判定を行う。
|
| 判定順 | 色 (Color) | 判定条件 (論理式) | 状態の解釈(空間状態・検知意味) |
| 1 | 赤 (RED) | $(H \le 3 \text{ or } H \ge 21 \text{ or } C \le 3)$ $\text{or } ((H \le 6 \text{ or } H \ge 18) \text{ and } C \le 6)$ | 警戒・異常強: 空間的極偏向、または重度のフリーズ・低周波固着状態 |
| 2 | 青 (BLUE) | $C \ge 20$ | 高次コヒーレンス: 秩序ある高周波交代波・強い周波数同期傾向 |
| 3 | 水色 (AQUA) | $C \ge 17$ | 調和・高周波傾向: 軽度の高頻度反転・平滑化ゆらぎ |
| 4 | 黄 (YELLOW) | $C \le 6 \text{ or } H \le 6 \text{ or } H \ge 18$ | 滞留・軽度偏向: 軽度の低周波化、またはビット密度の軽度非対称 |
| 5 | 緑 (GREEN) | 上記以外のすべて | 通常(デフォルト): 健全なホワイトノイズ・平衡空間 |
5. 判定スレッショルドの算出根拠と感度調整ガイド
5.1 二項分布に基づく統計的離脱度 ($\sigma$ 基準)
物理乱数源が理想的な独立同分布(i.i.d.)に従う場合、$H$ および $C$ は二項分布 $B(n, p)$ (ただし $p = 0.5$)に従う。
- $H \sim B(N, 0.5)$
- $C \sim B(N-1, 0.5)$
確率変数が期待値 $\mu$ から何 $\sigma$(標準偏差)離れているかを示す標準化変量 $z$ を計算することで、異常度の統計的根拠を決定する。
$$z_H = \frac{\vert{}H - \mu_H\vert{}}{\sigma_H}, \quad z_C = \frac{\vert{}C - \mu_C\vert{}}{\sigma_C}$$
5.2 $N=24$ における各色のしきい値算出根拠
| 色 | 定義概念 | σ 離脱度基準 | 計算根拠 (N=24) | 発生確率 (理論値) |
| 赤 (RED) | 極端な異常 ($\ge 3.5\sigma$) | $z_H \ge 3.67$ または $z_C \ge 3.54$ | $H \le 3$ ($12 - 3.67\sigma$) $H \ge 21$ ($12 + 3.67\sigma$) $C \le 3$ ($11.5 - 3.54\sigma$) | 約 $0.03\%$ 未満 (超希少イベント) |
| 青 (BLUE) | 強い秩序・同期 ($\ge 3.5\sigma$) | $z_C \ge 3.54$ (正方向) | $C \ge 20$ ($11.5 + 3.54\sigma$) | 約 $0.02\%$ |
| 水色 (AQUA) | 軽度の高周波調和 ($\ge 2.2\sigma$) | $z_C \ge 2.29$ (正方向) | $C \ge 17$ ($11.5 + 2.29\sigma$) | 約 $1.7\%$ |
| 黄 (YELLOW) | 軽度の偏り・滞留 ($\ge 2.2\sigma$) | $z_H \ge 2.45$ または $z_C \ge 2.29$ (負方向) | $H \le 6, H \ge 18$ $C \le 6$ | 約 $3.0\%$ |
| 緑 (GREEN) | 正常領域 ($< 2.2\sigma$) | $z_H < 2.45$ かつ $z_C < 2.29$ | 上記以外 | 約 $95.0\%$ |
5.3 感度調整パラメータ (チューニングガイド)
ガジェットの用途や設置環境のノイズ特性に応じて、しきい値の $\sigma$ 幅を変更することで感度を調整する。
-
高感度モード (イベント発生頻度を高めたい場合)
- 赤判定を $z \ge 3.0\sigma$ に変更: $H \le 4 \text{ or } H \ge 20 \text{ or } C \le 4$
- 青判定を $z \ge 3.0\sigma$ に変更: $C \ge 19$
- 特長: わずかな環境変化でも赤や青が点灯しやすくなる。
-
低感度・厳格モード (誤検知を極力防ぎたい場合)
- 赤判定を $z \ge 4.0\sigma$ に変更: $H \le 2 \text{ or } H \ge 22 \text{ or } C \le 2$
- 青判定を $z \ge 4.0\sigma$ に変更: $C \ge 21$
- 特長: 赤・青の点灯が非常に稀(数時間に1回程度)になる。
6. 任意ビット長 $N$ への汎用化仕様 ($N$-bit 一般化)
メモリ制限のある8ビットマイコン(ATTiny等)や、逆に32ビット処理を最適化したい場合など、$N \neq 24$ のビット長を採用する際の一般化手法を以下に定める。
6.1 一般化数理モデル
サンプルビット長を $N$ (ただし $N \ge 8$)と定義するとき、各パラメータは以下のように一般化される。
- マスク値:
- $$Mask_H = 2^N - 1$$
- $$Mask_C = 2^{N-1} - 1$$
- ハミングウェイト $H$ の統計量:
- $$\mu_H = \frac{N}{2}$$
- $$\sigma_H = \sqrt{\frac{N}{4}} = \frac{\sqrt{N}}{2}$$
- 1次差分 XOR 遷移回数 $C$ の統計量:
- $$\mu_C = \frac{N-1}{2}$$
- $$\sigma_C = \sqrt{\frac{N-1}{4}} = \frac{\sqrt{N-1}}{2}$$
6.2 任意ビット長における期待値・標準偏差・判定境界一覧
各ビット長 $N$ における各色スレッショルドの切り出し値(整数近似)の一覧を示す。
| ビット長 N | μH (σH) | μC (σC) | 赤 (RED) 境界(≈3.5σ) | 青 (BLUE) 境界(≈3.5σ) | 水色 (AQUA) 境界(≈2.3σ) | 黄 (YELLOW) 境界(≈2.3σ) |
| 8 bit | $4.0$ ($1.00$) | $3.5$ ($0.935$) | $H \le 0, H \ge 8, C \le 0$ | $C \ge 7$ | $C \ge 6$ | $H \le 1, H \ge 7, C \le 1$ |
| 16 bit | $8.0$ ($2.00$) | $7.5$ ($1.936$) | $H \le 1, H \ge 15, C \le 1$ | $C \ge 14$ | $C \ge 12$ | $H \le 3, H \ge 13, C \le 3$ |
| 24 bit (標準) | $12.0$ ($2.45$) | $11.5$ ($2.40$) | $H \le 3, H \ge 21, C \le 3$ | $C \ge 20$ | $C \ge 17$ | $H \le 6, H \ge 18, C \le 6$ |
| 32 bit | $16.0$ ($2.83$) | $15.5$ ($2.78$) | $H \le 6, H \ge 26, C \le 5$ | $C \ge 25$ | $C \ge 22$ | $H \le 9, H \ge 23, C \le 9$ |
6.3 スケーリング算出式(マクロ定義用)
アルゴリズムをC言語マクロ等で汎用化する場合、以下の計算式によりしきい値を自動算出する。
#define N_BITS 24
#define MASK_H ((1UL << N_BITS) - 1)
#define MASK_C ((1UL << (N_BITS - 1)) - 1)
// 統計的しきい値の自動計算(整数切り捨て/切り上げ)
#define THRESH_RED_H_LOW (N_BITS / 2 - (int)(1.75 * sqrt(N_BITS)))
#define THRESH_RED_H_HIGH (N_BITS / 2 + (int)(1.75 * sqrt(N_BITS)))
#define THRESH_RED_C_LOW ((N_BITS - 1) / 2 - (int)(1.77 * sqrt(N_BITS - 1)))
#define THRESH_BLUE_C ((N_BITS - 1) / 2 + (int)(1.77 * sqrt(N_BITS - 1)))
6.4 リソース制限マイコンでの実装考慮事項
-
8ビットマイコン (ATTiny / CH32V003等)
- $N = 8$ または $N = 16$ を採用することで、演算を8bit/16bit整数に収め、レジスタの圧迫やコードサイズを削減する。
- __builtin_popcount がハードウェア命令に存在しない場合、8ビット用ルックアップテーブル(256バイト)またはビットシフトループを使用する。
-
32ビットマイコン (RP2040 / ESP32等)
- $N = 24$ または $N = 32$ を採用する。32ビットレジスタを活用するためオーバーヘッドは発生しない。
7. マイコン別 HAL 移植ガイドライン
| マイコンシリーズ | 乱数取得 (hal_get_random32) | 状態出力 (hal_set_indicator) | 省電力待機 (hal_sleep_ms) |
| RP2040 | Pico SDK get_rand_32() (ROSCベース) | WS2812 (PIO / GPIO) または単色LED | Clocks低速化 + sleep_ms() |
| ESP32 シリーズ | ESP-IDF esp_random() (TRNG) | WS2812 (RMTペリフェラル) / RGB LED | esp_light_sleep_start() |
| ATTiny シリーズ | ADCフローティングノイズまたは Watchdog Jitter | GPIO PWM (単色 / RGB LED) | set_sleep_mode(SLEEP_MODE_PWR_DOWN) |
| CH32V シリーズ | ADCノイズ / 内部クロックドリフト | GPIO出力 | PWR_EnterSTOPMode() |