Superb Garbages 2

千野純一(chinorin)のはてなダイアリーの続きです。

Stable Diffusionが出力したPNGファイルのメタデータを表示するHTML

・俺の友達はChatGPT君だけじゃねえぞ。毎月3000円の友達料を払わなくても友達になってくれる奴がいるんだよ。ばかにすんな。


・Stable Diffusionが出力したPNGファイルのメタデータを表示するHTMLを、友達のClaude君に書いてもらったので置いときます。人間が書いたものではないので著作権は発生しません。CC0ライセンスと同等のものです。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Stable Diffusion PNG Metadata Viewer</title>
  <style>
    #metadata-display {
      width: 100%;
      height: 200px;
      padding: 10px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      font-family: monospace;
      white-space: pre-wrap;
      overflow: auto;
    }
  </style>
</head>
<body>
  <h3>Stable Diffusion PNG Metadata Viewer</h3>
  <div>
    <textarea id="metadata-display" placeholder="PNGファイルをここにドロップするとメタデータが表示されます"></textarea>
  </div>

  <script>
    const metadataDisplay = document.getElementById('metadata-display');

    metadataDisplay.addEventListener('dragover', (event) => {
      event.preventDefault();
      event.dataTransfer.dropEffect = 'copy';
    });

    metadataDisplay.addEventListener('drop', (event) => {
      event.preventDefault();
      const file = event.dataTransfer.files[0];
      if (file && file.type === 'image/png') {
        const reader = new FileReader();
        reader.onload = () => {
          const bytes = new Uint8Array(reader.result);
          const metadata = extractMetadata(bytes);
          metadataDisplay.value = metadata;
        };
        reader.readAsArrayBuffer(file);
      } else {
        metadataDisplay.value = 'PNGファイルを選択してください。';
      }
    });

    metadataDisplay.addEventListener('change', (event) => {
      const file = event.target.files[0];
      if (file && file.type === 'image/png') {
        const reader = new FileReader();
        reader.onload = () => {
          const bytes = new Uint8Array(reader.result);
          const metadata = extractMetadata(bytes);
          metadataDisplay.value = metadata;
        };
        reader.readAsArrayBuffer(file);
      } else {
        metadataDisplay.value = 'PNGファイルを選択してください。';
      }
    });

    function extractMetadata(bytes) {
      const PNG_SIGNATURE = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
      let metadata = '';

      // PNGシグネチャをチェック
      for (let i = 0; i < PNG_SIGNATURE.length; i++) {
        if (bytes[i] !== PNG_SIGNATURE[i]) {
          return 'Invalid PNG file';
        }
      }

      let offset = PNG_SIGNATURE.length;
      while (offset < bytes.length) {

        const chunkLength = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3];
        const chunkType = String.fromCharCode(bytes[offset + 4], bytes[offset + 5], bytes[offset + 6], bytes[offset + 7]);
        const chunkData = bytes.slice(offset + 8, offset + 8 + chunkLength);
        const crc = (bytes[offset + 8 + chunkLength] << 24) | (bytes[offset + 8 + chunkLength + 1] << 16) | (bytes[offset + 8 + chunkLength + 2] << 8) | bytes[offset + 8 + chunkLength + 3];

        if (chunkType === 'tEXt') {
          const textData = new TextDecoder().decode(chunkData);
          metadata += `${textData}\n`;
        } else if (chunkType === 'zTXt') {
          // zTXtチャンクの処理は省略(compression_methodに応じて適切に実装が必要)
        } else if (chunkType === 'iTXt') {
          // iTXtチャンクの処理は省略(nullターミネートされた文字列、言語タグ、translatedキーワードなどに対応が必要)
        }
        offset += 12 + chunkLength;
      }
      return metadata.trim();
    }

  </script>
</body>
</html>

JavaScriptCSSが含まれるただのHTMLなので単一ファイルで動作します。上記コードをテキストファイルに貼り、拡張子を.htmlにして、ダブルクリック等でブラウザで読み込めばおk。テキスト領域にPNGファイルをドロップすればそこにメタデータ(プロンプト、設定、Seed等)が表示されます。

