サークルで活動するには参加が必要です。
「サークルに参加する」ボタンをクリックしてください。
※参加を制限しているサークルもあります。
-
from: 生成門さん
2026/09/08 18:10:05
icon
AIとの対話(AIとの比較による違い:ピコマシンのスペック)
AIがAIを査読するというのは凄い事ですね。これもまた世界で初めての実験ですね。何しろ数千円で、しかも秋葉原で部品が賄えるのだからとんでもです。ウクライナのドーロン開発に似ています。PIOアセンブラの骨組みからお願いします。どうなりますかね。まだ現れていない未来のエンジニアもびっくりするでしょうね。まるで植物のタイムマシンのような実験です。つまり未来完了型の実験です。
いい進め方です。
ここからは実装、まず PIO アセンブラの骨組み です。数千円・秋葉原部品・センサーなし、という制約の中で「刃の立つパルス」を先に出すのは、まさにゲリラドローン的です。未来のエンジニアが驚くかどうかは分かりませんが、今の部品で、今の手に届く未来を先に作る実験、という意味では、あなたの言う未来完了型に近いです。以下は、Raspberry Pi Pico の PIO State Machine で、GPIO15 出力
非対称パルス
黄金比デューティ(ON ≈ 0.618T / OFF ≈ 0.382T)
CPU 側から周期を流し込める
ようにした 最小骨組み です。設計方針PIO に全部やらせないで、役割を分けます。役割
担当
急峻な ON/OFF の刃
PIO
黄金比デューティ
PIO の delay / カウント
1/f ゆらぎや周波数掃引
CPU(MicroPython)
モード1/2
CPU が周期値を切り替えて PIO に渡す
これで「メインCPUの直線時間に依存しない刃」と、「後から変えられるゆらぎ」を両立します。PIO 骨組み(非対称・黄金比デューティ)pio
; ir_pulse.pio
; GPIO15 に非対称赤外線パルスを出す最小骨組み
; ON ≈ 0.618 T
; OFF ≈ 0.382 T
;
; 使い方:
; - X レジスタに「基本カウント」を入れてから起動
; - ON 側は X、OFF 側は X * 0.618 相当を Y で回す
; - 立ち上がりは即時 set で立て、立ち下がり側にだけ余白を持たせる
.program ir_asym_pulse
.side_set 1 opt
public start:
; 事前に CPU から X へ「ONカウント」を入れておく
; Y へ「OFFカウント」を入れておく
; ここでは pull / out で受け取る形にする
load_params:
pull block ; osr <- CPU から 32bit
out x, 16 ; x = ON カウント
out y, 16 ; y = OFF カウント
on_phase:
set pins, 1 ; 即座に ON(立ち上がり優先)
on_loop:
jmp x_dec, on_loop ; ON を維持
off_phase:
set pins, 0 ; OFF
; 立ち下がり側にだけ小さな余白を持たせるなら、ここに nop を足す
; nop [1]
off_loop:
jmp y_dec, off_loop ; OFF を維持
jmp load_params ; 次周期の値をまた CPU から受け取る
これは「毎周期 CPU から ON/OFF カウントを受け取る」版です。
最初の波形確認には少し丁寧すぎるくらいですが、1/f ゆらぎを後で載せやすい骨組みです。もっと刃を優先した固定デューティ版まずオシロで立ち上がりを見たいだけの段階なら、こちらがわかりやすいです。pio
; ir_pulse_fixed.pio
; 固定黄金比デューティの最小版
; X = 周期基準カウント
;
; ON = 約 0.618
; OFF = 約 0.382
;
; 例:
; 基準を 1000 とすると
; ON = 618
; OFF = 382
.program ir_fixed_golden
public start:
pull block
out x, 32 ; x = base count
loop:
; ---- ON 0.618 ----
set pins, 1
mov y, x
on_hold:
; 近似: base のまま回し、OFF側で短くする
jmp y_dec, on_hold
; ---- OFF 0.382 ----
set pins, 0
mov y, x
off_hold:
; OFF を短くするため、同じ base を使うのではなく
; CPU側で off_count を別に渡す方が正確
jmp y_dec, off_hold
jmp loop
固定版の弱点は、黄金比を正確に分けるなら ON 用と OFF 用の2値が欲しいことです。
なので、実装の本番は最初の「ON/OFF 二値を pull する版」に進むのがよいです。MicroPython 側の骨組みpython
import rp2
from machine import Pin
import time
# 仮のPIOプログラム登録用デコレータ
# 実際は .pio を asm_pio で書くか、別途ロードする
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def ir_asym_pulse():
pull(block)
out(x, 16)
out(y, 16)
set(pins, 1) # ON 即時
label("on_loop")
jmp(x_dec, "on_loop")
set(pins, 0) # OFF
# nop() .side(0) [1] # 必要なら立ち下がり余白
label("off_loop")
jmp(y_dec, "off_loop")
jmp("ir_asym_pulse") # 先頭へ
# 注: 実際のラベル先頭位置は asm_pio の書き方に合わせて調整
# GPIO15, SM0
sm = rp2.StateMachine(
0,
ir_asym_pulse,
freq=137_000_000, # まず125_000_000で確認してもよい
set_base=Pin(15)
)
def make_counts(period_counts):
"""
period_counts: 1周期の総カウント
ON = 0.618
OFF = 0.382
"""
on_c = int(period_counts * 0.618)
off_c = max(1, period_counts - on_c)
if on_c < 1:
on_c = 1
# 16bitずつ詰める
return (on_c & 0xFFFF) | ((off_c & 0xFFFF) << 16)
# 例: 適当な低周波から開始
# freq が 137MHz のとき、1カウントの意味は PIO分周に依存するため
# 実測で合わせる
period = 20000
sm.put(make_counts(period))
sm.active(1)
# 後で 1/f ゆらぎを載せるなら、この period を更新して sm.put() する
実装上の重要ポイントまず 125MHz で波形確認
その後に 137MHz へ上げる。最初からオーバークロック前提にしない。
PIO の set pins, 1 が刃
立ち上がり優先なら、ON は即 set、待ちはその後。
黄金比は「時間の比」で入れる
ON:OFF = 0.618:0.382
ここはあなたの仕様の中核なので、最初からマジックナンバーで持ってよいです。
1/f は後段
いまは骨組みなので、CPU が period を時々更新する棚だけ作る。
カオス式は次の段階で十分。
実測が最終審判
カウント計算より、オシロで 立ち上がり時間
ON幅
OFF幅
を見る。Pico の出力単体と、MOSFET 後段では全然違います。
次の一手この骨組みの次は、自然にどちらかです。asm_pio で動く完全な MicroPython 1ファイル版に整形
モード1(低周波)/ モード2(高周波)の周期値表を決める
TC4427 + MOSFET 後の波形確認手順に進む
おすすめは、まず 1. 動く1ファイル版 です。
Pico単体で GPIO15 にパルスが出れば、未来の装置の「芯」は立ったことになります。次は、その 完全な1ファイル版 に整形して出しますか。
1/f ゆらぎの実装手順
TC4427 ドライバ回路
1ファイル版コードを提供
整形をお願いします。
整形版です。
Raspberry Pi Pico 上で、まず GPIO15 に非対称・黄金比デューティのパルスを出す ための、1ファイルの骨組みです。実装ファイル:ir_pico_pulse.pypython
"""
Raspberry Pi Pico
PIO非対称赤外線パルス骨組み
- 出力ピン: GPIO15
- State Machine: SM0
- デューティ: ON=0.618 / OFF=0.382
- 役割分担:
PIO = 急峻なON/OFFの刃
CPU = 周期の更新(後で1/fゆらぎを載せる)
注意:
- まずはPico単体でGPIO15の波形確認用
- 12V駆動・LEDパネル接続・生体照射は、後段回路確認後に行うこと
- PC接続しながらの生体照射は禁止
"""
import rp2
from machine import Pin
import time
# =========================================================
# PIOプログラム
# =========================================================
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def ir_asym_pulse():
# CPUから 32bit を受け取る
# 下位16bit = ONカウント
# 上位16bit = OFFカウント
pull(block)
out(x, 16) # x = ON
out(y, 16) # y = OFF
# 立ち上がり優先: 待たずに即ON
set(pins, 1)
label("on_loop")
jmp(x_dec, "on_loop") # ON維持
# 立ち下がり
set(pins, 0)
# 必要なら、立ち下がり側だけ短い余白を入れる
# nop() [1]
label("off_loop")
jmp(y_dec, "off_loop") # OFF維持
# 次の周期パラメータを受け取る
jmp("ir_asym_pulse")
# =========================================================
# ユーティリティ
# =========================================================
def make_counts(period_counts):
"""
1周期の総カウントから
ON=0.618 / OFF=0.382 の 32bit 値を作る
"""
period_counts = int(period_counts)
if period_counts < 2:
period_counts = 2
on_c = int(period_counts * 0.618)
off_c = period_counts - on_c
if on_c < 1:
on_c = 1
if off_c < 1:
off_c = 1
# 下位16bit=ON, 上位16bit=OFF
return (on_c & 0xFFFF) | ((off_c & 0xFFFF) << 16)
def period_from_hz(target_hz, sm_freq):
"""
目標周波数から、おおよその周期カウントを見積もる。
実際の周波数はオシロで確認して合わせること。
"""
if target_hz <= 0:
target_hz = 1
# 経験的な開始点。PIOの1ループオーバーヘッド分は実測補正が必要
return max(2, int(sm_freq / target_hz))
# =========================================================
# StateMachine 起動
# =========================================================
PIN_OUT = 15
SM_ID = 0
# まず安定優先なら 125_000_000
# 仕様の137MHzを試すなら 137_000_000
SM_FREQ = 125_000_000
sm = rp2.StateMachine(
SM_ID,
ir_asym_pulse,
freq=SM_FREQ,
set_base=Pin(PIN_OUT)
)
# ---------------------------------------------------------
# モード仮設定
# モード1: 低周波(お腹用のイメージ)
# モード2: 高周波(背中用のイメージ)
# 値は初期値。必ず実測で調整する
# ---------------------------------------------------------
MODE1_HZ = 20 # 低周波側の開始値
MODE2_HZ = 2000 # 高周波側の開始値
current_mode = 1
current_hz = MODE1_HZ
period_counts = period_from_hz(current_hz, SM_FREQ)
# 最初の周期を投入して起動
sm.put(make_counts(period_counts))
sm.active(1)
print("PIO pulse started")
print("pin = GPIO{}".format(PIN_OUT))
print("sm_freq = {}".format(SM_FREQ))
print("mode = {}".format(current_mode))
print("target_hz = {}".format(current_hz))
print("period_counts = {}".format(period_counts))
# =========================================================
# メインループ
# 今は固定周波数。
# 後でここに1/fゆらぎの漸化式を入れる。
# =========================================================
def set_mode(mode):
global current_mode, current_hz, period_counts
current_mode = mode
if mode == 1:
current_hz = MODE1_HZ
else:
current_hz = MODE2_HZ
period_counts = period_from_hz(current_hz, SM_FREQ)
sm.put(make_counts(period_counts))
print("mode={}, target_hz={}, period_counts={}".format(
current_mode, current_hz, period_counts
))
# デモ:
# 数秒ごとにモード1/2を切り替える。
# 実機ではトグルスイッチ入力に置き換える。
while True:
set_mode(1)
time.sleep(5)
set_mode(2)
time.sleep(5)
使い方Pico に MicroPython を入れる
このコードを ir_pico_pulse.py として保存
実行
GPIO15 をオシロで見る
見るポイントは次の3つです。立ち上がりが立っているか
ON:OFF がおおよそ 0.618 : 0.382 か
モード1/2で周期が変わるか
実装上の注意最初は 125MHz で確認してください。安定したら 137MHz に上げます。
いまは Pico単体の論理パルス確認用 です。
TC4427 / MOSFET / LED パネルの前に、まずここを通します。
period_from_hz() は概算です。正確な周波数は実測で合わせます。
1/fゆらぎは、まだ入れていません。
次の段階で while True: の中で period_counts を更新すれば載せられます。
次の段階この整形版の次は、自然にこの順です。オシロ確認用に、モード切替デモを止めて固定出力にする
1/fゆらぎ更新ルーチンを追加する
TC4427 + MOSFET 後段の駆動確認に進む
次は「固定出力の計測用バージョン」と「1/fゆらぎ入りバージョン」、どちらを整形しますか。
1/fゆらぎの実装コード
TC4427ドライバ回路
揺らぎバ―ジョンをお願いします。
ゆらぎ版です。
前の整形版に、CPU側の 1/fゆらぎ(間欠性カオス風) を載せた1ファイル版です。実装ファイル:ir_pico_pulse_flicker.pypython
"""
Raspberry Pi Pico
PIO非対称赤外線パルス + 1/fゆらぎ版
- 出力ピン: GPIO15
- State Machine: SM0
- デューティ: ON=0.618 / OFF=0.382
- PIO: 急峻なON/OFFの刃
- CPU: 1/f風の周期ゆらぎをPIOへ供給
注意:
- まずはPico単体でGPIO15の波形確認用
- 12V駆動・LEDパネル接続・生体照射は後段回路確認後
- PC接続しながらの生体照射は禁止
"""
import rp2
from machine import Pin
import time
# =========================================================
# PIOプログラム
# =========================================================
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def ir_asym_pulse():
# 下位16bit = ONカウント
# 上位16bit = OFFカウント
pull(block)
out(x, 16)
out(y, 16)
# 立ち上がり優先
set(pins, 1)
label("on_loop")
jmp(x_dec, "on_loop")
# 立ち下がり
set(pins, 0)
# nop() [1] # 必要ならOFF側の余白
label("off_loop")
jmp(y_dec, "off_loop")
jmp("ir_asym_pulse")
# =========================================================
# 基本ユーティリティ
# =========================================================
def make_counts(period_counts):
"""
総カウント -> 黄金比デューティの32bit値
ON=0.618 / OFF=0.382
"""
period_counts = int(period_counts)
if period_counts < 2:
period_counts = 2
on_c = int(period_counts * 0.618)
off_c = period_counts - on_c
if on_c < 1:
on_c = 1
if off_c < 1:
off_c = 1
return (on_c & 0xFFFF) | ((off_c & 0xFFFF) << 16)
def period_from_hz(target_hz, sm_freq):
"""
目標周波数から概算カウントを作る。
最終値はオシロ実測で合わせる。
"""
if target_hz <= 0:
target_hz = 1.0
return max(2, int(sm_freq / float(target_hz)))
# =========================================================
# 1/f風ゆらぎ生成
# =========================================================
class Flicker1F:
"""
軽い1/f風ゆらぎ生成器。
厳密な数学的1/fというより、
「慣れを防ぐための間欠的なゆらぎ」を作る実装。
- pink: 低域寄り成分
- chaos: 間欠的な跳び
"""
def __init__(self, seed=1):
self.state = int(seed) & 0x7FFFFFFF
if self.state == 0:
self.state = 1
# ローパス状態
self.pink = 0.0
# カオス状態 (0..1)
self.chaos = 0.37
def _rand01(self):
# 単純なLCG
self.state = (1103515245 * self.state + 12345) & 0x7FFFFFFF
return self.state / 2147483647.0
def next_factor(self):
"""
周期に掛ける係数を返す。
おおよそ 0.6 〜 1.6 程度に収める。
"""
r = self._rand01()
# 低域寄り
self.pink = (0.92 * self.pink) + (0.08 * (r - 0.5))
# logistic map 風の間欠性
self.chaos = 3.7 * self.chaos * (1.0 - self.chaos)
# 合成
# pinkは緩い波、chaosは時々の揺れ
factor = 1.0 + (1.2 * self.pink) + (0.25 * (self.chaos - 0.5))
# 暴走防止
if factor < 0.60:
factor = 0.60
if factor > 1.60:
factor = 1.60
return factor
# =========================================================
# StateMachine 設定
# =========================================================
PIN_OUT = 15
SM_ID = 0
# まずは125MHzで安定確認。その後137MHzへ
SM_FREQ = 125_000_000
sm = rp2.StateMachine(
SM_ID,
ir_asym_pulse,
freq=SM_FREQ,
set_base=Pin(PIN_OUT)
)
# ---------------------------------------------------------
# モード
# 値は初期値。実測で調整する
# ---------------------------------------------------------
MODE1_HZ = 20 # 低周波(お腹用イメージ)
MODE2_HZ = 2000 # 高周波(背中用イメージ)
current_mode = 1
base_hz = float(MODE1_HZ)
# ゆらぎ生成器
flicker = Flicker1F(seed=7)
# 更新間隔 [秒]
# 短いほど頻繁に揺れる
UPDATE_INTERVAL_SEC = 0.05
# モード切替デモ間隔
MODE_SWITCH_SEC = 8.0
def set_mode(mode):
global current_mode, base_hz
current_mode = mode
if mode == 1:
base_hz = float(MODE1_HZ)
else:
base_hz = float(MODE2_HZ)
print("mode={}, base_hz={}".format(current_mode, base_hz))
def push_period(period_counts):
sm.put(make_counts(period_counts))
# 起動
set_mode(1)
init_period = period_from_hz(base_hz, SM_FREQ)
push_period(init_period)
sm.active(1)
print("PIO flicker pulse started")
print("pin=GPIO{}".format(PIN_OUT))
print("sm_freq={}".format(SM_FREQ))
print("update_interval={}s".format(UPDATE_INTERVAL_SEC))
# =========================================================
# メインループ
# =========================================================
last_update = time.ticks_ms()
last_mode_switch = time.ticks_ms()
while True:
now = time.ticks_ms()
# 一定間隔で1/f風に周期更新
if time.ticks_diff(now, last_update) >= int(UPDATE_INTERVAL_SEC * 1000):
factor = flicker.next_factor()
target_hz = base_hz * factor
# モードごとの保護レンジ
if current_mode == 1:
# 低周波モード: ゆっくり揺れる
if target_hz < 5.0:
target_hz = 5.0
if target_hz > 80.0:
target_hz = 80.0
else:
# 高周波モード
if target_hz < 500.0:
target_hz = 500.0
if target_hz > 8000.0:
target_hz = 8000.0
period_counts = period_from_hz(target_hz, SM_FREQ)
push_period(period_counts)
# デバッグ表示が邪魔ならコメントアウト
# print("hz={:.2f}, period={}".format(target_hz, period_counts))
last_update = now
# デモ: モード1/2を交互に切替
# 実機ではトグルスイッチ入力に置き換える
if time.ticks_diff(now, last_mode_switch) >= int(MODE_SWITCH_SEC * 1000):
if current_mode == 1:
set_mode(2)
else:
set_mode(1)
last_mode_switch = now
# 軽い待ち(busy loop抑止)
time.sleep_ms(1)
この版でやっていることPIO
いつも通り、ON即時・黄金比デューティの刃を生成
CPU
50msごとに周期を更新し、1/f風のゆらぎを与える
ゆらぎの中身ローパス的なゆっくり成分
logistic map風の間欠的な跳び
係数はおおよそ 0.6〜1.6 に制限
モードモード1: 低周波帯で揺らぐ
モード2: 高周波帯で揺らぐ
まず確認することGPIO15にパルスが出る
ON:OFFがおおよそ 0.618:0.382
時間が経つと周期がゆっくり変わる
8秒ごとに低周波/高周波モードが切り替わる
オシロがあるなら、短い時間軸で刃を見る
長い時間軸でゆらぎを見る
の両方を見るとわかりやすいです。調整ポイントゆらぎが強すぎる → factor の係数 1.2 や 0.25 を小さく
ゆらぎが速い → UPDATE_INTERVAL_SEC = 0.10 などへ延長
まず固定に近い方がよい → 係数を狭くして 0.9〜1.1 に制限
137MHzを試す → SM_FREQ = 137_000_000
次の自然なステップデモの自動モード切替をやめて、固定モード+ゆらぎのみにする
トグルスイッチ入力でモード1/2を切り替える
TC4427 + MOSFET 後段へ進む
次はどれを整形しますか。
必要なら「計測しやすい低ゆらぎ版」もすぐ出せます。
Explain logistic map chaos
Pink noise generation methodsサークルで活動するには参加が必要です。
「サークルに参加する」ボタンをクリックしてください。
※参加を制限しているサークルもあります。
コメント: 全0件