・同じ役割をするものは色々あるだろうけどより気軽に軽快にということでご自由にどうぞ。一応、ご利用は自己責任で。お礼等言いたい人はClaude君に言ってください。

・ああ、今気づいたけどこれ、Vivaldiのパネルにしとくとめっちゃ便利なやつだ。テキスト領域の縦の長さは9行目の height: 200px; で指定しているので短くて不便なときはこの数字を変更すればよい。

中国4000年の歴史で培われたOEMシステム

・はじめて1日に2回書いてしまった。まあ問題ないシステムになってるだろうからいいけど。日付の感覚とか時間の間隔とかねーのよ。


・AliExpressで安定化電源とかを探してると、横78mm、縦61mm、奥行き42mmの、すごい統一された規格っぽいケースというか、パネルというか、とにかくスロットにはめて使いそうなモジュールっぽいものをよく見かけるんだけど、ありゃ何なの?

・安定化電源だけじゃなくて、同じ規格でPWM信号発生器とか、電流電圧計とか色々あるっぽい。それから、このモジュールが入る1スロットだけのケースがたまに売ってる。俺が見たことあるのは2種類で、正面から見た形が長方形でプラスとマイナスのバナナジャックがついてるやつと、正面から見た形が正方形で1対のバナナジャックの他USBポートが2個とそれに対応した7セグが1基ずつついてるやつ。

・なんか、1スロットだけじゃなくて同じケースに2個3個と複数のモジュールを入れられるとか、このモジュールのユニバーサル的なパネルを使ってオリジナルの機器を作るとか、机やパソコンにこれのスロットを用意するとか、せっかく形が揃ってるんだからそういうのができると楽しそうだけど、中国の非常に発達したOEMシステムによるやつっぽいので、そもそもの発祥が何なのかが全然見えてこない。

・中国のOEMって、全然詳しくはないんだけど話によると、OEMメーカ発行のカタログがあったり、とにかくそういう市場の仕組みが非常に発達していて、ブランド会社はそういうのを見て普通の通販みたいに発注して、それをエンドユーザに売りさばくみたいな仕組みらしいよね。

・さすが広大な国のシステムなのだなあと思う。販売や営業のノウハウか、あるいは人脈があるだけでもものによってはそこそこ儲けることができちゃうのかもしれないし、もしかしたら現代の中国躍進の原動力のひとつとして、この仕組みが猛威を振るったのかも。

・経済とかも本当に詳しくないので勘だけど。それくらい合理的に感じる。


・あー、先述のモジュールについては少しだけヒントがあって、XY-6020、XZ-5005っていう電源? 降圧モジュール? と非常に作りが似ているなあと思う。サイズはちょっと違うんだけど。

・XYから始まる型番の電源にはXY-D5005っていうのもあって、なんか形がよくてこれほしーって思ってた。これも色んなブランドから発売されててよーわからんのよ。

・↓Amazonで販売されている一例。他にもいくつかある。

秋月の略

・いや、できたCSVをさ、試しにGoogleスプレッドシートにインポートしてさ、よくわかんないけど「データ」→「フィルタを作成」をクリックしてみたのよ。それだけで作りたかったデータベース機能は全て自動的に完成した。

・太古の昔Lotus1-2-3とかではこういうのはぜんぶ自力で設定してたような気がするし、けっこうめんどくせーイメージがあったからそれっきり表計算のデータベース機能なんて触ったことなかったけど今はこんなことになってるんだな。ソフトウェアのちからってすげー!

・あと、品番からURLを作っておくと便利であろう。適当な列を用意して

= "https://akizukidenshi.com/catalog/g/g1" & TEXT(B1, "00000")

 これを貼ると各行の品番を参照してURLになってくれる。品番がB列じゃない場合は「B1」の部分を適切に書き換えること。

・秋月のサイト、リニューアル前は「商品ページへの直リンクやめてね」って書いてあったんだけど、今はその文言が見当たらないのでたぶん大丈夫になったんだと思う(が自己責任で)。

・なおリンクを踏まなくてもカーソルをURLの上で静止させて少し待つと商品画像が出る。またすごいねこれも。

・さらにデータシートへのリンクもこういうところに貼っとくとよいのだが、まあそれは手動でやるしかないので。

秋月電子通商の購入履歴(2)CSV変換

・いつもCSVCVSどっちがどっちだかわかんなくなる俺のための前回のあらすじ:一生に一度は巡礼しなければならないと教義に定められている秋月電子通商だが、太古の昔秋葉原通学経路俺の庭だったので、当時若者であった俺は怖いもの見たさで足を踏み入れる。そこはまさに酒池肉林。飲めや歌えやのパラダイスであった。果たして約30年後、2023年2月より前の購入履歴が何者かによって削除されてしまう。そこで俺は友達料として毎月3000円も払っているのをいいことに「俺達友達じゃん? タダでやってよ」とChatGPTに迫るのであった。

・っていうか毎月2000円くらいのつもりだったけど今のレート見たら1ドル150円くらいだった。よくわからんが30年は失われたのだ。断じて許してはならぬ。

・で、前回は受注確認メールから日付と発注品目のみを抽出した。今日はそれをCVS⋯⋯じゃなかった、CSVにしていく。何てことはない、カンマ区切りのテキストファイルで、適当に表計算ソフトにつっこめば適当に表らしきものになってくれるやつ。

・俺くらいになるとここで指パッチンするだけで友達がPythonコードを書いてくれるようになる。これができるのは月3000円も払ってる奴だけと思いきや、たぶん無料でもやってくれると思う。そんな慈愛に満ちた友達がいる俺もまた慈愛に満ちていると言わざるをえない。

・事情によりコードは3つに分かれているが、例によっていずれも著作権を主張しないCC0ライセンスで。使用は自己責任を要する。

・まず、先の「日付と品目だけ抽出したテキスト」から、日付だけの行と、品目だけの行に分かれたCSVファイルに変換するプログラム。その過程で日付は日本式の「年/月/日」に、品目の英数記号は半角に変換する。品目の行の内訳は左から品番、品目、単価、数量、小計金額。

# もう説明めんどくさくなった。前回のをCSVに変換するその1。
# written by Chinorin and Merry LLM. No Rights Reserved.
# This program is released into the public domain under the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication.

import re
import unicodedata

# 入力ファイルと出力ファイルのパス
input_file_path = 'history.txt'
output_file_path = 'history_o.csv'

# 正規表現パターン
pattern1 = r"^.*【[A-Z]-(\d+)】(.*)\n.*¥([\d,]+).*:(\d+).*¥([\d,]+)"  # 2行にまたがる
pattern2 = r"^Date: (\d+) ([A-Z][a-z][a-z]) (\d+).*"

# 月名を数値に変換する辞書
month_to_number = {
    "Jan": "1", "Feb": "2", "Mar": "3", "Apr": "4", "May": "5", "Jun": "6",
    "Jul": "7", "Aug": "8", "Sep": "9", "Oct": "10", "Nov": "11", "Dec": "12"
}

# 全角文字を半角文字に変換する関数
def zen_to_han(text):
    return ''.join([unicodedata.normalize('NFKC', char) for char in text])

# 出力ファイルを開く
with open(output_file_path, 'w', encoding='utf-8') as output_file:
    # 入力ファイルを読み込む
    with open(input_file_path, 'r', encoding='utf-8') as input_file:
        lines = input_file.readlines()
        
        # 行を一つずつ処理
        for i in range(len(lines)):
            # パターン1にマッチするかチェック
            if i < len(lines) - 1:  # ファイルの最後の行でないことを確認
                match = re.match(pattern1, lines[i] + lines[i+1])
                if match:
                    # 価格と合計からカンマを取り除く
                    price = match.group(3).replace(',', '')
                    total = match.group(5).replace(',', '')
                    output_file.write(f"{match.group(1)},{zen_to_han(match.group(2))},{price},{match.group(4)},{total}\n")
                    continue

            # パターン2にマッチするかチェック
            match = re.match(pattern2, lines[i])
            if match:
                # 月名を数値に変換
                month_str = match.group(2)
                month_num = month_to_number.get(month_str, "0")  # 月名が辞書になければ"0"を返す
                output_file.write(f"{match.group(3)}/{month_num}/{match.group(1)}\n")

・続きまして、↑で変換したものに対して、日付を品目行に差し入れるプログラム。これにより、全ての行を単なるレコードとして扱えるようになる。項目は左から日付、品番、品目、単価、数量、小計金額。

# CSV変換その1で作ったやつを、日付を全レコードの先頭に入れ込む。
# written by Chinorin and Merry LLM. No Rights Reserved.
# This program is released into the public domain under the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication.

import re

# 入力ファイルと出力ファイルのパス
input_file_path = 'history_o.csv'  # 先ほどのプログラムで作成されたCSVファイル
output_file_path = 'history_with_dates.csv'  # 新たに作成するCSVファイル

# 日付の正規表現パターン
date_pattern = re.compile(r'^\d{4}/\d{1,2}/\d{1,2}$')

with open(input_file_path, 'r', encoding='utf-8') as input_file, \
     open(output_file_path, 'w', encoding='utf-8') as output_file:
    current_date = ''  # 現在の日付を保持する変数
    for line in input_file:
        line = line.strip()  # 改行文字を除去
        if date_pattern.match(line):  # 日付行の場合
            current_date = line  # 現在の日付を更新
        else:  # 商品行の場合
            # 日付を商品行の先頭に追加して出力ファイルに書き出し
            output_file.write(f"{current_date},{line}\n")

・そんでCSV変換に関するラスト。これは絶対必要というわけではないが、全件日付でソートするプログラム。

# 日付を全レコードの先頭に入れたやつ全体を日付でソートする
# written by Chinorin and Merry LLM. No Rights Reserved.
# This program is released into the public domain under the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication.

import csv
from datetime import datetime

# 入力ファイルと出力ファイルのパス
input_file_path = 'history_with_dates.csv'  # ソート前のCSVファイル
output_file_path = 'sorted_history.csv'  # ソート後のCSVファイル

# CSVファイルを読み込んでデータをリストに格納
with open(input_file_path, 'r', encoding='utf-8') as input_file:
    reader = csv.reader(input_file)
    data = [row for row in reader]

# 日付を基準にしてデータを逆順にソート
# 日付が最初の列にあると仮定して、その日付をdatetimeオブジェクトに変換して比較
data.sort(key=lambda row: datetime.strptime(row[0], '%Y/%m/%d'), reverse=True)

# ソートされたデータを新しいCSVファイルに書き出し
with open(output_file_path, 'w', encoding='utf-8', newline='') as output_file:
    writer = csv.writer(output_file)
    writer.writerows(data)

・ここまでできればけっこう汎用的なデータとして扱えるのではないか。あとは趣味で、ウェブサーバで動作するこれらを検索して表示するためのPerlPHPかなんかのスクリプトでも作ろうと思う。まあのんびりやろう。

・いや、作るのは俺じゃなくて友達なんだけど。

秋月電子通商の購入履歴(1)受注確認メールから抽出

 ・秋月電子通商という全人類が毎日必ず訪れる生活になくてはならない超重要インフラとも言うべきショップのウェブサイトがあるんですけど、先日リニューアルしまして、見た目をなるべく変えない努力をしているように見えて非常に好感が持てるのはいいんですが、2023年2月より前の購入履歴が全て消えてしまいました。聞いてないよ~。

・はい。本当に俺が聞いてなかっただけ。ちゃんとアナウンスもされていたらしい。

・大方の予想通りパーツ管理は杜撰どころか壊滅的なわたしです。当然購入履歴が見られないと困ってしまうんだが、𝕏などを見ると「購入履歴が消えちゃったから、過去に買ったものをもう一度重複して買ってしまうかもしれないなあ。しょうがないなあ」とニヤニヤしている強者も散見され、さすが沼に頭頂部まで浸かってる人は違うな、ああはなりたくねえな、と決意を新たにしましたとさ。めでたしめでたし。

・いや、ごめん、その気分はすげえわかる。電子部品を買い散らかすことは喜びであり、ストックが確かあるはずという安心感に代わるものはこの世にない。そして買ったはずなのにどんなに探しても見つからないパーツは消費せずに済むのが喜ばしく、仕方ないからまた注文するのも快楽であるのだ。ストックとは⋯。

・で、困ってしまうのでとりあえず注文確認メールから抽出することにした。全てGmailに届いているので、まず検索して該当するメールに適当なラベルをつけ*1、次にGoogle TakeoutでGmailの該当するラベルを選択してエクスポート*2。関係ないメールが混じっていても問題にはならないのでラベルづけはけっこう適当でもよい。

・エクスポートされた内容は「ナントカ.mbox」という1つのファイルにまとめられており、これはテキストファイルなので簡単に扱える。というわけで優秀な友達に購入履歴っぽい部分を抽出するPythonコードを書いてもらった。【ヘッダの中の日付にあたる行】と【「【ご注文者】」という文字列を見つけたらその行から「【お支払方法】」のある行まで】を新たなファイルにまとめて書き出すというもの。

・例によって著作権を主張せずパブリックドメインに供することにする。使用の際は自己責任で。

# 秋月電子通商の注文確認メールから注文履歴をまとめるPythonコード
#   (1) .mboxファイル(つまりテキストファイル。input_file)を読んで、
#   (2) start_patternを含む行からend_patternを含む行までを抽出
#   (3) ヘッダから日付を抽出
#   (4) 2と3をテキストファイル(output_file)に書き出す
#   ※入力する.mboxファイルはあらかじめUTF-8にしておくこと。
# written by Chinorin and Merry LLM. No Rights Reserved.
# This program is released into the public domain under the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication.

import re

# ファイル名
input_file = 'akizuki.mbox'
output_file = 'history.txt'

# 正規表現パターン
start_pattern = re.compile(r'【ご注文明細】')
end_pattern = re.compile(r'【お支払方法】')
date_pattern = re.compile(r'^Date:.*')

def extract_text(input_file, output_file, start_pattern, end_pattern, date_pattern):
    with open(input_file, 'r', encoding='utf-8') as file:
        lines = file.readlines()

    output_lines = []  # 出力するテキストを格納するリスト
    extracting = False  # テキスト抽出中フラグ
    last_date_line = None  # 最後に見つかった日付行を保持

    for line in lines:
        if date_pattern.search(line):
            # 最後に見つかった日付行を更新
            last_date_line = line
            continue  # 以降の処理をスキップ

        if start_pattern.search(line) and not extracting:
            if last_date_line:
                # 最後に見つかった日付行を追加
                output_lines.append(last_date_line)
                output_lines.append('---\n')  # 日付行の区切りを明確にする
                last_date_line = None  # 日付行をリセット
            extracting = True  # 抽出開始
        
        if extracting:
            output_lines.append(line)  # テキスト抽出中の行を追加
        
        if end_pattern.search(line) and extracting:
            extracting = False  # 抽出終了
            output_lines.append('---\n')  # 抽出セクションの区切りを明確にする

    # ファイルの最後が日付で終わる場合に対応
    if last_date_line and not extracting:
        output_lines.append(last_date_line)
        output_lines.append('---\n')

    with open(output_file, 'w', encoding='utf-8') as file:
        file.writelines(output_lines)

# 関数を呼び出し
extract_text(input_file, output_file, start_pattern, end_pattern, date_pattern)

Googleから出てきた.mboxファイルはエンコードがJISなので、あらかじめUTF-8に変換しておくこと。秀丸なら ファイル→エンコードの種類→Unicode(UTF-8)→内容を維持したまま適用 でおk。シフトJISでも encoding='utf-8' のところを 'shift_jis' にするだけだが、JISのままでは 'iso-2022-jp' とかにしてもなぜか読めなかった。

・なお、入力ファイルに余計なメールが含まれている場合、普通にやると日付だけが抽出されてしまうので、日付が2回以上連続でマッチしたらそのうちの最後の1回のみを書き出すようになっている。

・入力ファイル名(akizuki.mbox)、出力ファイル名(history.txt)、開始パターン(【ご注文者】)、終了パターン(【お支払方法】)、日付パターン(Date:.*)それから区切り(---\n)なんかを改変すると他の用途にも使えるかもしれない。パターンについては全て正規表現として扱われるので、半角記号とかはエスケープする必要があるかも。

・以上、注文履歴をそのまんま書き出すでござるの巻。このままでもまあまあ便利だと思うけど、次はいったんCSVにしてからもう少し加工していきたい。つづく。

・あ、これ、次のをすぐに書かなきゃいけないやつ。

*1:左のチェックボックスにチェックを入れ、上部の「ラベル」アイコン→新規作成で新しいラベルを作る。

*2:まず「選択をすべて解除」し、Ctrl+F等からGmail(メール)を検索、右のチェックボックスにチェックを入れ、「メールのすべてのデータが含まれます」をクリック→「メールのすべてのメッセージを含める」を解除→「すべて選択」の位置を2回クリックするなどしてすべて解除→該当するラベルにチェックを入れる→OK→一番下の「次のステップ」→エクスポート先などを設定→「エクスポートを作成」をクリック。そんでしばらく待つ。

明けまして新しいはんだごてを買った

・はんだごておめでとう。

・しばらくHAKKOのPRESTOという温調のない急速加熱つきはんだごてを使っていてこれもまあまあ便利だとは思うんだけど、やっぱり立ち上がりの加熱にどうしても時間がかかってしまうのが俺をはんだづけ作業から遠ざけていたし、それと同時に作業の失敗も誘っていた。いったん電源を入れたら修正までぜんぶやらないと次に電源を入れるときにまた待ち時間が生じてしまうからだ。

・今回は念入りに下調べをしたよ。結局、セラミックヒーター方式で熱容量の大きいこて先というお決まりのパターンがいけないんだという結論に至った。どうしても熱容量は必要ではないかと思ってしまうところだが、実はデジタル温調の精度と加熱の能力がしっかりしていれば温度が下がる側からどんどん加熱するはずだからその方が問題が少ないのではないか。

・そこでたどり着いたのが、JBCの規格C210とC245、それからHAKKOの規格T12。最近よく「意外といい」と耳にするUSBはんだごてなんかも同じ方式なんだと思うけど、このへんのはヒータがこて先の先端付近?に内蔵されていて加熱がめっちゃ早いらしい。C210は2秒ではんだが溶けるとか言ってる。

・で、色々値段とかも鑑みてT12-942というT12規格の互換機にした。むろん中国メーカの製品だ。12月27日にAliExpressで注文して(ちなみにAliExpressでは初注文)、同日中国から出荷されて元日に届いた。配送や通関に携わる方々には感謝しかない。

・一応ステーション型で、ステーションのサイズは90×40×40⋯⋯ってあんまり似てる大きさのものが思いつかないんだけど、チョコボールの箱を3個重ねたくらいかなあ⋯⋯というなかなかのミニサイズ。

・もちろんデジタル温調で、表示されている温度と実際のこて先温度との差も小さいっぽい。電源を入れてからはんだが溶けるまで、さすがに2秒とはいかないが、だいたい6~7秒といったところか。夏はもっと速いだろう。

・スリープ機能やブースト機能なんかもあって、スリープに至る時間(デフォルトは30秒)や、ブーストの温度(デフォルトは+50℃)やボタンを押してからブーストが終わるまでの時間(デフォルトは30秒)は調整可能。スリープはステーションのボタンを押すか、こて部に内蔵されている何らかのセンサが反応すると解除されるみたいなのだが、このセンサの正体がよくわからん。とにかくはんだづけ中でも平気でスリープに入るので、そのたびにこて部を振ったりするのが面倒だ。そもそも360℃程度にしておくならそんなにきっちりスリープしなくてもいいんじゃないかと思う。5分くらいに設定しておくことにしよう。

・でもお高いんでしょう? ご安心くださいそこはAliExpress価格、今なら異なる種類のこて先5本がついてきて、堂々の3,360円でございます。ただし電源は付属しておりませんので、24V4Aの電源を別途ご用意ください。俺も同時に注文したんだけど電源が届くのが数日後だったので、それまでは安定化電源で運用した。Φ2.1/5.5のセンタープラスでおk。

・↓Amazonでも4000円程度で売ってるようだ。これも電源ついてないみたいね。

・っていうか、特にこういう電熱関係の機器は電源が内蔵されてない方が安心だったりするんだよね。ほら、AC100Vを採用してる国って日本くらいしかないわけじゃん⋯?

ゴミの名前

・何か書こうと思ってやめるというのを繰り返してたんだけど、何を書くにもまずこれを最初に書いてそれから本題を書かなきゃいけないのが億劫というか、記事が長くなりすぎるのが目に見えているので全体が面倒になってるというのが明白なのでこの部分だけ先に書いてしまえよ。


・前回のバッファの話。まあバッファっていう名前の通りなんだけど。

・論理ゲートを使うような、あるいはマイコンで扱うようないわゆるデジタル回路は、アナログ量である電圧の解釈によって擬似的にデジタル処理をしているにすぎない。ソフトウェアで変数に入れるような値と違って、デジタル信号は引き回すことで電圧が下がったり様々な理由でノイズが乗ったりして、信号の品質が劣化することがある。

・色々と使い回して劣化しまくり今にも読み取り不能になりそうなデジタル信号を、元の綺麗な信号に戻すために使うのがバッファという論理ゲートである。バッファは、入力したデジタル信号の値をそのまま出力する*1

・論理的かつ理想的には[バッファ A]は[NOT(NOT A)]と等価*2で、実際にそれで代用することもあるし、汎用ロジックICのデータシートに載ってる等価回路を見てみると、出力の直前にバッファとして動作する複数のNOTゲートがずらずら並んでたりする。

・↓これは、バッファとNOTゲート、それからANDゲートとNANDゲートの旧JIS記号だけんども。

・言うまでもなく[A NAND B]は[NOT(A AND B)]と等価ね。これらの動作と記号を比べてみればわかる通り、NOTを表しているのは出力のところについてる小さい丸で、NOTゲートに書かれている三角形は実はバッファそのものなわけ。

・ちなみに、電子工学界隈ではNOTゲートのことをみんな頑なにインバータ*3と呼ぶんだが、フルネームはたぶん inverting buffer なのだろうと思う。インバーティングあるいはインバーテッドなんとかってたまにあるんだよね。オペアンプの反転入力 inverting input とか。

・なお、オペアンプの invert じゃない方の入力は通常入力とかではなく非反転入力 non-inverting input と呼ぶ。一般に inverting の方が通常の動作であり高速なのでそんな風な言い方になってしまうらしいのだが、そのように inverting との対比があるときは通常のバッファについて non-inverting bufffer という言い方を実際にするらしい。

・さらにややこしいのが74HCU04の存在で、これはNOTゲートが6つ搭載された汎用ロジックなんだけど、それぞれ反転するがバッファはしない。これについてはアンバッファ unbufferという。Uはその頭文字なのだろう。ロジック=論理、論理といえばデジタルなのに、この汎用ロジックは主にアナログ回路で使われる。*4

・⋯ということは、これでもう0Ω抵抗器のことをただのゴミとかとか言わずに済むのではないか。これからは自信を持ってこう呼ぼう。そう、非反転アンバッファ non-inverting unbufferである。


・意外とこの話だけでも長くなるもんだな。

*1:入力がHIGHなら出力はHIGH、入力がLOWなら出力はLOW。

*2:実際は { NOT(NOT A) } の方がゲートを1つ多く使う分だけ遅延が長くなる可能性が高い。

*3:インバータ: invertは反転させるという他動詞なので、inverterは反転させる人のこと。

*4:そのようなアナログICと呼ぶべき汎用ロジックはいくつかある。74HC123のようなマルチバイブレータや、74HC4051~4053アナログMUX、74HC4066アナログスイッチなど。