Quantcast
Channel: エンジニア徒然草
Viewing all 60 articles
Browse latest View live

Ubuntuアップグレード (12.04 → 14.04.1) でgrubトラブル

$
0
0
何台かあるデスクトップPCの内の1台でUbuntu 12.04 LTSを動かしていたのだが、7月末近くに14.04.1 LTSがリリースされアップデート・マネージャーを使った自動アップグレードが可能になった。半月程経ち、大きな問題は無さそうなのでアップグレードを行ったが、タイトルの様にトラブルに見舞われてしまった。

/*-----------  -----------*/

Ubuntu LTSのアップグレード・スケジュール

今動かしているのが非LTSの場合、新しいリリースが利用可能になり次第自動アップグレードできるようになる。つまり13.10を使っているなら14.04がリリースされ次第アップグレード可能になるわけだ。しかし今使っているのがLTSだと、新しいリリースのマイナーバージョンが1つ上がって14.04.1にならないと自動アップグレードは可能にならない。安定性重視、と言うことだ。

Ubuntu 14.04.1 LTSは7月24日リリース予定だったが、特に遅れなくリリースされた模様である。

 

アップグレードの準備

最悪Ubuntuは再構築しても良かったので、念のためデータの入っている/homeパーティションだけバックアップしてアップグレードを開始した。

 

トラブル

アップグレードは大した問題もなく完了し、再起動までこぎつけた。しかし!再起動したら見慣れない画面で止まってしまった。

grub rescue> _

起動環境に何か問題があることは分かる。しかしお初にお目にかかる画面でどうしていいのか皆目見当がつかない。こういう時はGoogle先生頼みだ。

パーティションの切直しなどしていないのでgrubの何かが壊れた可能性が高い。とりあえず起動できるようにしてgrub-installすれば直るはずである。検索でヒットしたページを参考に起動を試みたが、何かおかしい。

grub rescue > set prefix=(hd0,msdos1)/boot/grub
grub rescue > insmod (hd0,msdos1)/boot/grub/i386-pc/normal.mod

error: file '/boot/grub/i386-pc/normal.mod' not found

grub rescue > ls (hd0,msdos1)/boot/grub/i386-pc/normal.mod

error: not a directory

lsはnormal.modが在ると言っているのだがinsmodでは見つからない。ナンデ??

日本語の答えは見つからなかった。こういう時は英語で探し直すしかない。ナルホド、こういうことなの?

(MorrisseyJの答えの冒頭)

It seems that one cause of this problem is the installer thinking that you have EFI secure boot, when you don't and therefore loading the incorrect GRUB files.

この問題の原因の一つは、インストーラーが本当はそうじゃないのにEFIのセキュアブートになっていると考えて間違ったGRUBファイルをインストールしてしまう事らしい。

私の場合、問題になっているPCのCPUはNorthwoodコアのPentium4だ。10年以上使っている。もちろんUEFIなんかじゃあない。言うのが遅くなったがUbuntuは32ビット版だ。またハードディスクの区画はsda1=/、sda2=SWAP、sda3=/homeである。grubはsda1の/bootディレクトリー下にインストールされているはずだ。

もしかすると本当の原因は別にあるのかもしれないが、「grub rescue>」でどんなに頑張ってもダメな場合があると分かった。さっさとDVDかUSBメモリーからUbuntuを起動してgrub-installするのが吉である。手元に14.04の起動メディアが無かったので12.04のものを使った。ハードディスクのUbuntuが起動してからgrub-installをやり直せばよいから、とりあえず起動させるにはgrubのバージョンなどはあまり関係ない。起動メディアからUbuntuが立ち上がったら、

$ sudo mount /dev/sda1 /mnt

$ sudo grub-install /dev/sda --root-directory=/mnt
 

これで再起動。「file not found」が3行出てヒヤッとした。grub-installした時と環境が違っているからだろうか。しかし最終的にハードディスクからUbuntu 14.04.1が起動した。こうなればこっちのものだ。

$ sudo grub-install /dev/sda
 

これで再起動。「file not found」はもう出ない。dmesgなど確認しても問題なし。これにて一件落着。

 

今回のまとめ

自動アップグレードだったから問題が起こったのか、クリーンインストールでも同じ問題が起こり得るのか、定かではない。いずれにせよ古いハードウエアでUbuntuをアップグレードする際の要注意点である。


ワットチェッカー的なものを自作する (その4)

$
0
0

このシリーズの前回の記事にBBBのPRUを使ってADE7753からデータを取り込む方法を紹介すると書いたが、今回はその予定を変更する。

PRUの件の記事を準備する過程で発見したことを書く。電源用トランスを商用電源から電圧信号を取り出すのに使うには少し問題がある。

/*-----------  -----------*/

ADE7753の電圧信号の位相遅れ対策

ADE7753では波形データとゼロクロス信号に使う電圧データはLPFを通るため50Hzで約19.7°の位相遅れがある。rmsと皮相電力の計算にも同じ信号が使われるが、出力されるのが信号周期よりも十分長い期間の平均値なので位相遅れは問題にならない。また有効電力とリアクティブ電力の計算にはLPFを通る前の電圧信号が使われている。

電流波形などと並べて電圧波形をプロットする場合は位相遅れを補正する必要がある。波形データの取り込み開始はゼロクロス信号を基準に制御するが、この信号も位相遅れがあるので電圧波形はそのままでよい。しかし電流と有効電力の波形を取り込む場合はタイミングを調整する。

300w

サンプル数単位の記録開始遅延時間が信号の周期とサンプルレートから計算できるので、ゼロクロスの後その数だけサンプルを破棄し、その後記録開始すればよい。純抵抗負荷として300Wの強制空冷式のダミーロード、と言うと大仰だが早い話ヘアードライヤーを接続して波形データを記録してプロットしてみた。

300w

27.9kspsで出力するよう設定したADE7753のWAVEFORMレジスターのデータである。各値は暫定的な換算係数を使っているので正確ではない。電流と電圧の間に位相差は無いはずなのだが、プロットのゼロクロス部分を見ると明らかに電流の位相が遅れている。タイミング調整が間違っていないか確認したが問題ない。こうなるとADE7753に入力される信号そのものの位相差を疑う必要がある。

なおグラフ上の波形の振幅は特に調整していないが、偶然ほぼ同じになった。こうなっているとグラフを見ただけで位相差が分かり易い。

 

入力信号を確認する

このシリーズの最初の回でやったようにPCオーディオを使って信号を確認してみた。これなら計測系の電流と電圧の信号経路に位相差は無いので信号の元々の位相差がはっきりと分かるはずである。

Wf_consoli

今度は振幅を合わせるロジックを入れた。ゼロクロス付近を見ると約250μsの時間差がある。位相にして4.5°だ。電流の波形が遅れている。

最初電流トランスの問題を疑った。今回使った電流トランスの仕様に位相誤差の規定は無いが、一般的な電流トランスの例だと計測範囲の下端付近では最大200分=約3°程度の位相誤差が出る場合がある。しかし電流トランスの位相誤差は通常進み方向なので今回の現象と合致しない。

プロットをよく見ると少しおかしなことがあるのに気付いた。ゼロクロス付近に比べてピーク付近は曲線のずれの程度がかなり小さい。これはどうも波形歪があるらしい。そう言うことなら波形をフーリエ変換してスペクトラムを見るのが一番いい。

Spectrum

パワースペクトラムの平方根を取っているので縦軸は振幅比に相当する値である。ほとんどの部分は一致しているが、3倍の高調波である150Hzの成分だけは電圧の方が電流よりも10倍程度大きい。またフーリエ変換結果から得られた歪率と位相関係の情報は以下のとおりである。

電流波形電圧波形
歪率 (THD+N) [%]3.14.0
50Hz成分の位相角 (窓関数基準) [°]-44.6-41.9
50Hz成分の位相差 (電圧-電流) [°]2.7

どうやらこれはこう言うことらしい。

  • 電圧信号取り出しに使っているトランスで歪率約2%に相当する3次高調波歪が発生している。
  • それ以外の波形歪は供給されている商用電源波形に元々あった可能性が高い。

トランスが発生している3次高調波歪の量はスペクトラムのプロットから推定した。歪率を計算する時、高調波の各成分の二乗和の平方根を取るため加成性が成り立たない。また歪以外に50Hzの基本波成分の位相差もあり、電圧信号が電流信号より2.7°進んでいる。

波形歪と位相誤差による電力値の誤差は平均的な条件で5%程度と見積もられる。これは無視できない大きさなので対策が必要だ。また最悪条件では相当大きな誤差になる可能性もある。

なお電流波形には電圧波形に無い偶数次の高調波や倍数関係でない周波数の成分があり、ファンを回しているブラシモーターなどからのノイズではないかと思われる。ただしレベルが-60db以下と小さいので無視しても影響ないはずだ。またADE7753を使って採取したものに比べて電圧波形のピークが平坦になっているが、これはADE7753の電圧波形はLPFを通ったものなので高調波が取り除かれて正弦波に近くなっているためだと考えられる。

 

対策

今回調査して電圧信号の取り出し用に造られた「電圧検出トランス」があることが分かった。詳細な資料 (PDF)によれば波形歪と位相誤差両方とも小さくなるように作られている。商用電源の電圧信号を得るためにはこの種のトランスを使わないとマズかったようだ。

詳細資料を見ていて気付いたのだが、これによれば電源トランスの場合の位相差は最大100μsecに及ぶとある。今回使ったトランスの場合、基本波の位相差2.7°は150μsでやや大きい。電流トランスの位相進みもあればその分さらに大きいはずだ。意図的に選んだのではないが、今回使った電源トランスは「Short circuit proof」になっているものだ。もしかするとその影響があるのかもしれない。

前出リンクの製品ではないが電圧検出トランスを手配した。この製品は通販で入手可能だ。ただし少し納期がかかるようである。また歪・位相誤差の規定値は不明だが、今使っている電源トランスよりかなりマシだろうと期待している。

ADE7753を使うのなら電圧と電流信号は抵抗で取り出し、デジタル信号に変換された部分で絶縁する手段が使える。量産する製品ならこうすべきだろう。ワットチェッカーの類にBluetoothでスマートフォンやPCとつないで使うものがあるが、無線接続にしているのは絶縁する目的も兼ねているのだと思う。

 

今回のまとめ

電流・電圧信号を取り出すのにトランスを使うと位相誤差があるかもしれないと認識していたが、波形歪までは考えが至らなかった。位相誤差に変動が無ければ補償可能である。しかし変動が無い確証はないし、また歪は簡単には補償できない。

安全性と自由度を確保するため電圧検出トランスを使うようにした。これで問題ない範囲に収まる事を期待しているが、トランスを使う限りそれに伴う誤差がゼロにはならない。抵抗を使って信号を取り出すようにすれば位相誤差と波形歪はほとんどゼロにできるはずである。

電圧検出トランスが届くまで時間がかかりそうなので、いったん本来の予定に戻そうと思う。届いたらトランスの差異比較をして報告するつもりだ。

ワットチェッカー的なものを自作する (その5)

$
0
0

手配した電圧検出トランスが意外と早く到着したので、再び予定を変更して前回の記事の続きを書く。

/*-----------  -----------*/

電圧検出トランスVT2401-A01

左側が到着した電圧検出トランスである。

Vt2401

今まで使っていた電源トランスに比べると二まわりほど小さい。メーカーのホームページに「0.03Φの極細電線の巻き線技術により、国内最小クラスの小型化を実現しました」とあるが、本当に小さい。一次巻き線の直流抵抗を測ったら約14kΩだった。電源トランスは約750Ωなので約19倍、トランスの巻き線とは思えない値だ。位相が進まないよう巻き線インダクタンスを大きくする必要があるはずだから極細電線を多数回巻いているのだろう。

写真で分かるように引き出し部分の巻き線が露出している。少し気になる構造だ。写真に写っているのは二次側なので割と太い電線だが、反対側の一次巻き線は「0.03Φの極細電線」だ。基盤に実装してしまえば奥まった場所になるのでうっかり触って切ってしまう心配は無いのかもしれない。しかしフラックスなどが付着して長期的には腐食したりしないか心配である。

二次電圧をデジタルテスターで測ると約1.2Vだった。電源トランスの場合の約1/10。このくらい小さな電圧だとテスターは誤差が大きくなる可能性がある。一応の参考情報だ。電圧の換算係数などは組み立てた後、実測した一次電圧との対比で求めることにしよう。

 

電圧検出トランスの効果

前回と同じようにPCオーディオを使って信号を確認してみた。ただしトランスの二次電圧が低下したのを補うため電圧信号の分圧比を1/101から11/111に変更している。この際にPCから見た信号源インピーダンスが10倍高くなったのでノイズを拾いやすくなってしまったようだ。

Wf_consoli

電圧信号のノイズで曲線が左右に揺れているが、ゼロクロスの時間差は揺れの中心を採ると約30μsである。位相にして0.54°だ。電圧の波形が遅れている。前回は250μs≑4.5°電圧信号が進みだったので、電圧信号の位相進みが電流信号よりも小さくなったようである。

フーリエ変換したスペクトラムを見ると、

Spectrum

3倍の高調波成分は依然として電流波形より電圧波形の方が大きい。しかしその違いは2倍程度 (以前は約10倍) であり歪率1%に相当するよりも小さなレベルなので全体に及ぼす影響はかなり小さいはずだ。フーリエ変換結果から得られた歪率と位相関係の情報でみると、

電流波形電圧波形
歪率 (THD+N) [%]2.82.8
50Hz成分の位相角 (窓関数基準) [°]-17.5-17.8
50Hz成分の位相差 (電圧-電流) [°]-0.3

第3次高調波歪の量は歪率の数字に表れるほどではない。

総合的に考えると、電圧検出トランスで電圧信号を取り出す際に生じる歪や位相差など誤差の要因は、電流信号を電流トランスを使って取り出す際のものと同じ程度の水準に収まった、と言えそうである。

 

電圧信号の換算係数

トランスの出力電圧が小さくなったことに合わせてADE7753の回路を以下のように修正した。

Ade7753_schema_mod

朱記した抵抗値の変更1か所である。この回路を使って電圧信号のアナログ的な分圧比などを計算した。

No.項目根拠、式など
商用電源電圧テスターで実測100.5 [Vrms]
ADE7753 VRMSレジスター値実測0x0dc395
ADE7753 ch2入力電圧/ADC出力データこのシリーズの記事第3回4.844e-05 [V]
ADE7753 ADC出力/VRMSレジスター値このシリーズの記事第3回4.566e-03
ADE7753 ch2入力電圧② x ③ x ④0.1995 [Vrms]
電圧検出トランス二次電圧⑤ x (5.1 + 1)1.217 [Vrms]
電圧検出トランス変成比100:(⑥ x 100 / ①]100:1.211

このシリーズ第3回の記事に登場した電圧の減衰比をRは、今回の電圧検出トランスを使った回路では以上の結果から R = (1.211/100) x (1/6.2) = 0.001953 である。電源トランスを使った回路では 0.002115 だったので少し小さな値になり、フルスケールまでの余裕が若干増えたことになる。

 

電圧信号取り出しに電源トランスを使うべきでないもう一つの理由

製造元のデータシート (PDF)によると、今まで使っていた電源トランスは無負荷時消費電力 (No-load loss) が0.6W (代表値) ある。電圧を測ろうとするだけで少なくとも0.6W電力を消費してしまうのはバカらしい話だ。またトランスがそれなりに熱を持つのもあまり気持ちのいいものではない。

今回入手した電圧検出トランスに無負荷時消費電力の規定は無い。無負荷状態で一次電流を実測したら約190μAだった。電圧に対する位相関係などは分からないが、このトランスによる無負荷時の消費電力が19mWを超えることが無いのは確かだ。また二次側で電圧を測る際に消費する電力は大きくても1mWを超えないので、負荷状態の消費電力もせいぜい20mW位だろう。

小さな数字の議論だが常時電源に接続しておく場合を考えるとそれなりに差が出る。1年間の電気代は (0.6 – 0.02) [W] x 24 [h/日] x 365 [日/年] x 0.001 [kW/W] x 30 [\/kWh] = 152 [\/年] の差になる。電圧検出トランスと電源トランスの価格差がほとんど無いことを考えると、無視できない数字である。

 

今回のまとめ

電圧検出トランスにより目論見通りの効果が得られた。今度こそ本来の予定に戻そう。このシリーズの次回はPRUを使ってADE7753のデータを取り込む方法を紹介する。

ワットチェッカー的なものを自作する (その6)

$
0
0

懸案だった BBB の PRU を使って ADE7753 からデータを取り込む方法を紹介する。

/*-----------  -----------*/

PRU の利用に必要な環境

以前の記事に書いた通り am335x_pru_package に含まれる prussdrv ドライバーと pasm アセンブラーが必要である。またデバッガーも必要で、同じ記事で紹介した Prudebug を使う。

 

McSPI0 と PRU-ICSS を有効化して P8-15 と P8-16 を使えるようにする

Device Tree Overlay を使う。McSPI0 はDebian に標準で含まれている BB-SPIDEV0 を使えばよいが PRU-ICSS と I/O ポートについては新たに作成する必要がある。

$ cat BB-PRU-P8_1516-00A0.dts
/*
* pru dts file BB-PRU-P8_1516-00A0.dts
*/

/dts-v1/;
/plugin/;
 
/ {
  compatible = "ti,beaglebone", "ti,beaglebone-black";

   /* identification */
  part-number = "BB-PRU-P8_1516";
  version = "00A0";

  exclusive-use =
    "P8.15", /* input */
    "P8.16", /* input */
    "pruss";
 
  fragment@0 {
    target = <&am33xx_pinmux>;
    __overlay__ {
      mygpio: pinmux_mygpio{
        pinctrl-single,pins = < 
                0x03C 0x36 // P8_15 = GPIO1_15
                0x038 0x36 // P8_16 = GPIO1_14
                >;
      };
    };
  };

  fragment@1 {
    target = <&pruss>;
    __overlay__ {
      status = "okay";
      pinctrl-names = "default";
      pinctrl-0 = <&mygpio>;
      pru_p8_15 {
        pin-names = "GPIO:PRU-P8.15";
        gpios   = < &gpio2 15 0 >;
      };
      pru_p8_16 {
        pin-names = "GPIO:PRU-P8.16";
        gpios   = < &gpio2 14 0 >;
      };
    };
  };
};
$ dtc -O dtb -o BB-PRU-P8_1516-00A0.dtbo -b 0 -@ BB-PRU-P8_1516-00A0.dts
$ sudo cp BB-PRU-P8_1516-00A0.dtbo /lib/firmware/
$ cat ../pru_spi.sh
#!/bin/bash

echo BB-SPIDEV0 > /sys/devices/bone_capemgr.*/slots
echo BB-PRU-P8_1516 > /sys/devices/bone_capemgr.*/slots
cat /sys/devices/bone_capemgr.*/slots
$ sudo ../pru_spi.sh 
 0: 54:PF--- 
 1: 55:PF--- 
 2: 56:PF--- 
 3: 57:PF--- 
 4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
 5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
 7: ff:P-O-L Override Board Name,00A0,Override Manuf,cape-bone-iio
 8: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-SPIDEV0
 9: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-PRU-P8_1516

2つとも忘れずに Cape Manager に読ませるためシェルスクリプトを作った。

BB-PRU-P8_1516 を読ませないと PRU が使えない。例えば Prudebug を起動し、d コマンドで RAM の内容を表示しようとすると異常終了する。

$ sudo ./prudebug 
[sudo] password for debian: 
PRU Debugger v0.24
(C) Copyright 2011, 2013 by Arctica Technologies.  All rights reserved.
Written by Steven Anderson

Using /dev/mem device.
Processor type          AM335x
PRUSS memory address    0x4a300000
PRUSS memory length     0x00040000

         offsets below are in 32-bit word addresses (not ARM byte addresses)
         PRU            Instruction    Data         Ctrl
         0              0x0000d000     0x00000000   0x00008800
         1              0x0000e000     0x00000800   0x00009000

PRU0> d  
Absolute addr = 0x0000, offset = 0x0000, Len = 16
$ 

特にメッセージも出さずにシェルのプロンプトに戻ってしまう。これについては Prudebug に改善の余地がありそうだ。

一方 BB-SPIDEV0 を読ませなくても PRU も McSPI も一応動くが、外部と信号のやり取りができないので正常には動かない。

 

基本的な PRU のプログラム

ADE7753 の任意のレジスター1つを読出しまたは書き込みできるプログラムである。これを複数組み合わせれば原理的に何でもできるはずだ。SPI関連の主な処理内容は以下の通り。

  • PRU が SPI などをアクセスできるよう、OCP (On-Chip Peripheral) master ポートを有効にする
  • McSPI0 モジュールのクロックを有効にする
  • McSPI0 モジュールをリセットする
  • McSPI0 モジュールを設定する
  • McSPI0 モジュールとCS0信号を有効化する (同時に SPI クロック周波数を設定している)
  • データ転送を行う (2~4バイト)
  • McSPI0 モジュールを有効化して CS0 信号をアクティブにする
  • McSPI0 モジュールと CS0 信号を無効化する
  • McSPI0 モジュールのクロックを止める
  • 結果を RAM に保存して停止する

マルチタスクではないので割り込みは使わず全てプログラムで制御しているので、処理の内容が分かり易いのではないかと思う。複数バイト転送間隔などのタイミングもプログラムで制御するので FIFO などは使っていない。

$ cat demo0.p
// ADE7753 spi demo0

.origin 0
.entrypoint START

// MCSPI_CH0CONF param
// CLKG=1, FORCE=0, DPE0=1, WL=7, EPOL=1, CLKD=4, PHA=1
#define OFF_CONF 0x200103d1
// CLKG=1, FORCE=1, DPE0=1, WL=7, EPOL=1, CLKD=4, PHA=1
#define ON_CONF  0x201103d1

START:
// Set C24 reg. to 0x00000000
    MOV r5, 0x00022000      // Load PRU0 CTRL base address
    MOV r1, 0
    SBBO r1, r5, 0x20, 1    // Set C24_BLK_INDEX zero
// Enable OCP master ports.
    LBCO r1, C4, 4, 4       // Load SYSCFG reg.
    CLR  r1, r1, 4          // Clear STANDBY_INIT
    SBCO r1, C4, 4, 4       // Save new content to SYSCFG reg.
// Turn-on McSPI0
    MOV r6, 0x44E00000      // Load CM_PER base address
    MOV r1, 0x00000002      // Bit pattern to enable SPI0 clock
    SBBO r1, r6, 0x4C, 4    // Write to CM_PER_SPI0_CLKCTRL
// Reset McSPI0
    MOV r6, 0x48030100      // Load MCSPI0 + 0x100
    MOV r1, 0x00000002      // Soft reset
    SBBO r1, r6, 0x10, 4    // Write into MCSPI_SYSCONFIG
WAIT4RESET:                 // Wait for reset done
    LBBO r2, r6, 0x14, 4    // Read MCSPI_SYSSTATUS 
    QBBC WAIT4RESET, r2, 0  // Check RESETDONE
// Configure McSPI0
    MOV r1, 0x00000001      // Master, 4pin & single
    SBBO r1, r6, 0x28, 4    // Write into MCSPI_MODULCTRL
    MOV r1, 0x00000011      // Smart idle & autoidle
    SBBO r1, r6, 0x10, 4    // Write into MCSPI_SYSCONFIG
// Assert CS0 signal (low)
    MOV r1, ON_CONF         // SPI configuration word
    SBBO r1, r6, 0x2C, 4    // Write r1 into MCSPI_CH0CONF
    MOV r1, 0x00000001      // Param to enable McSPI0 channel 0
    SBBO r1, r6, 0x34, 4    // Write the param to MCSPI_CH0CTRL
// Prepare for transfer
    MOV r9, 0               // Clear RX data reg. (for debug)
    LBCO r8, C24, 4, 4      // Load data word
    LBCO r4, C24, 0, 1      // Load command byte
    QBEQ XFR_2_BYTE, r4.b0, 2
    QBEQ XFR_3_BYTE, r4.b0, 3
XFR_4_BYTE:                 // Transfer 4 bytes
    MOV r1.b0, r8.b3
    CALL XFR_BYTE
    MOV r9.b3, r3.b0
    CALL WAIT4USEC
XFR_3_BYTE:                 // Transfer 3 bytes
    MOV r1.b0, r8.b2
    CALL XFR_BYTE
    MOV r9.b2, r3.b0
    CALL WAIT4USEC
XFR_2_BYTE:                 // Transfer 2 bytes
    MOV r1.b0, r8.b1
    CALL XFR_BYTE
    MOV r9.b1, r3.b0
    CALL WAIT4USEC
// Transfer last byte
    MOV r1.b0, r8.b0
    CALL XFR_BYTE
    MOV r9.b0, r3.b0
// Deassert CS0 signal (high)
CLOSE_SPI0:
    LBBO r2, r6, 0x30, 4    // Load MCSPI_CH0STAT
    QBBC CLOSE_SPI0, r2, 2  // Check EOT -- wait until set
    MOV r1, 0x0             // Param to disable channel 0 of McSPI0
    SBBO r1, r6, 0x34, 4    // Write the param to MCSPI_CH0CTRL
    MOV r1, OFF_CONF
    SBBO r1, r6, 0x2C, 4    // Write into MCSPI_CH0CONF
// Turn-off McSPI0
    MOV r6, 0x44E00000      // Load CM_PER base address
    MOV r1, 0x00000000      // Bit pattern to disable SPI0 clock
    SBBO r1, r6, 0x4C, 4    // Write the pattern to CM_PER_SPI0_CLKCTRL
// Save received data
    SBCO r9, C24, 8, 4
// Save result code to indicate that the processig ended
    MOV r1, 1
    SBCO r1, C24, 1, 1
// End of processing: halt PRU
    HALT

// Single byte transfer proc
//
XFR_BYTE:
    LBBO r2, r6, 0x18, 4    // Load MCSPI_IRQSTATUS
    QBBS READY4WRITE, r2, 0 // Check for TX0_EMPTY
    QBA XFR_BYTE            // Loop until TX0_EMPTY set
READY4WRITE:
    MOV r2, 0x00000001      // Reset TX0_EMPTY
    SBBO r2, r6, 0x18, 4    // Do it
    SBBO r1, r6, 0x38, 4    // Write r1 into MCSPI_TX0
READ2:
    LBBO r2, r6, 0x18, 4    // Load MCSPI_IRQSTATUS
    QBBS READY4READ, r2, 2  // Check for RX0_FULL
    QBA READ2               // Loop until RX0_FULL set
READY4READ:
    MOV r2, 0x00000004      // Reset RX0_FULL
    SBBO r2, r6, 0x18, 4    // Do it
    LBBO r3, r6, 0x3C, 4    // Read MCSPI_RX0
    RET

// Wait for 4us
//
WAIT4USEC:
    MOV r4, 400
WAITLOOP:
    SUB r4, r4, 1
    QBNE WAITLOOP, r4, 0
    RET
$ cat Makefile 

COMPILER=~/pru_pkg/am335x_pru_package/pru_sw/utils/pasm -V3 -blz 
FILENAME=demo0

.PHONY: clean all

all:
        $(COMPILER) $(FILENAME).p


clean: 
        rm -rf $(FILENAME).bin $(FILENAME).txt $(FILENAME).lst


$ make
~/pru_pkg/am335x_pru_package/pru_sw/utils/pasm -V3 -blz  demo0.p


PRU Assembler Version 0.84
Copyright (C) 2005-2013 by Texas Instruments Inc.

Base source directory: '.'
New source file: 'demo0.p'
Output base filename: 'demo0'
DOTCMD : Scope '_ROOT_' declared
Base source directory: '.'
New source file: 'demo0.p'
demo0.p(    8) : DEFINE : 'OFF_CONF' = '0x200103d1'
demo0.p(   10) : DEFINE : 'ON_CONF' = '0x201103d1'
demo0.p(   12) : LABEL  : 'START' = 00000
demo0.p(   29) : LABEL  : 'WAIT4RESET' = 00015
    (104行省略)
Pass 2 : 0 Error(s), 0 Warning(s)

Writing Code Image of 78 word(s)

1バイトを転送する処理の概要は以下の通りだ。

  • MCSPI_IRQSTATUS レジスターを読んで TX0_EMPTY ビットがセットされている事を確認し、送信するデータを MCSPI_TX0 レジスターに書き込む
  • MCSPI_IRQSTATUS レジスターを読んで RX0_FULL ビットがセットされるまで待ち、MCSPI_RX0 レジスターから受信したデータを読み込む

TX0_EMPTY ビットがセットされていなかった場合に待つロジックが入っているのは念のためで、通常ここで待つことは無い。また次回転送のために TX0_EMPTY および RX0_FULL ステータスビットをクリアしておく必要がある。

SPI クロックは始めの方で #define している ON_CONF 定数で変えられるようにしていて、今回は ADE7753 が許容する最大値に近い 48Mhz の 1/5、9.6Mhz にしている。その代わりタイミングの制約を満たすよう1バイト転送が終わって次の転送を始める前に 4us 待ち時間を設けた。これはすべての場合で最も遅いタイミングに合わた安全サイドの設計である。

デバッグの際修正とアセンブルを繰り返すことになるので Make ファイルを準備して make を使えるようにした。

このプログラムはデバッガーで試すことができる。

$ sudo ./prudebug 
[sudo] password for debian: 
PRU Debugger v0.24
(C) Copyright 2011, 2013 by Arctica Technologies.  All rights reserved.
Written by Steven Anderson

Using UIO PRUSS device.
Processor type          AM335x
PRUSS memory address    0x4a300000
PRUSS memory length     0x00040000

         offsets below are in 32-bit word addresses (not ARM byte addresses)
         PRU            Instruction    Data         Ctrl
         0              0x0000d000     0x00000000   0x00008800
         1              0x0000e000     0x00000800   0x00009000

PRU0> l 0 demo0.bin
Binary file of size 308 bytes loaded into PRU0 instruction RAM.

PRU0> wr 0 3 0x90000 0x12345678
Write to absolute address 0x0000
PRU0> d
Absolute addr = 0x0000, offset = 0x0000, Len = 16
[0x0000] 0x00000003 0x00090000 0x12345678 0x8d1df242 
[0x0004] 0x0cb83ad0 0xcfbd98ce 0xb6144e49 0xb668d1de 
[0x0008] 0xa608328d 0xdf79be77 0x9413d0cd 0x625be6ca 
[0x000c] 0x137ccf38 0x16618a47 0x9e808104 0xb00e8a30 

PRU0> g
PRU0> d
Absolute addr = 0x0000, offset = 0x0000, Len = 16
[0x0000] 0x00000103 0x00090000 0x00ff000c 0x8d1df242 
[0x0004] 0x0cb83ad0 0xcfbd98ce 0xb6144e49 0xb668d1de 
[0x0008] 0xa608328d 0xdf79be77 0x9413d0cd 0x625be6ca 
[0x000c] 0x137ccf38 0x16618a47 0x9e808104 0xb00e8a30 

PRU0> 

プログラムをロードし動作内容を指定するデータをRAMに書き込んで実行すれば結果がRAMに残される。RAMデータの内訳は以下のとおりだ。

  • ワードアドレス 0x00 の最下位バイト: 0x03 = 転送するバイト数 (入力)
  • ワードアドレス 0x00 の2番目のバイト: 0x00 → 0x01 = PRU の処理終了フラグ (出力)
  • ワードアドレス 0x01: 0x00090000 = 送信するデータ (入力)
  • ワードアドレス 0x02: 0x12345678 → 0x00ff000c = 受信したデータ (入力)

上のリストはリセット直後のADE7753のMODEレジスターを読み込んだ例である。

もし分かりにくい点があるとしたら、PRU 上の32ビットデータの扱いはリトルエンディアンだが SPI で取り扱われるストリームはビッグエンディアンだ、と言うことではないだろうか。例えばワードアドレス 0x01 のデータはバイトアドレス順で 0x00, 0x00, 0x09, 0x00 と格納されているが、このうち先頭3バイトを 0x09, 0x00, 0x00 の順でSPIに送り出す必要がある。

この PRU のプログラムを利用して、このシリーズの第2回で紹介した SPI のテストプログラムとほとんど同じ動きをするプログラムを作ることができる。なお今回 Linux 上で動くプログラムは Python で作った。

$ cat demo0.py
#!/usr/bin/python

import ctypes, prussdrv, struct, sys, time

n = len(sys.argv)
if n<3 or n>5:
    print "Usage: %s d1 d2 [d3 [d4]]" % sys.argv[0]
    print "\td1...d4: 2 digit hex value"
    sys.exit(1)

prussdrv.init()
prussdrv.open(prussdrv.PRU_EVTOUT_0)

data_ram = ctypes.POINTER(ctypes.c_ubyte)()
prussdrv.map_prumem(prussdrv.PRUSS0_PRU0_DATARAM, ctypes.byref(data_ram) )

for i in range(4):
    data_ram[i] = 0
    data_ram[i+4] = int(sys.argv[-i-1], 16) if n > (i+1) else 0
data_ram[0] = n - 1
data_ram[1] = 0
prussdrv.exec_program(0, "demo0.bin")

while not data_ram[1]:
    time.sleep(0.1)

ram_values = struct.unpack('L'*3, str(bytearray(data_ram[0:0x0c] ) ) )
for i,d in zip([0, 4, 8], ram_values):
    print "data_ram[0x%02x:0x%02x] =" % (i+3, i),
    print "0x%08x" % d

prussdrv.pru_disable(0)
prussdrv.exit()
$ sudo python demo0.py
[sudo] password for debian: 
Usage: demo0.py d1 d2 [d3 [d4]]
        d1...d4: 2 digit hex value
$ sudo python demo0.py 9 0 0
data_ram[0x03:0x00] = 0x00000103
data_ram[0x07:0x04] = 0x00090000
data_ram[0x0b:0x08] = 0x00ff000c

 

次のステップ

今回 PRU を使っているのは ADE7753 から波形データを読み出すためだ。そのためには複数のデータをタイミングを合わせて読出し、バッファーに格納する処理を PRU のプログラムに実装する必要がある。

タイミングを合わせるのには IRQ 信号を使い、バッファーは PRU の共用 RAM を使うことにした。共用 RAM は12kB あるので、ADE7753の波形データは 24 ビットだが扱いやすいよう 32 ビットにしても 3,072 サンプルを格納できる。電力、電流、および電圧の波形データをそれぞれ 1,024 サンプルずつ一括して採取することができる勘定だ。これなら最大サンプルレート 27.9ksps で採取しても約 37ms、つまり 50Hz でも1サイクル半以上が収まるから十分と言えるだろう。

他に必要となるこまごまとした事がいくつかある。

  • 各波形データの採取は ZX (ゼロクロス) 信号に同期して開始しなければならない
  • ZX と電圧波形信号は LPF による遅れがあるので、電力と電流データの採取開始はこの分の調整が必要である
  • 速いサンプルレートに対応するため、1バイト転送が終わってから次の転送を始めるまでの待ち時間を許容される最小値に調整する必要がある
  • サブルーチンの中からさらにサブルーチンを呼べるようにする必要がある

ZX に同期する処理は ADE7753 に電圧信号が与えられていないとずっと待ちっぱなしになってしまうので、タイムアウトさせる仕組みもあった方がいい。これらを加味し、さらにここには書いていない事も盛り込んで PRU のプログラムを修正した。必要と思われる個所には全てコメントを入れておいたので参照してほしい。開発環境を日本語化していないから怪しげな英語だし、あまり親切とは言えないコメントだがご容赦願いたい。

$ cat ade7753.p
// ADE7753 spi

.macro XCALL              // Define extended call pseudo op
.mparam where             // Parameter: where to call to
    SUB r29, r29, 2         // Push stack pointer (r29)
    SBBO r30.w0, r29, 1, 2  // Save current return address
    JAL r30.w0, where       // Call
    LBBO r30.w0, r29, 1, 2  // Restore the return address
    ADD r29, r29, 2         // Pop stack pointer
.endm // XCALL

.origin 0
.entrypoint START

// MCSPI_CH0CONF param
// CLKG=1, FORCE=0, DPE0=1, WL=7, EPOL=1, CLKD=4, PHA=1
#define OFF_CONF 0x200103d1
// CLKG=1, FORCE=1, DPE0=1, WL=7, EPOL=1, CLKD=4, PHA=1
#define ON_CONF  0x201103d1

// Start address of shared RAM
#define SHRDRAM 0x00010000
// NUmber of samples, in word unit (not byte)
#define SAMPLES 1024

// *** Data RAM map (local view) ***
// 0x0000: Command from ARM
//    [2:0]==0,1,5,6 or 7: Take waveform samples
//        [7:6]==00b: take waveform samples in 27.9ksps
//        [7:6]==01b: take waveform samples in 14ksps
//        [7:6]==10b: take waveform samples in 7ksps
//        [7:6]==11b: take waveform samples in 3.5ksps
//    [3:0]==0x2,0x3 or 0x4: transfer 2-4 bytes immediately
//    [3:0]==0xa,0xb or 0xc: transfer 2-4 bytes in sync witn zero-cross
// 0x0001: Busy/done flag
//      00000000b: PRU is busy
//      00000001b: Completed normally
//      10000001b: Completed with zero-cross time-out
// 0x0002 - 0x0003: Non-WSMP IRQ count in waveform samples
// 0x0004 - 0x0007: Data to send from ARM,
//                  or delay time in number of samples for waveform
// 0x0008 - 0x000b: Data received from SPI (normal transfer)
//        "       : IRQ wait count (x15ns) (waveform samples)
// 0x000c - 0x000f: Wait count in SPI communication (x20ns)
//        - 0x1fff: Return address stack
// 0x010000 - 0x010fff (Shared RAM): Power waveform data
// 0x011000 - 0x011fff (Shared RAM): Channel 1 waveform data
// 0x012000 - 0x012fff (Shared RAM): Channel 2 waveform data

START:
    MOV r29, 0x1fff         // Set stack pointer to top of data RAM
// Enable OCP master ports.
    LBCO r1, C4, 4, 4       // Load SYSCFG reg.
    CLR  r1, r1, 4          // Clear STANDBY_INIT
    SBCO r1, C4, 4, 4       // Save new content to SYSCFG reg.
// Set C24 reg. to 0x00000000
    MOV r5, 0x00022000      // Load PRU0 CTRL base address
    MOV r1, 0
    SBBO r1, r5, 0x20, 1    // Set C24_BLK_INDEX zero
    SBCO r1, C24, 1, 1      // Clear done signature
    MOV r1, 0x80000000      // Set r31[31] as wakeup source
    SBBO r1, r5, 0x08, 4    // Save the bitmap to WAKEUP_EN

// Main loop
//
NEXT:
// Preset time-out counters to prevent false time-out error
    MOV r13, 4000000        // ZX (time-out=60ms)
// Clear debug counters
    MOV r10, 0              // SPI wait count
    MOV r11, 0              // Non-WSMP IRQ count
    MOV r15, 0              // IRQ wait count
// Reset wait counts to 400 = 4us
    MOV r20, 400            // Between b0 and b1
    MOV r21, 400            // Between b1 and b2
    MOV r22, 400            // Between b2 and b3
// Sleep until an event comes from ARM
    SLP 1                   // Sleep until an event comes from ARM
    MOV r4, 1 << 22         // ARM_PRU0_INTERRUPT event bit
    MOV r5, 0x00020280      // Setup r5 to point SECR0
    SBBO r4, r5, 0, 4       // Clear ARM_PRU0_INTERRUPT event
// Turn-on McSPI0
    MOV r6, 0x44E00000      // Load CM_PER base address
    MOV r1, 0x00000002      // Bit pattern to enable SPI0 clock
    SBBO r1, r6, 0x4C, 4    // Write to CM_PER_SPI0_CLKCTRL
// Reset McSPI0
    MOV r6, 0x48030100      // Load MCSPI0 + 0x100
    MOV r1, 0x00000002      // Soft reset
    SBBO r1, r6, 0x10, 4    // Write into MCSPI_SYSCONFIG
WAIT4RESET:                 // Wait for reset done
    LBBO r2, r6, 0x14, 4    // Read MCSPI_SYSSTATUS 
    QBBC WAIT4RESET, r2, 0  // Check RESETDONE
// Configure McSPI0
    MOV r1, 0x00000001      // Master, 4pin & single
    SBBO r1, r6, 0x28, 4    // Write into MCSPI_MODULCTRL
    MOV r1, 0x00000011      // Smart idle & autoidle
    SBBO r1, r6, 0x10, 4    // Write into MCSPI_SYSCONFIG
// Check for waveform command
    LBCO r4, C24, 0, 1      // Load command byte
    AND r4, r4, 0x07        // Take lower 3 bit
    QBEQ WF_SAMPLES, r4.b0, 0
    QBEQ WF_SAMPLES, r4.b0, 1
    QBEQ WF_SAMPLES, r4.b0, 5
    QBEQ WF_SAMPLES, r4.b0, 6
    QBEQ WF_SAMPLES, r4.b0, 7
    CALL OPEN_SPI0          // If not WF, assert CS0 and continue
// Prepare for transfer
    MOV r9, 0               // Clear RX data reg.
    LBCO r8, C24, 4, 4      // Load TX data word
    CALL SYNCIF             // ZX sync if data_ram@0x0[3]==1
    QBEQ TRANSFER3, r4.b0, 2
    QBEQ TRANSFER3, r4.b0, 3
    CALL XFR_4_BYTE
    QBA XFR_DONE
TRANSFER3:
    CALL XFR_3_BYTE
    QBA XFR_DONE
TRANSFER2:
    CALL XFR_2_BYTE
XFR_DONE:
    CALL CLOSE_SPI0         // Deassert CS0
    SBCO r9, C24, 8, 4      // Save received data
XFR_END:                    // ALL done!
// Turn-off McSPI0
    MOV r6, 0x44E00000      // Load CM_PER base address
    MOV r1, 0x00000000      // Bit pattern to disable SPI0 clock
    SBBO r1, r6, 0x4C, 4    // Write the pattern to CM_PER_SPI0_CLKCTRL
// Set the result code
    MOV r4, 0x01            // Result code for normal end
    QBNE NO_ZX_TO, r13, 0   // Check if ZX time-out?
    OR r4, r4, 0x80         // Set ZX time-out bit
NO_ZX_TO:
    SBCO r4, C24, 1, 1      // Save result code
// Save debug counters
    SBCO r10, C24, 0xc, 4   // Save SPI wait count
    SBCO r11, C24, 2, 2     // Save non-WSMP IRQ count
    QBA NEXT  // The end of mainloop -- go to sleep until next event

// Take waveform samples
//
WF_SAMPLES:
// Clear entire shared ram (debug purpose)
    MOV r12, SHRDRAM + 0x3000  // 0x3000 = 12k
    MOV r4, 0
    MOV r14, SHRDRAM
CLRLOOP:
    SBBO r4, r14, 0, 4
    ADD r14, r14, 4
    QBGT CLRLOOP, r14, r12
// Cleare done, then prepare sps parameter
    LBCO r4, C24, 0, 1      // Load command byte
    AND r7, r4, 0xc0        // Get sps value
    LSL r7, r7, 5           // Aligne bit position
// Start taking power waveform samples
    MOV r8, 0x89008C        // Code to choose power waveform samples
    OR r8, r8, r7           // Apply sps value
    MOV r14, SHRDRAM        // Start address of data area
    LBCO r16, C24, 4, 4     // Load data word as delay count
    CALL GET_SAMPLE         // Do it
// Start taking channel 1 waveform samples
    MOV r8, 0x89408C        // Code to choose channel 1 waveform samples
    OR r8, r8, r7
    MOV r14, SHRDRAM + 0x1000
    LBCO r16, C24, 4, 4     // Load data word as delay count
    CALL GET_SAMPLE
// Start taking channel 2 waveform samples
    MOV r8, 0x89608C        // Code to choose channel 2 waveform samples
    OR r8, r8, r7
    MOV r14, SHRDRAM + 0x2000
    MOV r16, 0              // Delay count = zero for ch2 (voltage)
    CALL GET_SAMPLE
// Save WF specific debug counter
    SBCO r15, C24, 8, 4     // Save IRQ wait count
// Take waveform samples done
    QBA XFR_END             // Goto end-of-mainloop

// Unit transfer proc for reg read/write
//
XFR_4_BYTE:                 // Transfer 4 bytes
    MOV r1.b0, r8.b3
    XCALL XFR_BYTE
    MOV r9.b3, r3.b0
    MOV r4, r22
    XCALL WAIT10XR4NS
XFR_3_BYTE:                 // Transfer 3 bytes
    MOV r1.b0, r8.b2
    XCALL XFR_BYTE
    MOV r9.b2, r3.b0
    MOV r4, r21
    XCALL WAIT10XR4NS
XFR_2_BYTE:                 // Transfer 2 bytes
    MOV r1.b0, r8.b1
    XCALL XFR_BYTE
    MOV r9.b1, r3.b0
    MOV r4, r20
    XCALL WAIT10XR4NS
// Transfer the last byte
    MOV r1.b0, r8.b0
    XCALL XFR_BYTE
    MOV r9.b0, r3.b0
    RET

// Proc to get waveform samples from a channel
//
GET_SAMPLE:
    XCALL WF_WR_3          // Send channel selection
    MOV r8, 0x8A0048       // Enable sampling
    XCALL WF_WR_3
    MOV r12, SAMPLES << 2  // Get number of bytes to store
    ADD r12, r12, r14      // Get the end address of data area
    XCALL ZXSYNC           // Sync with zero-cross
WAIT4WSMP:
    QBBC GOTIRQ, r31, 14    // Wait for IRQ signal
    ADD r15, r15, 1         // Wait count
    QBA WAIT4WSMP
GOTIRQ:
    MOV r8, 0x0C0000        // Read RSTATUS reg
    XCALL WF_RD_3
    QBBS WSMPOK, r9, 3      // Got WSMP IRQ, let's go on
    ADD r11, r11, 1         // Non-WSMP IRQ count
    QBA WAIT4WSMP           // Ignore non-WSMP IRQ
WSMPOK:
    MOV r8, 0x01000000      // Read WAVEFORM reg
    XCALL WF_RD_4
    QBEQ SAVEWSMP, r16, 0   // Check if not to skip
    SUB r16, r16, 1         // 1 sample skipped
    QBA WAIT4WSMP           // and try again
SAVEWSMP:
    QBBC WSMP_POSITIVE, r9, 23 // Check sign bit
    MOV r9.b3, 0xff         // Negative value
    QBA WSMP_SIGDONE
WSMP_POSITIVE:
    MOV r9.b3, 0            // Positive value
WSMP_SIGDONE:
    SBBO r9, r14, 0, 4
    ADD r14, r14, 4
    QBGT WAIT4WSMP, r14, r12  // Loop until the end
    RET

// Unit transfer proc for waveform samples
//
WF_RD_4:                    // Transfer 4 bytes (read)
// Change wait count
    MOV r22, 50             // 500ns between b2 and b3
    MOV r21, 0              // 0ns between b1 and b2
    MOV r20, 0              // 0ns between b0 and b1
    XCALL OPEN_SPI0
    XCALL XFR_4_BYTE
    XCALL CLOSE_SPI0
    RET
WF_WR_3:                    // Transfer 3 bytes (write)
// Change wait count
    MOV r21, 400            // 4us between b1 and b2
    MOV r20, 400            // 4us between b0 and b1
    QBA WF_3_BYTE
WF_RD_3:                    // Transfer 3 bytes (read)
// Change wait count
    MOV r21, 400            // 4us between b1 and b2
    MOV r20, 0              // 0ns between b0 and b1
WF_3_BYTE:
    XCALL OPEN_SPI0
    XCALL XFR_3_BYTE
    XCALL CLOSE_SPI0
    RET

// Single byte transfer proc
//
XFR_BYTE:
    LBBO r2, r6, 0x18, 4    // Load MCSPI_IRQSTATUS
    QBBS READY4WRITE, r2, 0 // Check for TX0_EMPTY
    ADD r10, r10, 1         // Wait count
    QBA XFR_BYTE            // Loop until TX0_EMPTY set
READY4WRITE:
    MOV r2, 0x00000001      // Reset TX0_EMPTY
    SBBO r2, r6, 0x18, 4    // Do it
    SBBO r1, r6, 0x38, 4    // Write r1 into MCSPI_TX0
READ2:
    LBBO r2, r6, 0x18, 4    // Load MCSPI_IRQSTATUS
    QBBS READY4READ, r2, 2  // Check for RX0_FULL
    QBA READ2               // Loop until RX0_FULL set
READY4READ:
    MOV r2, 0x00000004      // Reset RX0_FULL
    SBBO r2, r6, 0x18, 4    // Do it
    LBBO r3, r6, 0x3C, 4    // Read MCSPI_RX0
    RET

// Wait timer
//
WAIT10XR4NS:                // Wait for (10 x r4)ns
    QBNE WAITLOOP, r4, 0    // Do wait if r4 != 0
    RET                     // Do nothing if r4 == 0
WAITLOOP:
    SUB r4, r4, 1
    QBNE WAITLOOP, r4, 0
    RET

// Open & Close McSPI0 (assert & deassert CS0)
//
OPEN_SPI0:
// Assert CS0 signal (make it low)
    MOV r1, ON_CONF         // SPI configuration word
    SBBO r1, r6, 0x2C, 4    // Write r1 into MCSPI_CH0CONF
    MOV r1, 0x00000001      // Param to enable McSPI0 channel 0
    SBBO r1, r6, 0x34, 4    // Write the param to MCSPI_CH0CTRL
    RET
CLOSE_SPI0:
// Deassert CS0 signal (make it high)
    LBBO r2, r6, 0x30, 4    // Load MCSPI_CH0STAT
    QBBS EOT_OK, r2, 2      // Check EOT
    QBA CLOSE_SPI0          // Loop until EOT set
EOT_OK:
    MOV r1, 0x0             // Param to disable channel 0 of McSPI0
    SBBO r1, r6, 0x34, 4    // Write the param to MCSPI_CH0CTRL
    MOV r1, OFF_CONF
    SBBO r1, r6, 0x2C, 4    // Write into MCSPI_CH0CONF
    RET

// Sync with rising edge of zero-cross signal (ZX)
//
SYNCIF:  // conditional
    LBCO r4, C24, 0, 1      // Load command byte
    QBBS SYNC, r4, 3        // Do sync if bit 3 is set
    RET
ZXSYNC:  // always
    QBNE DO_SYNC, r13, 0    // Do sync if not timed-out previously
    RET
DO_SYNC:
    MOV r13, 4000000        // Reset tmieout -- 60ms / 15ns = 4e6
SYNC:
    QBBC SYNC_LO, r31, 15   // Check if ZX signal is lo
    SUB r13, r13, 1         // Check time-out
    QBLT SYNC, r13, 0
SYNC_LO:
    QBBS SYNC_HI, r31, 15   // Check if ZX signal is hi
    QBEQ SYNC_HI, r13, 0    // Check time-out
    SUB r13, r13, 1
    QBA SYNC_LO
SYNC_HI:                    // Sync done if r13 != 0 else time-out
    RET
debian@arm:~/spi/pru/rel_cand_1$ make
~/pru_pkg/am335x_pru_package/pru_sw/utils/pasm -V3 -blz  ade7753.p


PRU Assembler Version 0.84
Copyright (C) 2005-2013 by Texas Instruments Inc.

Base source directory: '.'
New source file: 'ade7753.p'
Output base filename: 'ade7753'
DOTCMD : Scope '_ROOT_' declared
    (中略)

Writing Code Image of 291 word(s)

デバッガーを使ってこのプログラムを試すことはできるが、波形データがちゃんととれているかどうかまで調べるのは無理である。インターフェイス用の Python  モジュールを準備した。なお今回準備したモジュールは 50Hz 専用である。60Hz 対応するには get_wf メソッドを修正する必要がある。

$ cat pru_spi.py
#!/usr/bin/python

import ctypes, prussdrv, time, struct

class pru_spi(object):
    def __init__(self, binpath="ade7753.bin", verbose=False, ts=False):
        self.ZX_TO_ERROR = IOError("Zero-cross timeout.")
        self.PRU_NOT_RUNNING = IOError("PRU is not running (stopped already.)")
        self.NO_SUCH_KSPS = ValueError("No such ksps (3.5|7|14|27.9).")
        self.NO_WF_DATA = Exception("No waveform data available.")
        self.ksps_dict = {3.5:0xc0, 7:0x80, 14:0x40, 27.9:0x00}
        self.verbose = verbose
        self.ts = ts
        self.ts0 = time.time()
        self.last_num = 0
        self.last_cmd = 0
        self.last_ret = 0
        self.last_val = 0
        self.tot = [0] * 3 * 1024
        self.results = [0] * 4
        self.wf_done = False
        prussdrv.init()
        prussdrv.open(prussdrv.PRU_EVTOUT_0)
        prussdrv.pruintc_init(prussdrv.constants.getPRUSS_INTC_INITDATA() )
        self.data_ram = ctypes.POINTER(ctypes.c_ubyte)()
        self.shrd_ram = ctypes.POINTER(ctypes.c_ubyte)()
        prussdrv.map_prumem(prussdrv.PRUSS0_PRU0_DATARAM,
                            ctypes.byref(self.data_ram) )
        prussdrv.map_prumem(prussdrv.PRUSS0_SHARED_DATARAM,
                            ctypes.byref(self.shrd_ram) )
        prussdrv.exec_program(0, binpath)
        self.pru_ok = True
        
    def xfer(self, num, cmd):
        self.last_num = num
        self.last_cmd = cmd
        if self.pru_ok:
            self.data_ram[0] = num
            cmdarray = bytearray(struct.pack('L', cmd) )
            for i in range(4):
                self.data_ram[i+4] = cmdarray[i]

            # Send host to PRU event
            prussdrv.pru_send_event(22) # prussdrv.ARM_PRU0_INTERRUPT = 21?
            r = self.data_ram[1]
            while not r:
                time.sleep(.01)         # sleep 10ms
                r = self.data_ram[1]    # try again
            self.last_ret = r

            self.results = struct.unpack('L'*4,
                                         str(bytearray(self.data_ram[0:16] ) ) )
            self.data_ram[1] = 0
            n = num&0x07 if (num&0x07) > 0 and (num&0x07) <= 4 else 4
            mask = 0x0000ff if n==2 else 0x00ffff if n==3 else 0xffffff
            self.last_val = self.results[2] & mask
            if self.verbose:
                self.dump()
            if r & 0x80:
                raise self.ZX_TO_ERROR
            else:
                return r, self.last_val
        else:
            raise self.PRU_NOT_RUNNING

    def get_wf(self, ksps=14):
        if not self.ksps_dict.has_key(ksps):
            raise self.NO_SUCH_KSPS
        elif not self.pru_ok:
            raise self.PRU_NOT_RUNNING
        else:
            self.xfer(self.ksps_dict[ksps],
                      int(round(float(ksps)*20*(1.-19.7/360) ) ) )
            self.wf_done = True
            self.tot = struct.unpack(
                'i' * 3 * 1024, str(bytearray(self.shrd_ram[0:4*3*1024] ) ) )
            return self.wf_data()

    def wf_data(self):
        if not self.wf_done:
            raise self.NO_WF_DATA
        else:
            p = self.tot[0:1024]
            c = self.tot[1024:2048]
            v = self.tot[2048:3072]
            return p, c, v

    def dump(self):
        if self.ts:
            print "PRU_SPI dump (@time=%.3f):" % (time.time() - self.ts0)
        else:
            print "PRU_SPI dump:"
        for i in range(4):
            print "\tData_RAM[0x%02x-0x%02x] = 0x%08x" % (4*i+3,
                                                          4*i,
                                                          self.results[i] )
    def stop(self):
        if self.pru_ok:
            if self.verbose:
                if self.ts:
                    print "Stopping PRU @time=%.3f" % (time.time() - self.ts0)
                else:
                    print "Stopping PRU..."
            prussdrv.pru_reset(0)
            prussdrv.pru_disable(0)
            prussdrv.exit()
            self.pru_ok = False

if __name__ == "__main__":
    import os, sys

    n = len(sys.argv)
    if n<3 or n>5:
        print "Usage: %s d1 d2 [d3 [d4]]" % sys.argv[0]
        print "\td1...d4: 2 digit hex value"
        sys.exit(1)

    binpath = os.path.join(sys.path[0], "ade7753.bin")
    pru = pru_spi(binpath)
    try:
        pru.verbose = True
        pru.ts = True

        d = 0
        for a in sys.argv[1:]:
            d = int(a, 16) + (d<<8)

        pru.xfer(n-1, d)
    except:
        raise
    finally:
        pru.stop()
$ sudo python pru_spi.py 9 0 0
PRU_SPI dump (@time=0.013):
        Data_RAM[0x03-0x00] = 0x00000103
        Data_RAM[0x07-0x04] = 0x00090000
        Data_RAM[0x0b-0x08] = 0x00ff000c
        Data_RAM[0x0f-0x0c] = 0x00000000
Stopping PRU @time=0.017

モジュールをプログラムとして実行すると最初の方で紹介した Python のプログラムとほぼ同じ動きをするようにしておいた。これは簡単な動作確認用だ。波形データを目視チェックするにはプロットしてみるのが一番である。これは Python で対話的に行うことができる。

$ sudo python
Python 2.7.3 (default, Mar 14 2014, 17:55:54) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pru_spi
>>> import matplotlib.pyplot as pl
>>> import numpy as np
>>> 
>>> pru = pru_spi.pru_spi(verbose=True)
>>> ksps = 27.9
>>> t = np.arange(1024) / ksps
>>> t20 = int(20 * ksps)
>>> p,a,v = [np.array(i) for i in pru.get_wf(ksps)]
PRU_SPI dump:
        Data_RAM[0x03-0x00] = 0x00000100
        Data_RAM[0x07-0x04] = 0x0000020f
        Data_RAM[0x0b-0x08] = 0x0048e18e
        Data_RAM[0x0f-0x0c] = 0x00000000
>>> 
>>> print p[:t20].mean()
78178.0681004
>>> print a[:t20].std()
311652.471269
>>> print v[:t20].std()
3878.05186451
>>> 
>>> ax1 = pl.subplot(111)
>>> ax2 = pl.twinx()
>>> ax1.plot(t,a,'r',label="Amp")
[<matplotlib.lines.Line2D object at 0x11488f0>]
>>> ax2.plot(t,p,'g',label="Pow")
[<matplotlib.lines.Line2D object at 0x1166f10>]
>>> ax2.plot(t,v,'b',label="Vol")
[<matplotlib.lines.Line2D object at 0x1166e70>]
>>> ax1.legend(loc="upper left")
<matplotlib.legend.Legend object at 0x1166550>
>>> ax2.legend(loc="upper right")
<matplotlib.legend.Legend object at 0x1153d10>
>>> ax1.grid()
>>> pl.show()

もちろんファイルに書いてスクリプトとして実行するのも可能だ。多分その方が作業は楽である。上の実行例は 300W のヘアードライヤーを負荷にしている。この時のプロットは以下の通りだ。

20140829_300w

値は ADE7753 内部表現のままなので少し分かりにくいかもしれないが、一応それらしくプロットされていて動作にこれと言った異常は無さそうである。

電力の平均値および電流と電圧の標準偏差を表示させているが、これらはそれぞれ有効電力と rms 値に相当するものである。これらにこのシリーズ第3回目で求めた係数を (電圧については第5回目の修正も) 適用すると、

  • 電力平均値 = 78180 x 9.460e-06 x (4.844e-5 / 0.001953) x 1.626e04 = 298.3
  • 電流 rms 値 = 311700 x 1.892e-7 ÷ 0.02 = 2.949
  • 電圧 rms 値 = 3878 x 1.062 x 4.844e-05 x 6.1 x 100/1.211 = 100.5

電流値に関してアナログ回路の誤差を無視しているが、かなりそれらしい値が得られた。正確な値を得るには電流の係数を校正する必要がある。それを別にすれば正常に動作していると見て良いだろう。

 

今後の展開

BBB の Linux 上のプログラムから ADE7753 の全ての機能が使えるようになったので、かなり高機能な「ワットチェッカー的なもの」を容易に実現する手段が整ったことになる。Web サーバーを動かしてアプリを組むのが最もありがちなパターンではないかと思う。しかしこの方向に進めるのには若干の躊躇があるのも事実だ。

「ワットチェッカー的なもの」を自作しようとした理由は比較的長期間の消費電力推移を記録したかったからである。多分常時動かしておくことになる。そう考えると BBB は少し消費電力が多過ぎる。商用電源の消費電力で考えるので AC アダプターの効率が影響するが、大体 3W 位消費するはずである。サーバーと考えれば十分小さな値だが、常時動かしておくなら 1W を切るのが望ましいと思っている。

今あるアイデアは ADE7753 と PIC32MX を組み合わせてラトックシステムの Bluetooth ワットチェッカーと同じようなことができるのではないか、と言うことである。

この製品の仕様によれば消費電力は 0.3W だ。ここまで小さくするには電源回路をかなり工夫する必要がある。以前電圧信号の取り出しに使っていた電源トランスを使おうかと思っていたのだが、これだとトランスだけで 0.6W 消費してしまう可能性があるのでアウトだ。

今後 BBB よりも小規模な実装を試そうと思っているが、少し時間がかかりそうだ。なのでこのシリーズは一旦終了して、何か成果が出たらその時にまた報告するつもりである。実際のところ BBB を使うのが楽なので、結局その方向に落ち着く可能性が結構高いのかもしれない。

 

今回のまとめ

今までに検討した方式の比較をまとめておく。

方式 PC オーディオ
利点
  • PC を除けばハードウエア規模最少
  • 容易に高機能・高性能を実現できる
  • 短い時間スケールの解析が可能 (電流・電圧両方)
  • 比較的長時間の波形データを一旦記録してオフライン解析が容易
  • 課題
  • 消費電力大 (少なくとも 15W 程度)
  • 装置サイズ大
  • 信号レベルの調整とそれに応じた校正が必要 (自動化可能?)
  • 主な用途・目的
  • 一時な (常設でない) 数時間程度の消費電力データ記録
  • 短い時間スケールの現象の解析
  • 発生頻度の低い現象の解析
  •  
    方式 ADE7753 + BBB
    利点
  • 装置サイズ小
  • 消費電力が比較的小さい (3W 程度)
  • 比較的容易に高機能・高性能を実現できる
  • 短い時間スケールの解析が可能 (電流のみ)
  • 課題
  • BBB の価格と入手性
  • PRU を使った開発スキル
  • 主な用途・目的
  • 一時的な (常設でない) 数日間程度の消費電力データ記録
  • 常設の高機能電力計測サーバー
  •  
    方式 ADE7753 + 小規模マイクロコントローラー (PIC32MX など)
    利点
  • 装置サイズ小
  • 消費電力最少 (1W 未満)
  • 課題
  • 開発スキル
  • 専用の開発環境 (プログラマー、In-Circuit Debugger など)
  • 既製品との競合
  • 主な用途・目的
  • 自作することによる技術的な満足感
  • 既製品に無い機能の実現
  • 常設の継続的な消費電力記録
  • クランプメーターによる測定値の正確さ

    $
    0
    0

    ワットチェッカー導入前はクランプメーターで測定した消費電流から消費電力を推定していた。使っていたクランプメーターは安価な製品で真の rms を測っていないことは分かっていたが、それがどんな差異を与えているか推測するしかなかった。

    今回はワットチェッカーと比較してみた。また電流波形を得るために自作中の「ワットチェッカー的なもの」による測定も併用した。

    /*-----------  -----------*/

    とりあえず比べてみる

    真の rms 値を測っていないことの影響が大きいのは電流波形に歪がある場合だ。最近の家電製品で電流波形に歪が無く位相の遅れ進みで力率が大幅に小さくなっているようなものは稀で、波形歪による影響の場合が多い。波形歪のある電気器具の代表として、今回は定格消費電力 10W の LED 電球、およびノート PC に AC アダプターで給電する場合を選んだ。

    Snap

    計測方法項目LED 電球ノート PC単位
    クランプメーター電流0.0970.332A (rms?)
    ワットチェッカー電流0.150.54Arms
    電圧103.0102.8Vrms
    皮相電力1555VA
    有効電力1035W
    力率0.670.64-

     予想していたことだがクランプメーターは真の rms よりもかなり小さな値を示している。しかも有効電力を電圧で割った値、すなわち力率が 1.0 だったとした時の電流値に近くなっている。これが元で以前の記事にトンチンカンなことをずいぶん書いたような気がする。

     

    クランプメーターの測定方式

    クランプメーターは電流を電圧に変換した後、絶対値の平均にある係数を掛けた値を表示しているはずだ。この「ある係数」は正弦波を測った時に rms 値表示になるものである。

    正弦波の場合、平均値と rms はそれぞれ以下のとおりなので、

    ave = (1/π)∫0π sin(θ) dθ = 2/π
    rms = [(1/π)∫0π sin2(θ) dθ]1/2 = (1/2)1/2

    「ある係数」は、

    (1/2)1/2 / (2/π) = π / 81/2≈ 1.11

    である。

     

    実際の電流波形

    PC オーディオを利用した「ワットチェッカー的なもの」を使って波形サンプルをプロットしてみた。なお電流の値は大まかに合わせた係数を使って計算しているので、相対的な大小関係は正しいが絶対的な値はあまり正確ではない。

    Led

    Pc

    電流の rms 値と平均値を波形から計算して表示しておいた。平均値からクランプメーターが表示するはずの電流値を計算すると LED 電球は 0.100、ノート PC では 0.324 で、rms 値との関係が最初に示した表とほとんど同じになっている。

    電流波形を見て気付くのはどちらも同じような三角形になっていることだ。これは商用電源を直接ダイオード・ブリッジで整流・平滑している電源回路に特徴的なものである。

    Rectifier

    これは LED 電球を模したシミュレーション・モデルで、これを実行すると実測と良く似た電流波形が得られる。

    Rectifier_graph

    最初の半サイクルは手動で設定している初期値の影響を受けるのでシミュレーション結果を正しく反映していない。この点、注意が必要である。シミュレーション結果の2サイクル目のデータから電流値などを計算してまとめると以下の通りになる。

    電流 (rms)0.159Arms
    電流 (平均)0.079A
    電圧100.0Vrms
    皮相電力15.9VA
    有効電力9.7W
    力率0.61-

    実際の回路より力率が小さくなっているが、平滑コンデンサーの ESR など損失要素を省いたのが原因ではないかと思う。また rms 値と平均値の違いが大きくなっているのも同じ原因が考えられる。このことを除けば、このモデルは実際の回路の状況を良く表していると言えそうだ。

     

    平均値方式の電流測定値に関する考慮点

    波形歪のある電流を平均値方式のクランプメーターで測ると通常マイナスの誤差が出る。またこの場合力率が 1 よりも小さいから有効電力を電圧で割った値が平均値方式クランプメーターの読み取り値に近づく傾向になる。ただし「近づく」だけで特定の相関関係がある訳ではないので、残念ながら何の役にも立たない。

    平均値方式の電流測定値にプラス誤差が出る場合が無いわけではない。電流波形が矩形波に近い場合だ。完全に矩形波ならピーク値、平均値、そして rms 値全てが同じになる。しかし平均値方式では正弦波の rms 値に合わせる係数の影響でプラス 11% の誤差が出る。ただし実際に電流波形が矩形波に近くなることはあまり考えられない。ほとんどあり得ないのではないかと思う。

    電流波形が似ているもの同士なら、クランプメーターの読み取り値で相対的な消費電力の大小をある程度判断できる。これは正しい。しかし「電流波形が似ているもの同士」だと推定するのは簡単ではない。

    Led_sharp

    これは 4年以上前の記事でフリッカーがあることを指摘したシャープ製 LED 電球の電流波形である。平滑用コンデンサーが足りないのだろう位に思っていたのだが、これを見るとそんな単純なことではない様だ。同じ LED 電球同士なので電流波形も似ているだろうと思ったら大間違い、の例である。この製品、力率は 0.84 と優秀だ。

     

    今回のまとめ

    平均値方式のクランプメーターで消費電力を調べようとするのはかなり無理がある。電流と電圧波形の位相差まで考えると真の rms が測れても十分ではない。しかし回路を切らずに電流を測れるのは便利だ。消費電流、あるいは消費電力を調べたいが使えるのが唯一クランプメーターと言う場合も少なくない。制約事項を理解して活用する、これに尽きるのではないだろうか。

    Beaglebone Black Rev. C 調達

    $
    0
    0

    ちょっとした手違いで1年弱使ってきた BBB (BeagleBone Black) にダメージを与えてしまい、GPIOの一つで本来 3.3V の H レベルが 2.9V にしかならなくなってしまった。調べられる範囲ではそれ以外の不具合は無く、そのピンを使わないようにすれば問題なく使える。しかしダメージが拡大する可能性もあるから、と、それを口実に Rev. C を調達することにした。

    /*-----------  -----------*/

    Adafruit の配送オプション

    色々と面白そうなものを取り揃えていて以前から気になっていた Adafruitを調達先に決めた。ここはチェックアウトに進まないと送料が分からない。今回は UPS Worldwide Expedited が第一候補として提示された。送料約 $23 で 2~5営業日で届くサービスだ。しかし第二候補に提示された UPS Worldwide Saver は送料 $24.11 で 1~3営業日。$1 程度の追加で済むなら早く届く方がいいと思い、こちらを選んだ。

    送料込みで $79.11。為替レートが 110\/$ なら約 \8,700 である。決して安くは無いが能書き通り 3営業日で届いたからあまり不満は無い。.

    Tracking

    この後、10月9日の昼前に届いた。国内はヤマトが代理店になっているのだが、配送状況の共有がうまくいっていないようで「配達車両に積載済み」が表示されるよりも先に品物が届いてしまった。まぁ品物が遅れるよりはいい。

     

    BBB Rev. C

    USB ケーブルと名刺大に二つ折りされた簡単な資料が同梱されていた。これは以前入手した Rev. A5C と同じである。

    Revc_contents

    最大の変更点は eMMC のサイズが 2GB から 4GB になり、Debian がプリインストールされるようになったことだが、外観からはほとんど見分けがつかない。

    Bbb_component_side

    左側が Rev.  C で、RJ-45 ジャックの右下にある U-13 が eMMC だ。見分けがつかないのは裏面も同じである。

    Bbb_soldering_side

    USB ケーブルで PC につないで操作する際の状況も多分全く同じだが、ディスプレイ、キーボード、およびマウスをつないで起動するとさすがに Debian、一目瞭然である。

    Bbb_preinstall_debian

    GUI は LXDE だ。Preferences メニューの先頭に Calibrate Touchscreen があるのが目を引く。対応するデバイスが無いので確かめられないが、タッチスクリーンをサポートしているらしい。なお以前の Ångström では画面が出なかった 1920x1200 解像度のモニターでも OK になった。

    SoC が XAM3559 から 3558 に変わったのがもう一つの大きな変更点だ。これにより PRU-ICSS から EtherCAT モジュールが無くなった。ただしこのことは大多数の BBB ユーザーには影響無いはずだ。

    Rev. A5C で使っていた microSD による起動も試したが全く問題なかった。大きくなった eMMC を使わない限り違いを実感できる場面はあまりないかもしれない。

     

    今回のまとめ

    BBB Rev. C は国内販売店からも供給されているようだが、流通量はかなり限られていてほとんどが売切れ・入荷待ちの状態らしい。早く入手したい場合、海外通販を利用するのが確実である。「あるところにはある」と言うことだ。しかもかなり潤沢に。しかし送料の分割高になってしまうのが難点だ。

    確かめていないが Adafruit の場合、送料が数量に比例するとは思えないので友達と一緒にまとめ買いするのが良いかもしれない。ただし合計商品代金が一定水準を超えると消費税がかかるが、最大でも BBB 1台当たり \500 程度だ。送料が割安になる効果の方が大きいだろう。また Digikey 日本語サイトの円表示価格で買うと購入金額が \7,500 以上なら送料無料だ。BBB 単体ではその金額にならないので他のパーツなどを併せて購入する必要があるが、不必要なものを買ってしまわないよう注意が必要だろう。これは私の日頃の経験からの教訓である。また Digikey 日本語サイトの円表示価格は英語サイトの米ドル表示価格を通貨換算したよりも10% 程度割高になっている。送料無料にするための仕組みだと思うが、たくさん買うとドル表示価格で決済して送料を払うよりも高くなるかもしれない。

    docomo L-07C の時限爆弾 (空き容量消滅!)

    $
    0
    0

    L-07C は 2011年夏モデルのスマートフォンだ。1年ほど前に中古を入手して使っていたのだが、半年くらい前から空き容量低下のメッセージが表示されるようになった。

    Low_capa_warning

    使用頻度の低いアプリをアンインストールしたりしてしのいできたのだが、ニッチもサッチも行かなくなったので詳しく調べてみた。なお記事の内容は root 化した V10d-20111221 ファームウエアに関するものである。

    /*-----------  -----------*/

    空き容量低下すると・・・

    新たにアプリをインストールできなくなる。

    Low_capa_install_error

    それだけなら我慢すれば済むのかもしれないが、プリインストール分を含むインストール済のアプリに対するアップデートもインストールできなくなるので始末が悪い。

    「空き容量低下」のメッセージをタップすると「アプリケーションの管理」の画面に飛ばされる。

    Low_capa_app_list

    これは「余計なアプリをインストールしてますよね」と言われているようなものだ。あまり使わないアプリをアンインストールしたり、可能なら SD カードに移動したりしてしのいできたが、こう言った対応は限界になってしまった。

    ちなみにこの画面に表示される未使用が 150MB を切ると「空き領域低下」状態になるようである。

    プリインストール・アプリを削除したら? との思いが頭をよぎったが、

    Mount_mod

    入っているフラッシュメモリーの区画が異なるので、削除したうえで区画を切りなおさないと効果が無いはずだ。これは大事だし一つ間違えば文鎮化のリスクもあるので、そこまでやる気にはならない。

     

    本当の原因と対策

    ここまで来るとさすがに気付いた。アンインストールや SD カードへの移動を繰り返しているのに空き容量が低下するのだからアプリが原因ではない可能性がある。誰かせっせと /data ディレクトリの下に空き容量を埋めるデータを作っている子が居るらしい。

    du コマンドが使えないのが痛い(注参照)。使えるなら du -h -d 1 を何回か繰り返せば済むのだが、意を決して /data ディレクトリとその下のサブディレクトリを虱潰し ls -l することにした。と言ってもそんなにたいした数ではない。ほどなく /data/logger ディレクトリに動かぬ証拠が見つかった。

    Huge_kernel_log

    ログ置き場らしい。4MB 毎にローテートされているようだが、kernel.log はそうなっていないらしく飛び抜けて大きい。約 75MB ?、いや 1文字右にずれているから 約 750MB! コイツが空き容量を喰っていたのだ。

    検索したら blog 記事「/data/logger/kernel.log が肥大化する (その2) (その3) (その4)」が見つかった。巨大化した kernel.log はさっくり削除しても大丈夫らしい。また標準の電話アプリで「3845#*07#」をダイヤルしてHidden Menu を呼び出し、下の方にある Log Service から入って Disabled にしてやればログを吐かなくなるらしい。

    Log_service_at_hidden

    これで新たなログは作られないはずだ。しかし気付かずに Enabled になってしまっても大丈夫なよう、誰がデータを作っていたのかもう少し調べてみた。 Android のベースの Linux を初期化している /init.rc の下の方にログサービスの定義らしきものがある。

    Kernel_log_at_init_rc

    /etc/save_kernel_log.sh がサービスの実体らしい。ちなみに kernel log 以外は logcat を使って 4MB 毎にローテートし、過去ログを 4 世代保存するようになっている。

    Events_log_at_init_rc

    上のスクリーンショットは event log に関するものだが他も同様である。これは /data/logger ディレクトリの状況と符合する。

    /etc/save_kernel_log.sh の中身は予想通りだ。

    Save_kernel_log_sh

    コメントアウトしてある 1 行目が元々の内容で、これだとファームウエアをインストール以来のカーネルメッセージが延々と残る事になる。実際にその通りになったわけだ。

    2 行目以降は私が追加した内容だ。真ん中のブロックは他のログに合わせて過去ログ 4 世代保存するようにローテートさせるロジックである。最後の行と組み合わせて使う。ただしローテートはファイルの大きさ基準ではなく再起動の都度になる。つまり合計で再起動 5 回分ログが残る。

    これまでの実績を考えると 1 日あたり約 2MB ログが出ていたはずである。月一再起動を仮定すると 2 x 30 x 5 = 300MB ログが残る事になる。 Hidden Menu で Enabled になっているか、あるいは Disabled にしていてもログが止まらなかった場合の話である。これでは多過ぎると思うなら真ん中のブロックはコメントアウトしておいて、必要な時に編集して復活させればいいだろう。ただしその設定で再起動すると、再起動以前のログは無くなる。過去ログを 1 世代残す設定が妥当かもしれない。

    最後の行はカーネルメッセージを現在のログに記録する設定である。

    Hidden Menu の設定に関係なく全くログを吐かないようにするには元の内容をコメントアウトするだけでいい。必要な時に save_kernel_log.sh を編集する前提ならこれでいいはずだ。

    実際に何回か再起動して確認したところ Hidden Menu の設定が Disabled でもログは完全には止まっていないのではないかと考えられる現象が見られた。ログはローテートされるので実用上あまり問題無いが、正確な状況と原因は良く分からない。どうなっているのだろう?

     

    注: du コマンドについて

    記事を書き終わる頃になって「busybox が使えたのでは?」と思い出した。間抜けな話だ。

    Du_at_busybox

    これなら一目瞭然。数字は kernel.log をスリム化した後のものである。この状態でも使用済 /data 区画はアプリとログがほとんどを占めている事が分かる。

    分類使用量 [MB]該当サブディレクトリ
    アプリ306.5app, dalvik-cache, data
    ログ70.5logger
    その他3.0上記以外

     

    root 化しなくても可能な対処

    これまで書いてきたことは root 化したファームウエアでないとできない。しかし大多数のユーザーは root 化なんて考えたことすらないはずだ。そんな非 root 化環境で kernel.log が成長してしまったらどうしたらいいのだろう。ファームウエアの再インストールしか手段が無い、と言うのは悲し過ぎるなぁ、と考えていると、kernel.log ファイルのパーミッション、と言うかファイルモードが -wr-wr-wr- (666) になっていることに気付いた。そう、誰でも書き込めるのである。

    Nonroot_measures

    これで良いはずだ。 kernel.log ファイルを上書きした後にカーネル・メッセージが出てログに出力されるとおかしなことになる可能性があるので reboot しておくのが無難である。

    以上は L-07C 専用の手順である。他の機種で同じような問題が起こっている場合、ログのパスが分かれば同様に対処できる可能性がある。

    他のログが -wr------- root:root なのに kernel.log だけこうなっているのは手動で巨大化したログに対処することが必要になると予め想定していたからかもしれない。そう考えると、他の機種でも同じような事が起こるなら、ドコモは全ての該当機種についてログのパスを把握して対処方法を予め準備していてもおかしくない。 USB デバッグを活かして USB ケーブルを繋ぎ何かスクリプトを実行する。この程度ならドコモショップの窓口でも実施可能だろう。そうそう、忘れずに USB デバッグの設定を元に戻すこと。そして Hidden Menu で Log Service を Disabled にするのも必要である(もしかするとスクリプトで実施可能なのかもしれない)。これは私にドコモのユーザーサポートに関する決定権があればそうしたかもしれない、と言う話であって、実際にどうなっているか全く不明である。もちろん最初から kernel.log をローテートする仕組みがあればこんなことは要らないし、その方が安上がりのはずだが、現実はそうなっていない。

     

    今回のまとめ

    少し古い Android スマートフォンに関して「空き容量が不足して・・・」と言う話をインターネット上でいくつか見かけた気がする。私は L-07C しか使ったことが無いので他の機種の事は分からないが、もし同じような事が原因なら実にバカバカしい話だ。

    原因が分かってしまえば対処は簡単である。しかし root 化していないデバイスでユーザーが原因を突き止めるのは無理だろう。「このスマートフォンはストレージが小さ過ぎるから買い換えよう」と言うことになっている場合が多いような気がする。それが狙いだったらヒドイ話だ。

    kernel.log スリム化後、今まで SD カードに移動したものを全て元に戻し、アンインストールしたアップデートの全てとアプリの一部を再インストールしても 890MB の空き容量が確保できた。

    Capa_ok_app_list

    空き容量低下メッセージが出るまで 700MB以上余裕がある。これなら常時 kernel.log を取得し、過去ログを 4 世代残すよう修正した save_kernel_log.sh で 300MB 使うことにしても大丈夫だ。 Log Service を全て Disabled にした上で /data/logger ディレクトリーを空にすれば、更に空き容量を 70MB 程度増やせるが、特に必要を感じないので未実施である。

    Beaglebone Black をバッテリー駆動

    $
    0
    0

    この記事を真似て BBB をバッテリー駆動してみた。

    /*-----------  -----------*/

    コネクターの取り付けは要注意

    取り付けるコネクターは 2mm ピッチだが BBB の基盤上のパターンは 2.54mm ピッチである。元ネタの記事は基盤のピッチに合うようコネクターの足を広げるか曲げるかする必要があると書いているが、この程度の違いなら少し無理をすれば挿入できないことは無い。そのノリで差し込んだら写真のような情けないことになってしまった。

    Misfit

    P9 と干渉して斜めになってしまったのだ。ピッチもさることながら P9 と干渉しないようにピンを整形する必要がある。

    この状態でも電気的な問題は無いから当面はこれでも良い。しかし見栄えが悪いし、コネクターの抜き差しも少し困難なので、ずっと使うならやり直す必要がある。

     

    PMIC TPS65217C の設定変更

    定格電圧 3.7V の Li+ バッテリーを満充電するには充電完了電圧を 4.2V に設定する必要があるが、BBB では TPS65217C のディフォルト値 4.1V の設定になっている。これを確認したり変えたりするのは i2c-tools パッケージに含まれている i2cget/i2cset コマンドを -f オプション付きで使えば良い。

    ubuntu@arm:~$ dpkg-query -l 'i2c*'
    Desired=Unknown/Install/Remove/Purge/Hold
    | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
    |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
    ||/ Name                          Version             Architecture        Description
    +++-=============================-===================-===================-=========================================
    ii  i2c-tools                     3.1.0-2             armhf               heterogeneous set of I2C tools for Linux
    ubuntu@arm:~$ 
    ubuntu@arm:~$ sudo i2cget -f -y 0 0x24 0x05 b
    0x80
    ubuntu@arm:~$ sudo i2cset -f -y 0 0x24 0x05 0xa0 b
    ubuntu@arm:~$ sudo i2cget -f -y 0 0x24 0x05 b
    0xa0
    ubuntu@arm:~$ 
    

    CHARGER CONFIGURATION REGISTER 2 の VOREG[1:0] フィールドを ディフォルトの 00b から 10b に書き換えている。常時バッテリー駆動対応にするなら Linux の起動時に実行されるスクリプトに組み込むのが良い。これ以外の設定を変えなければならない場合は稀だと思う。

    充電状況は CHARGER CONFIGURATION REGISTER 0 を調べれば分かる。

    ubuntu@arm:~$ sudo i2cget -f -y 0 0x24 0x03 b
    0x10
    ubuntu@arm:~$ 
    

    0x10 は充電完了だ。充電中は 0x08 または 0x48 になるはずである。これ以外は何か異常事態が発生している可能性がある。詳細は TPS65217C のデータシートを参照してほしい。

    なお TPS65217C のレジスターの値を書き換えることでコア電圧などを変更できてしまう。最悪 BBB を壊してしまうことが無いとも言えないので慎重に作業する必要がある。

     

    バッテリー駆動時に必要な情報

    残量を知るためにバッテリー電圧が必要だが、BBB では回路を追加しないと測ることができない。ただしバッテリーが間もなく空になりそうかどうかなら、回路を追加しなくても知ることができそうだ。

    3v3b

    バッテリーからの電力は TPS65217C 内部の FET スイッチを介して SYS_5V に出てくる。そして上の図にあるように LDO TL5209 を通って VDD_3V3B レールに出力され、それを1/2に抵抗で分圧した信号を ADC で測るようになっている。

    TPS65217C の UVLO (Under Voltage Lock-Out) の閾値はディフォルトで 3.3V になっていて、バッテリー電圧がそれを下回ると「空になった」と判断して電源を切ってしまう。この時 Linux は自動的にシャットダウンするようになっていない様なので何か手を打つ必要がある。(これは今後の課題)

    TL5209 は LDO だと言っても電圧降下が少なくとも 100mV 程度はあるので UVLO の少し前には VDD_3V3B レールの電圧が低下するはずである。

    これを確かめるため下のリストのスクリプトを走らせながら満充電した Sparkfun ブランドの 400mAh Li-Po バッテリーで BBB を動かし続けてみた。

    ubuntu@arm:~$ sudo -s
    root@arm:~# echo cape-bone-iio > /sys/devices/bone_capemgr*/slots
    root@arm:~# exit
    exit
    ubuntu@arm:~$ while $True ; do
    > date | tee -a log.txt
    > cat /sys/devices/ocp.*/helper.*/AIN7 | tee -a log.txt
    > sleep 15
    > done
    Wed Dec 10 11:49:37 JST 2014
    1695
    Wed Dec 10 11:49:52 JST 2014
    1695
    ^C
    ubuntu@arm:~$ cat log.txt
    Wed Dec 10 11:49:37 JST 2014
    1695
    Wed Dec 10 11:49:52 JST 2014
    1695
    ubuntu@arm:~$ 
    

    上のリストは動作確認のために Ctrl+C で止めているが、実際には UVLO で止まるまで放置した。こうやって得られた log.txt を加工してプロットしたのが下のグラフである。ここでは /sys/devices/ocp.*/helper.*/AIN7 から読み取った値を2倍して求めた VDD_3V3B レールの電圧をプロットしている。

    Figure_1

    これは思いのほかうまくいきそうだ。条件を上手に設定すれば 50% 以下の任意のバッテリー残量で警告を出したり自動的にシャットダウンしたりできそうである。(本当ならスリープさせたいところだが現在主流のカーネルは対応していない様である)

    なお現在バッテリーで動いているか、あるいは USB または AC アダプターからの電力で動いているかの情報は TPS65217C の STATUS REGISTER から得ることができる。

     

    意外と用途が限られる

    今回の方式でバッテリー駆動した場合 5V 電源が得られないことがその原因である。そのため一部の例外を除き USB ホスト機能は使えない。セルフパワーの USB ハブを使えば解決する話だが、そうしてしまうと何のために BBB をバッテリー駆動しているのか分からなくなってしまう。

    5V 出力のモバイルバッテリーで BBB を使うのが一番現実的な解決策かもしれない。

    「一部例の外」はバスパワーが 3.3V でも動作してしまう USB 機器がある、と言うこと。いくつかの Bluetooth アダプターがこれに該当する。実際に BBB では試していないが、動くものがあることを PIC では確認している。

    私が今回のバッテリー駆動方式に最も適していると思っている用途は「UPS付マイクロサーバー」だ。最近の Linux は動作中にいきなり電源を切ってもあまり壊れないが、絶対ではない。もしそんなものがあれば、だが、データの整合性が特に重要な用途にはうってつけではないかと思う。またバッテリー駆動中にシャットダウンして、その後 USB または AC アダプターから給電開始すると自動的に起動することを確認できた。これはサーバーには望ましい挙動である。

    「UPS付マイクロサーバー」は、USB または AC アダプターからの給電が途絶えたら暫くバッテリーで動作した後にシャットダウンすることを想定している。これは短い時間の停電ならシャットダウンせずにサービスを継続させたいからだ。しかし AC アダプターで給電しているとその通りに動かない。給電が途絶えた途端に Linux が「Power button pressed」と言って勝手にシャットダウンしてしまうのだ。これは想定外である。なので USB 給電に限る、と言うことにしておきたい。BBB のリビジョンや Linux イメージに依存するのかもしれないが、実際に確かめていない場合について安全サイドに考えておくべきだからである。

     

    もう一つ想定外

    今回の方式でバッテリー駆動可能にしてしまうと、バッテリーを取り外した状態で起動しなくなってしまった。どうやらバッテリー無しで TP5 と TP6 を接続するのは具合が悪いらしい。バッテリーの代わりに 1kΩ 程度の抵抗を接続してやれば起動できるし、また一旦起動してしまえば何も接続していなくても大丈夫である。

    バッテリー有無を誤検出している疑い濃厚だが、もし仮にそうであってもデータシートを読む限り AC アダプターや USB が優先されて問題なく起動しそうなものだ。しかしなぜそうならないのか良く分からない。今回の方式でバッテリー駆動可能とした場合、常時バッテリー接続が必要と思っておいた方が間違いなさそうである。

     

    今回のまとめ

    TPS65217C の充電完了電圧の設定変更が難物かと思っていたが、意外と簡単に片付いてしまった。その反面色々と想定外の事があり、何でもやってみないと分からないものである。


    Fujifilm X-M1 とそのアクセサリー

    $
    0
    0

    ここのところほとんど中級クラスのコンデジを使っていた。RICOH GX-200 だ。これはこれで悪くないのだが、以前はよく使っていたデジタル一眼 PENTAX *ist DL で撮った絵に比べるとセンサーの大きさの違いが歴然とわかってしまう。そうは言っても *ist DL は古いし重いし、まぁ色々と使い勝手が悪くて出番があるとしたら望遠鏡の直焦点で月面撮影する時くらいだが、それとて最後にやったのはいつだっけ、と言うありさま。

    更に言うと GX-200 だってもうずいぶん古びてしまった。特にセンサー感度の悪さはいかんともしがたい。明るい場所ではなかなかいい絵が出来るのに、少し暗くなると途端に元気が無くなる。おもちゃと分かった上で CASIO の EX-ZR800 を試したりもした。高感度 + 面白い機能満載で楽しめるが、絵の出来はやはりそれなり、である。

    そんな時目にとまったのが X-M1 だ。

    小さくて軽くて高感度時のノイズが少ない。ローパスフィルターレスで解像感に優れ、無改造でも赤く淡い天体に強いらしい。今までファインダーの無い一眼には若干の抵抗感があったが、それを乗り越えることを正当化する理由がこれだけあれば十分。いつ買うの? 今でしょ、と言うことになってしまった。

    単焦点レンズも使いたかったのでダブルレンズキットにした。

    /*-----------  -----------*/

    一瞬 X-E2 と迷う

    量販店の店頭で X-E2 のファインダー(EVF)をのぞいたのが悪かった。ものすごく出来がいいのだ。GX-200 の EVF は「無いよりマシ」程度にしか思えなかったが、これならライブビューが無くても全然問題ないのではないかと思える水準。うーん、どうしようと一瞬悩んだ後、正気に戻った。

    ファインダーのために倍の値段は払えない。それに X-E2 は大きくて重いんだからと自分に言い聞かせながら、これじゃあ「sour grapes」そのものだね、と苦笑い。

    X-E2 の EVF は高画素もあるが、接眼光学系の出来の良さが大きく寄与しているのではないだろうか。ハイアイで見かけ視野が広くてケラレが無い。OVF 含めても最良のファインダーの一つではないかな、と思う。まぁそれなりの値段をしている訳だが。

     

    X-M1 でビックリしたこと

    それなりに事前リサーチしたつもりだったが、それでもビックリしたのはキット付属レンズのこと。二本ともマニュアルフォーカスはかなりオーバーインフで最初かなり戸惑った。ズームレンズ XC16-50 はオートフォーカス時に音がほとんどしないのにビックリ。その反面単焦点レンズ XF27 はオートフォーカス時の音がもの凄いのにビックリ。音声付き動画撮影は無理な水準。

    そして一番ビックリしたのは単焦点レンズでは手ぶれ補正ができないこと。調べたらキット付属の物だけではなく、このマウントに刺さる単焦点レンズすべてがそうなっているし、他のボディでも状況は全く同じらしい。なかなかスパルタンな設定だ。

     

    フジのミラーレスを選ぶ覚悟

    ちょっと大げさかもしれないが、フジのミラーレスを選ぶにあたり少々覚悟が要る。それはサードバーティー製専用アクセサリー類が少ない、と言うこと。これが分かっていたので当面必要になるアクセサリー類がサードパーティーから入手できるかどうか予め調べておいた。

    先ず予備バッテリー。これは今まで他製品用の物を購入して印象の良かったショップから出ていたので問題ない。

    次にシャッターリモコン。X-E2 なら今まで使っていた PENTAX 用の 2.5φ 3P プラグ接続のものがそまま使えたらしい。しかし X-M1 は小型化するためではないかと思うが、マイクロ USB コネクターに刺さる専用のものが必要になる。これはちょっとしたパズルだが、マイクロ USB → 2.5φ 3P プラグのケーブルに 2.5φ 4P 用 J-J 中継コネクターを組み合わせると 2.5φ 3P プラグ → マイクロ USB の変換ケーブルが出来上がる。


    +

    4P 用中継コネクターは 3P にも使える、と言うところがミソだ。これに手持ちの手動式 PENTAX 用シャッターリモコンをつなげればよいのだが、インターバル機能の付いたものがずいぶん安く出ていたのでついでに買ってしまった。

    バッテリーと同じショップである。大丈夫かな、と思うくらい安いが、期待外れでもあきらめられる値段だ。しかし思いのほかマトモな製品だった。結構よくできている。

    最後にマウントアダプター。これは主に望遠鏡につなぐためである。それだけなら T マウントアダプターで良い。

    しかし焦点距離 500mm の望遠鏡なので直焦点よりもう少し大きな像が欲しくなることがあり、PENTAX 用の2倍リアコンバーターを併用することになる。そのためPENTAX K (レンズ)→ Fuji X(ボディ)のマウントアダプターを使うことにした。これなら手持ちの PENTAX 用交換レンズを使うことも可能になる。

    調べてみると、中国製の最安のものと国内製のものとでは一桁値段が違う。しかし安い製品はレンズの固定に問題が出ることが多いようだ。最安の2倍位の値段だったが、悪い評判が見つからなかった八仙堂;から購入することにした。

    手持ちの PENTAX 製交換レンズ5本は全て問題無かった。しかし二つ持っている PENTAX ボディ用 T マウントアダプターのうち一つのガタが大きく使い物にならない。

    Trings

    右側が使い物にならなかった方だが、写真で見分けはつかないだろう。試しにボディ側フランジとの間にコピー用紙を一枚はさむと、緩めだが許容範囲に入ったようである。使ったコピー用紙を 16 枚重ねるとちょうど 1mm になったので 1 枚の厚さは 63μm だ。大体このくらい寸法が違っていた、と言うことらしい。PENTAX のカメラボディならこの程度の違いは全く問題ないのに、どうしてこうなるのか調べてみた。

    Body_mount

    右側は ME Super のボディ、左側は2倍リアコンバーターである。緑色矢印の部分にレンズをフランジに押し付けるように働く小さなリーフスプリングが入っている。写真では1か所しか見えないが、マウントの3か所についている。これらは薄い金属板でできていて、レンズが装着された場合に 1mm 程度圧縮された状態になるのではないかと思われる。従って 63μm 寸法が違っていても押し付ける力が数% 違うだけで全く問題は無い。押し付ける力が ±25% 変わっても良く、ばね定数が変位によらず一定と仮定すると ±250μm 違っても大丈夫と言うことになる。ちなみにこの写真を写したのが *ist DL で、このカメラボディのマウントも同様の構造である。 PENTAX は少なくとも 30 年前、多分 K 型マウントの最初からずっとこの構造を使っていたのだろう。

    一方、購入したマウントアダプターはもっとばね定位数の大きい、すなわち硬いリーフスプリング構造になっている。

    Mount_adpt

    63μm 調整して許容範囲に入ったわけだが、この内半分程度は隙間を埋めるのに必要だったと考えるべきだ。つまり約 30μm 圧縮すると許容範囲下限の力が得られると考えるのが妥当だろう。先ほど同様に ±25% が許容範囲だとすると、寸法として ±10μm である。「表 1  面取り部分を除く長さ寸法に対する許容差 (JIS B 0405−1991) 」の規定は最も厳しくても ±0.05mm = ±50μm だ。許容範囲 ±10μm はかなり無理がある。

    このせいでレンズ側の寸法が多少違っただけできつ過ぎたりガタが出たりするのだ。製品レビューで「精度が悪い」と言うコメントを多数見かけた。これがレンズ側に向けられたコメントなら、妥当かどうかはともかく、つじつまは合う。しかしマウントアダプターについてなら、これは「設計を間違えた」と言うべきだろう。レンズ側の寸法に対する許容範囲が狭過ぎるのだ。

    マウントアダプターをリサーチしていた時「国内製なら問題は無いのだろうが値段が・・・」と思っていた。多くの人がそう思うはずだ。しかしここで得られた知見を元に製品写真を見比べると意外なことが分かった。

    大丈夫だろうと思った国内製と称する製品は、今回購入したのと同じようにレンズ側寸法に対する許容範囲が狭い構造をしている。

    比較的安価な中国製の製品も同じ構造のものが多いが、最安の製品は意外にも寸法許容範囲が比較的広いのではないかと思われる構造のように見える。

    ただし注文したら実際に送られてきた製品が写真と違っていた、と言うことが無いとは言えないだろう。「写真と違う」と言えば返品に応じるかもしれないが、リスク要因である。

    中国製の中で比較的高価な製品も寸法許容範囲が比較的広いのではないかと思われる構造をしている。

    この場合写真で確かめられた範囲で同じブランドの製品は同じ構造をしていたので、このブランドを指名して買えば写真と同じ製品が送られてくると思って良さそうだ。

    許容範囲が広ければより多くの場合に対応できる。これは一般論として正しいが、極端に製造精度が悪かったりそもそも基準寸法がずれていたりすれば問題を起こすことになる。逆に許容範囲が狭くても実在する寸法の範囲をカバーできる場合が無いとは言えない。実際に私の場合でも使い物にならなかった T マウントアダプターが無ければ「問題なく使える良い製品」と言っていただろう。

    実はこう言っておくのは保険みたいなものだ。許容範囲の広い方が当然問題が少ない。国内製と称する高価な製品が本家と異なるリスクの高い構造を採用しているのは腑に落ちないことである。

     

    今回のまとめ

    八仙堂から買ったマウントアダプターは、問題のある T マウントアダプターを使わないようにすれば良いので、使い続けることにしている。それ以外のアクセサリー類は今のところ問題もなく使えている。

    八仙堂では出荷前にリーフスプリング部分を調整しているのではないかと思われる。だから PENTAX 純正レンズはどれもイイ感じで使えたのだ。ひと手間加えることで商品価値を向上させている、と言うことだろう。しかし設計上の問題までは直せない。仕入先と調整できるなら問題の少ないはずの構造をした製品に切り替えることを検討してほしい。

    X-M1 はまだそんなに使いこなせていないが、期待通りのカメラ、と言う印象だ。ほぼディフォルト設定のまま直焦点で月面を撮ってみた。

    Dscf1072_2

    2014/12/14 追記: 最初トリミングなしの画像を掲載したら縮小表示されてしまうようだったので、中央部分だけにトリミングした画像に差し替えた。

    撮って出しの JPEG 画像だ。ホワイトバランスが自動だったためか色が抜けてしまっているが、それを除くと結構イイ感じである。チルト式液晶モニターによるピント合わせは予想以上に快適だ。

    microSD カードの寿命を調べる

    $
    0
    0

    BBB を実用的な用途に使おうとすると microSD カードの寿命が気になる。「寿命が気になる」と言うことについては SSD も同じだが、以下のような理由で何倍か余計に気になる。

    • サイズが小さいから高集積度のフラッシュメモリーを使っているはずだ。集積度を上げるために消去/書き込み寿命を犠牲にしていないか?
    • 容量が小さいから書き込むデータ量が同じでも消去/書き込み回数が多くなり、早く寿命に到達するのではないか?
    • コントローラーに実装できる機能の制約が厳しいはずだから、 Write-amplification をあまり低減できていないのではないか?
    • S.M.A.R.T. 機能が無いから残り寿命を把握できないのではないか?

    気に病んでいる時間があるなら調べてしまおう、と言うこと。早く寿命に到達するなら調べる時間も短くて済むはずである。5日位で勝負がつくかもしれないと思って年末に始めたが、結局年を越してしまった。

    なお区別するとやたら端数が出て面倒なので、今回の記事では 210と 103は同じと言うことにしてしまった。そのためテラバイトの桁になると1割近く計算が合わない場合があり、有効数字1桁である。この点ご容赦願いたい。

    /*-----------  -----------*/

    調査対象と方法

    言うまでもなく調査対象は寿命だ。この場合の「寿命」は microSD が壊れるまでに書き込めたデータ量と定義する以外にあまり良い方法は無さそうである。また「壊れた」と言うのは書き込んだ直後にデータを読みだした際、書き込んだ通りのデータが読み出せなかったり I/O エラーが発生する状態と定義する。

    書き込み直後には正常に読み出せても少し時間が経つとエラーが発生するような状態、つまりデータ保持期間が極端に短くなるような場合も起こると思うが、これを調べようとするとかなり長期間の調査になりそうなので見送った。

    今回もう一つ調べたかったのが書き込みデータ量の実用的な把握方法である。

    SSD なら S.M.A.R.T. 機能の属性値に消去回数のような残り寿命を推定できる情報が準備されている場合が多いが、 microSD カードではこの種の情報が得られない。

    Smart

    その代わりに書き込んだデータ量を把握して、同じ様に調べておいた寿命と比べれば残り寿命が推定できるだろうと考えたわけである。寿命を調査する時はテスト用のプログラムが圧倒的に多量のデータを書き込むようにして、それ以外の書き込みは無視できるようにするのが一般的だと思う。しかし実用的なアプリ運用中にその手段は使えないが、 Linux の機能をうまく組み合わせれば同等の事が実現できる。

    最近の Linux では一般的になった Ext4 ファイルシステムはスーパーブロック情報に「Lifetime writes」が含まれていて、 dumpe2fs -h コマンドまたは tue2fs -l コマンドで表示させることができる。

    volumio@volumio223:~$ sudo dumpe2fs -h /dev/root | grep Lifetime
    dumpe2fs 1.42.5 (29-Jul-2012)
    Lifetime writes:          378 GB
    volumio@volumio223:~$ sudo tune2fs -l /dev/root | grep Lifetime
    Lifetime writes:          378 GB
    

    これはファイルシステムが作成されて以来書き込まれた累計データ量だ。ただしこの数値はファイルシステムがマウントされた時点のもので、マウント中は更新されないが、 iostat コマンドを使うと補うことができる。

    volumio@volumio223:~$ iostat -m
    Linux 3.8.13-bone20 (volumio223)        01/03/15        _armv7l_        (1 CPU)
    
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle
               3.29    0.00    6.52   89.90    0.00    0.29
    
    Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
    mmcblk0          50.72         0.52         2.61      42232     213834
    mmcblk1           0.00         0.00         0.00          0          0
    mmcblk1boot1      0.00         0.00         0.00          0          0
    mmcblk1boot0      0.00         0.00         0.00          0          0
    sda               0.01         0.00         0.00          5          0
    

    MB_wrtn は、デバイス毎の Linux 起動以来の累計書き込みデータ量である。この数値はコマンド実行時点の値なので、「Lifetime writes」と合計すればファイルシステム作成以来の書き込み量の最新値を得ることができる。ただし「Lifetime writes」はファイルシステム毎なので、一般論として同じデバイスに属する全ての区画を合計する必要があるが、 BBB では通常書き込みを行う区画が一つしかないのでこの種の心配は要らない。

    これでメデタシメデタシとなる予定だったのだが、今回調査していて少し困ったことが見つかってしまった。「Lifetime writes」は Linux が正常終了しなかった場合に更新されない様なのだ。つまりこう言う事である。

    • Linux 起動: Lifetime writes = 123GB
    • テストプログラムで 10GB 書き込み
    • リセットスイッチで Linux 再起動: Lifetime writes = 123GB

    「Lifetime writes」はアンマウントのタイミングでファイルシステムに書き戻されているのかもしれない。いずれにせよ「Lifetime writes」と iostat の結果を単純に合計しただけではダメだ。今回の調査ではファイルシステム作成以来 Linux 起動する都度の「Lifetime writes」と定期的な iostat 結果の記録を残しているので、正常に Linux が終了しなかったことによる「Lifetime writes」の差異は補正可能だ。ただし最後の iostat 結果の記録以降に行われた書き込み量が把握できず、マイナス誤差になる。この誤差は iostat 結果の記録頻度を高くすれば小さくなるので、必要な精度から頻度を決めるようにする必要がある。

    今回問題は1回の異常終了毎に最大 5GB の誤差を許容する設定だ。問題になるのがテラバイト単位のデータ量なのでこれで良いのである。

    同じような記録を残せば実用的アプリ運用中にも適用可能だ。この場合全ての記録を残す必要は無く、直近の2世代程度の情報を再起動をまたいで伝わるようファイルで残してやれば良いはずだ。これはまだ構想段階で、今回の調査が終わったら詳細を詰めたうえで記事にしたいと思っている。

    更にもう一つ、せっかく時間をかけて調べるのだから残り寿命に応じて変化するような指標になりそうなものを試すことにした。

    エラー訂正は今日の大容量フラッシュメモリーを支える重要な技術だ。これは磁気ディスクでも同じかもしれない。フラッシュメモリーが寿命を迎えるのはエラーが訂正しきれなくなる時である。つまり残り寿命が短くなるにつれ訂正されるエラー頻度が高くなり、それに応じて読出し時間が長くなるのではないかと考えた。 Read-modify-write を行っている場合があるので、これは書き込み時間にも影響するはずだ。つまり決まった量のデータを読み書きするのに要する時間変化を調べることにした。

    結局以下のようなシェルスクリプトで記録を取ることにした。

    #!/bin/bash
    
    log='/mnt2/sd_endurance/log.txt'
    part=`mount | grep 'on / ' |  awk '{ print $1 }' `
    echo "${part}"
    echo -n "${part} -- " >> $log
    sudo dumpe2fs -h $part | grep Lifetime | tee -a $log
    
    mkdir -p testfiles
    
    while $True ; do
        date | tee -a $log
        for i in 1 2 3 4 ; do
            echo -n "wrt[${i}] "
            ./filewrt.py
        done
        echo -n "wrt[5] "
        ./wrt_chk.py | tee -a $log
        date | tee -a $log
        iostat -m | grep mmcblk0  | tee -a $log
    done
    

    filewrt.py は 1GB データを書き込むプログラム、 wrt_chk.py は 1GB データを書き込んだ後読み出して正しく書き込めているか確認するプログラムである。

    書き込むのはサイズ 256kB のファイルを 1024 個、 256MB のサイズを 3 個で、内容は長さ 256kB のランダムな文字列だ。万が一圧縮機能があっても効かないようにするためである。なおランダムな文字列はプログラムの実行の都度生成するが、先頭をファイル名に置き換えている以外全てのファイルで共通である。 256MB のファイルでは同じ文字列を 1024 回繰り返している。なお書き込みブロックサイズは全て 256kB である。

    wrt_chk.py は読みだしたデータを書き込んだデータと照合して不一致が発生した場合、および読出し中に発生したエラーの内容がログに残るよう出力する。これらの事象が発生しても処理は打ち切らない。書き込み中にエラーが発生した場合は Python の標準機能でプログラムの実行が中断されるはずだが、可能な限りスクリプトの実行は継続する。これは microSD が壊れた時何が起こるか、できるだけ最後まで見届けられるように考えたものだ。

    スクリプトを実行する前にファイルサーバー上の共有ディレクトリーを /mnt2 にマウントしておく。実際はサンプルを識別するためにログファイル名をユニークにしているので同時複数のテストを行うことが可能である。

    なお今回 Linux イメージは Volumioを使った。テストプログラムを黙々と動かしている間も microSD 以外のリソースはほとんど使われていないので Web ラジオが聞けるようにしてしまおう、と言うことだ。記事を書いた時点の最新バージョンは 1.5 だが Volumio の機能に一部不具合があったので 1.4 を使っている。ディストリビューションは Debian 7.7、カーネル 3.8.13-bone20 だ。

    apt-get update および upgrade を行うのに加え、以下の準備を行っている。

    • IP アドレス固定化(/etc/network/interfaces 編集)
    • ホスト名変更(/etc/hosts および /etc/hostname 編集)
    • タイムゾーンを Asia/Tokyo に設定(dpkg-reconfigure tzdata)
    • パッケージ sysstat および screen をインストール

    sysstat パッケージは iostat コマンドを使うために必要。 ssh セッションで BBB にログインして、 screen パッケージが提供している screen コマンドを実行してからシェルスクリプトを動かしておく。これで ssh セッションを切断して再接続後に screen -r コマンドを実行することでスクリプトを実行中のセッションに再接続可能になる。

     

    調査対象サンプル

    できるだけ調査が短期間で終わるよう、 micoroSD HC カードの最小容量である 4GB で最も高速な Class 10 を4品種、それぞれ1つずつ調べることにした。

    Sd_cards

    今回の調査はブランド間の違いを調べるのが目的ではないので各品種1サンプルとした。これでは得られた結果から当該品種母集団の平均像を議論するのは統計的な意味が無いが、それで良いのだ。むしろブランドを決めずに「4GB Class 10 の micorSD カード」を一つ取り上げた時の結果がどの程度の範囲にバラつくのか、それを調べるのが目的である。

    ただし便宜上「xxx(ブランド名)のサンプル」と表現する場合があると思うが、これは今回使ったサンプルを識別するのが目的であって、そのブランドの製品の平均像と言う意味ではない。

     

    事前の予測

    寿命に関する記述のある microSD カードのデータシートは見たことが無い。 SSD なら詳細なデータシートを公開しているベンダーもあるが、コンシューマー向け製品の寿命に関しては「JESD218規格適合」で済まされている場合が多い。

    「JESD218規格」そのものは無償公開されていないが、間接的に無償公開されている例としてインテル 530 シリーズのデータシートを参照すると、以下のように記載されている。

    The Intel® SSD 530 Series meets or exceeds SSD endurance and data retention requirements as specified in the JESD218 specification.
    Table 10: Reliability Specifications
    ParameterValue
    (省略)
    Minimum Useful Life/Endurance Rating
     The SSD will have a minimum useful life based on a typical client workload assuming up to 20 GB of host writes per day.
    5 years
    (省略)
    Source: http://www.intel.co.jp/content/dam/www/public/us/en/documents/product-specifications/ssd-530-sata-specification.pdf

    「5年間毎日 20GB 書き込んでも大丈夫」と言うこと。 365 日/年とすると累計 36.5TB 書き込める計算だ。インテル 530 シリーズで最も容量の小さい製品は 80GB なので、ディスク容量の約 450 倍書き込んでも大丈夫、と言うことである。これから推定すると、ディスク容量の 500~1000 倍書き込むと「壊れる」のではないかと考えられる。

    少し無謀だと思うが、これをそのまま 4GB microSD に当てはめると 1.8TB 書き込んでも大丈夫、 2~4TB 書き込むと「壊れる」と言うことだ。 Class 10 の規格の半分、 5MB/s の書き込みスループットが得られるなら、早ければ5日で終わる。この程度なら手軽に試せる、と思って始めたのが間違いだったかもしれない。

     

    中間結果

    最も早く調査開始した磁気研究所(MAG-LAB)と Transcend のサンプルが1週間を超えた時点の結果である。

    Figure_1

    一番多いものでも累計書き込み量は約 1.7TB に留まっていて未だエラーなどは発生していない。これは BBB の書き込みスループットが 3~4MB/s しか出ないことに原因がある 。USB 接続のカードリーダー/ライターを使って Windows でイメージを書き込んだときは間違いなく 10MB/s 以上出ていたので、 BBB のアクセス方法の問題である可能性が高い。

    これだと 2TB に到達するにはさらに1日以上かかる計算になる。また同時に調査できるのは最大3サンプルなので、どれか一つが壊れてからさらに1週間以上調査する必要がある。やれやれ。

    なお MAG-LAB と Transcend のグラフが 200GB から始まっているが、これは最初読み込み確認を行っていなかったためである。また Silicon Power のサンプルは受け入れ検査のつもりで最初の 100GB だけテストして待機させている。

    現時点で収穫と言えるのは、書き込み量が増えるのに従ってテストプログラムの処理時間が増加している事だ。原因は私が想定した通りではないかもしれないが、今後どのような変化を見せるか楽しみである。

     

    Write-amplification

    先ほどインテル 530 シリーズの寿命がディスク容量の 500~1000 倍書き込みと計算した。 MLC フラッシュデバイスの消去/書き込みサイクル寿命が数千~1万回と言われている事を考えると、 Write-amplification が平均 5~10 程度になるような書き込みパターンを想定していると考えるべきなのだろう。

    今回の調査で使っているテストプログラムの書き込みブロックサイズは 256kB で、 Write-amplification がもっと小さくなっている可能性がある。もしそうなら、今回の調査は書き込み量 4TB 位では終わらないことになる。

    microSD のコントローラーはそんなに凝った制御はできないだろうから、書き込みに必要な時間が Write-amplification と比例するのではないかと考え、書き込みブロックサイズとパフォーマンスの関係を調べてみた。

    Atto_lexar_qd4

    今回調査に使っている microSD で調べると書き込みデータ量が正しく把握できなくなってしまうので、それらとは別の Lexar Media の 8GB Class 10 の製品で調べた結果である。書き込みに必要な時間が Write-amplification と比例している領域では IOPS が一定値になるはずなので、計算してプロットしてみた。

    Atto_lexar_plot_qd4

    ブロックサイズ 32kB 以下で IOPS がほぼ一定になっているようだ。若干右肩下がりなのはデータ転送に要する時間がブロックサイズに比例することで説明できるのではないかと思う。従って、今回のテストプログラムが行っているブロックサイズ 256kB の書き込みの場合 Write-amplification は1である可能性がある。もしその通りだとして、 4GB の microSD を壊すには 20TB 書き込みが必要だとすると、調査期間は2か月以上必要である。やれやれ。

    もちろん 4GB の microSD に 20TB 書き込まないと壊れない、と分かるのは喜ばしいことである。始めた以上見届けるつもりだが・・・やれやれ。

    しかしその一方で、そんなに長い期間かからないのではないかと思える材料もある。

    今のペース(2~4分/TB)で処理時間が増加を続けると、書き込み量が 20TB に到達するころには処理時間が最初の2倍を超えてしまう。これはありそうにない事だ。全く根拠は無いが仮に処理時間が最初の5割増しになった時に壊れるなら、書き込み量は 3.5~6TB である。こっちの方がもっともらしく思える数字だ。調査期間は2~3週間で済む。

     

    今回のまとめ

    ブロックサイズ 256kB は現在構想中のアプリの典型的なデータセットサイズだ。アプリでバッファーしておいて、一気に書き込むようにすればこうなる、と言う構想。こうすると 20TB 書き込めるなら、データセットを8千万回書き込める、と言うことである。データセットの中身にはセンサーから取得するサンプル値が含まれ、 256kB のデータセットを一つ作るのに少なくとも1分かかる見込みなので、連続してデータセットを作り続けても5万日分以上のデータを書き込める寿命がある・・・計算違いじゃあないかと心配になる数字だ。100年を超えるので現実的に意味のある数字ではない。つまり半永久的、と言える水準である。

    どんな結果が出るか続けてみないと分からない。続報も記事にする予定である。しかし 2TB でも5千日分以上のデータを書き込めるわけで、これでも十分おなか一杯だ。そしてその水準にもうすぐ到達するのだから、 microSD の寿命を気に病む必要があるかどうかについては既に決着済なのかもしれない。

    カメラのノイズと解像感

    $
    0
    0

    最近調達した FUJIFILM X-M1 と今まで主に使っていた RICOH GX-200 で風景を撮り比べてみた。どうやらノイズの少なさが解像感の向上に貢献しているらしい。

    /*-----------  -----------*/

    武蔵野の夕陽

    今回は「撮って出しJPEG」で撮り比べした。

    Gx200small2jpg

    上は GX-200 で撮った全景を 1/4 に縮小したものだ。この位のサイズで見るなら GX-200 も悪くない。

    撮った後見比べていて気付いたのだが、左下の建物の屋上フェンスが解像度の限界付近の画質を見るのにちょうどいいテストパターンになっている。上の写真にピンク色の枠で示した部分だ。ピクセル等倍で切り出してみた。

    Comb11

    撮影条件
    項目GX-200X-M1 + XC16-50mm単位
    大きさ4000x30004896x3264ピクセル
    画質設定FINE (最高)FINE (最高)
    白バランスAUTOAUTO
    絞り値3.2 (開放:2.5)5.0 (開放:3.6)F
    露出時間1/8701/550
    ISO 感度64200
    焦点距離5 (ワイド端)
    35mm換算: 24
    16 (ワイド端)
    35mm換算: 24
    mm
    フォーカス手動手動
    ファイルサイズ4,160,5912,820,520バイト

    GX-200 はコントラストが高くカッチリしている。その一方 X-M1 はコントラストが若干低く、ソフトな印象である。多分これが原因なのだが、X-M1 で写した画像をカメラの液晶モニターで確認した時にピント合わせを失敗したかとドキッとしたことが何回かあった。

    しかし GX-200 では同時に何かザワついた落ち着かない感じを受ける。フェンス左端から中央付近にかけてモアレないしは偽色が見られるからだろう。X-M1 の方はそのようなことは無い。詳しく見るためにフェンス左端付近をさらに拡大してみよう。

    Comb500

    ピクセルの存在がはっきり分かるよう拡大の際に補間は行っていない。これを見て分かったのは、フェンスの模様は画像センサーのピクセルピッチで決まる解像度の限界にほぼ等しい、と言うことだ。フェンス左端では限界よりも粗いが、右端では限界を超える。画角が同じでセンサーのピクセル数が多い X-M1 の方が解像度の限界が若干高いが、この状況は同じである。この領域でも GX-200 のように高いコントラストを得ようとすれば偽色やモアレが発生する場合があっても仕方がないと言えるだろう。

    また GX-200 の場合不規則なパターンがフェンス左端付近に生じている。どうやらこれが落ち着かない感じの本当の原因らしい。このように不規則なパターンはモアレなどでは説明できず、ノイズの影響と考えるのが妥当だろう。

    ここで言う「ノイズの影響」は、光量が少なくて信号レベルが小さくなることによるS/N比の低下ではない。露出条件を見れば十分な光量があることが分かるが、それでも GX-200 で写した画像の空の部分にザラついた感じのノイズが認められる。GX-200 はセンサーの解像度の限界付近でも比較的高いコントラストが得られるチューニングが施されているので、なおさらノイズの影響を受けやすくなっている可能性が高い。

    解像感を高めようとしてもノイズが多いと逆効果になる場合がある、と言えそうだ。これと似た内容の記事が「ようかんのあやしい実験ブログ」で見つかった。掲載画像を数値化して解析したら記事の内容を裏付ける結果が得られた、と言う実に興味深いものだ。

    ようかん氏から記事にすることへの承諾が得られたので、ここに併せて紹介する。

    なお私が X-M1 を調達するきっかけになったのがこのブログのいくつか前の記事である。

     

    月面写真のコンポジット処理の実験

    元画像は上のリンクをたどって見てほしい。コンポジット数の異なる横幅 120 ピクセルの帯状の画像が 8 枚横に並んだ画像である。上端から 161~280 ピクセルの範囲で各コンポジット数の画像を切り出し、モノクロ化して窓関数を適用したサンプルを準備する。

    Windowed_samples

    今回はハミング窓を使った。それぞれのサンプルについて2次元 FFT を行うと、元画像の配列と同じ 120x120 の2次元配列の形で空間周波数スペクトルが得られる。長くなるので数学的な詳細は省くが、平面上の空間周波数を測る場合に向き(角度)を意識する必要がある。つまり周波数が2次元ベクトルなので FFT の結果が2次元配列になるのだ。

    空間周波数毎に全ての向きの周波数成分値の RMS を計算すると、空間周波数と画像強度、つまりコントラストの関係が得られる。これは全く劣化が無い場合の元画像の空間周波数分布に処理系全体の MTF を適用したものに相当する結果である。これを各サンプルについて計算し、まとめてプロットした。

    Fft_power

    FFT を行ったままだと空間周波数の単位は 120 ピクセルあたりの波数なので、CMOS センサーの長辺のピクセル数 / 長さ[mm] / 120[ピクセル]= 4896 / 23.6 / 120 を掛けて mm あたりの波数 [1/mm] に換算している。

    このままでもコンポジット数の違いが分からなくもないが、ウェーブレット処理を行っていない n = 1 を基準にコントラストが何倍増加しているかを見たほうが違いが分かり易い。

    Fft_relative

    この結果から言えるのは;

    • 概ね空間周波数 65/mm 以下が有効な画像、それ以上がノイズと識別されている
    • 「Noisy Limit」と表示した線がノイズが目立ち始める限界である
    • n = 64 を超えてコンポジット数を増加させた場合もノイズ成分が減り続けている
    • ノイズ成分が減っているにもかかわらず n = 100 以上で有効な画像のコントラストが上がっていないのは、これ以上ウェーブレット処理を強くすると不自然になるからではないかと考えられる (Unnatural Limit)

    ただし有効画像とノイズ成分の境界や「Noisy Limit」および「Unnatural Limit」の位置は今回の条件固有である。元画像が変わればもちろん、同じ元画像でもサンプルを取る位置が変われば変わってしまう。ウェーブレット処理を行っていない n = 1 との比率を取っている事が変わってしまう一番の原因である可能性が強いので、一つ前のプロットを使えばもう少し普遍的な結論が得られるかもしれない。

    ただ、いずれにせよ画像の空間周波数分布を見ながら RegiStax を使う訳ではないので、どんな結果が得られても直ちに何かの役に立つことは無さそうである。この種の分析に利用価値があるとしたら、ウェーブレット処理の自動化につなげられるような結果が得られた場合だろう。

     

    レンズ系分解能との関係

    地上写真を撮影した際に1段絞り込んでいるので収差の影響はある程度軽減されているはずだ。それでも無収差を前提に天体望遠鏡と同列に議論して良いものか怪しいが、一応確認しておこう。

    項目GX-200
    地上風景
    X-M1 + XC16-50mm
    地上風景
    X-M1 + 天体望遠鏡(注1)
    月面写真
    単位
    絞り値3.2 (開放:2.5)5.0 (開放:3.6)15.4F
    レイリー限界(注2)1.93.09.4μm (センサー上)
    ピクセルピッチ1.94.84.8μm
    (注1)ビクセン ED103S EDアポクロマート鏡筒 (口径103㎜ 焦点距離795mm F7.7)
      Nikon Teleconverter TC-201 2X 合成焦点距離: 1590mm (F15.4)
    (注2)波長 500nm (0.5μm) の緑色光の値

    結果について論評する前に、レイリー限界について再確認しておきたい。レイリー限界は2つの点像が見分けられる範囲で最も近づいた状態だ。この場合の点像の中間の明るさを計算すると、点像の中心の約 1/2 になる。また中間の明るさがゼロになるのは点像がちょうどレイリー限界の2倍離れた場合で、これは光の回折が影響を表し始める状態である。これよりも点像が離れていれば回折の影響を無視しても大な誤差にはならないはずである。

    Rayleigh

    このプロットの横軸は像面上の距離 x を光の波長 λ とレンズの F 値で割ったものだ。レイリー限界は x = 1.22λF と表されるが、この時の 1.22 に相当する値である。また例えば 波長 500nm、F2 の場合なら、横軸の数値はそのまま μm で表した像面上の距離になる。

    ここで考えておく必要があるのが、いくつピクセルがあれば2つに分離された点像があることが分かるか、と言うこと。

    2つだと分離された点像がそれぞれのピクセル上にある場合と、分離されていない大きな点像が2つのピクセルにまたがって存在する場合が見分けられない。これは中間の暗い部分の有無を検出することで区別できるので、最低3ピクセルあればOKだ。つまりピクセルピッチは点像間隔の 1/2 以下であることが必要になる。

    デジタルカメラのピクセルピッチの説明で「レイリー限界よりも小さいのは無意味」と書かれているのを見かけることがあるが、これは「これより小さくても回折の影響でコントラストが次第に低下するから」と言う理由に基づくことになる。レイリー限界までは点像が分離できる立場を取るなら、ピクセルピッチの微細化はレイリー限界の 1/2 までは有効と書くべきだろう。この2倍の違いはある種のグレーゾーンとみなすのが適切なのかもしれない。

    さて、先の表を見てまず気づくのは、GX-200 はもう少し絞り込んだ状態に合わせてチューニングされているのかもしれない、と言うこと。今回は F3.2 だったが、もっと絞り込んで例えば F11 だったとするとエアリーディスクの明るい中心部に 20 ピクセル以上入る計算になるから、偽色やモアレが出る心配は無さそうである。ただしノイズに関しては良くも悪くも影響無いはずだ。

    GX-200 はレイリー限界とのグレーゾーンのピクセルサイズが大きい方の端に該当するが、「ようかんのあやしい実験ブログ」の月面写真は相対的にピクセルサイズが小さい方の端にあたっている。ここで注目に値するのは、ノイズとみなす空間周波数の下限 65/mm に該当する像面上のピッチがレイリー限界の 1.64 倍で、例のグレーゾーンの中に入っている事だ。空間周波数が 65/mm よりも高い成分は CMSO センサーに結像した画像にほとんど含まれていなかった可能性がある。RegiStax で処理する前に空間周波数 65/mm 以上の成分を取り除くような処理を行うともっと少ないスタック数で同じ結果が得られるかもしれない。RAW 画像を現像する際の設定で実現できれば手間が増えずに済むが、ざっと見た範囲ではディティールを捨てるような設定は無いようだ。バッチ的に多数の画像に一括でローパスフィルターを適用するプログラムは比較的簡単に作れるから、そのうち試してみたいと思うが、問題は素材の準備だ・・・。

     

    再びノイズについて

    比較的明るい画像で ISO 感度も低いのに問題になるようなノイズが発生するのを不審に思っていた。もしかしてと思って調べたら、ピクセルごとの感度のバラつきが原因でノイズなどの問題が発生するのは良く知られた事実らしい。構造上の特性から CMOS センサーで著しく、なかには「CMOS センサ特有」と書いている資料もある。

    今回の地上風景の比較では CCD センサーを使っている GX-200 の方がノイズが目立つ結果になったが、これは X-M1 の画像処理エンジンが良くできているかららしい。別の被写体の場合だが、RAW ファイルをディフォルト設定の RAW FILE CONVERTER で処理した .tif ファイルの方が同時記録した JPEG ファイルよりも明らかにノイズが多いのだ。

    センサーの感度のバラつきが原因ならフラット補正で解決できる可能性がある。光学系を含まないセンサーのみの補正で良いはずだ。オフセットのバラつきも問題になるのならダーク補正も必要だろう。RAW ファイルに適用するのが効果的だと思うが、現像して無圧縮の .tif を作って処理する方が道具の準備が簡単そうである。これもそのうち試してみたいと思う。

    もしかして X-M1 の画像処理エンジンは JPEG 生成時にダーク/フラット補正に相当するような処理をしている? まさかとは思うが、技術的に不可能ではないから、無いとは言えない。

     

    今回のまとめ

    ノイズが多いのが原因で解像感が損なわれる場合がある。エッジが毛羽立ってしまうからだろう。エッジが滑らかな方が解像感が高い。

    月面写真に最適なウェーブレット処理を行うためスタッキングによるノイズ低減が有効であることが実証された。月のような、天体写真ではかなり明るい被写体でもノイズ低減がこんなに効くのは意外だ。ピクセル毎の感度のバラつきによるノイズである可能性が考えられる。光学系の分解能を超える高周波成分を予めフィルターで取り除いてしまうのが有効かもしれない。

    水星と金星のランデブー

    $
    0
    0

    夕映えを眺めるつもりで近所の跨線橋に行ったら、金星の近くに見慣れない一等星が寄り添っていた。

    Mercvenu

    Google Sky Map で調べたらなんと水星。こんなに簡単に見えていいんだろうか?と心配になるくらい良く見える。ノーマークだったので、とりあえず持ち合わせの機材で撮影。もう少し長いレンズと三脚が欲しい・・・。(これは部分切り出し+約1/2に縮小)

    15日の東方最大離角を少し過ぎるくらいまで楽しめそう -- 日没後 30分~1時間くらいが狙い目。

    空間フィルターを使った天体写真の画質改善

    $
    0
    0

    ようかん@http://blogs.yahoo.co.jp/youkan2000/氏から素材画像など必要なデータ一式を提供していただいたので、以前の記事に書いた以下の事を試してみた。

    RegiStax で処理する前に空間周波数 65/mm 以上の成分を取り除くような処理を行うともっと少ないスタック数で同じ結果が得られるかもしれない。(中略)プログラムは比較的簡単に作れるから、そのうち試してみたいと思うが、問題は素材の準備だ・・・。

    途中いくつか新しい発見があり、何回か作業をやり直しているので時間がかかってしまったが、当初の目論見に近い結果が得られた。

    /*-----------  -----------*/

    背景と仮説

    以前の記事で「ようかんのあやしい実験ブログ」の記事「月面写真のコンポジット処理の実験 (FUJIFILM X-M1 編)」に掲載されていた画像を使い、スタックする画像数の違いによるコントラストの空間周波数分布の変化を調べた。

    1_fft_relative

    画像数が 64 を超えて増加すると空間周波数 65/mm 以上のコントラストが次第に低下するが、目で見た画質の変化はほとんど感じられない。この周波数領域に意味のある画像信号が存在しないためだと考えられた。これは次のことからも裏付けられる。

    2_airy

    F ナンバー毎の光学系の分解能を MTF カーブで示したもので、当該月面画像の撮影に使われた F 15.4 では空間周波数 65/mm 以上の信号成分の減衰が大きい。そのため画像センサーに結像した画像にその空間周波数領域の成分がほとんど含まれていなかった可能性がある。意味のある画像信号が存在しない空間周波数領域の信号は捨ててしまっても画質に影響は無い。

    3_sn_ratio


    半分の周波数範囲を捨てても意味のある画像信号に影響が無いなら、ノイズ電力が半減するので S/N 比が 3db 向上する。スタックで同じ効果を得るには画像数を2倍にする必要があるからこの違いは大きい。

     

    空間フィルターの設計

    カットオフ特性が鋭いほど効果が高いはずなので、そのようなフィルターの設計が比較的容易な FIR 方式を使った。FIR は周囲の画素の移動平均を計算する方式のフィルターである。

    4_fir

    Fig. 4 はオーディオ信号のような1次元の FIR に関するものだ。空間フィルターでは2次元になるが、本質的にやることは同じである。ただし2次元では向きを考える必要がある。例えば「目標の周波数-振幅特性を作る」場合、通過帯域を正方形にすると縦横方向と斜め方向で特性が違ってくる。円形のパターンにすれば等方性の特性になる。

    鋭いカットオフ特性を得ようとすると移動平均の重みに負の値が出てくる。計算結果も負の値を含む場合が出てくるが、画像の場合「負の明るさ」は表現できない。レタッチをしている感覚だと「負の明るさ」は値ゼロの黒レベルにしてしまえば良さそうに思えるが、それだと信号波形をクリップすることになり具合が悪い。波形が歪むことで元々無かった周波数の信号成分が発生してしまう。これはノイズで、フィルターの特性を大きく損なう原因になる。

    今回は計算結果の最大-最小値が画像データの表現できる範囲に収まるよう、全体の黒レベルとコントラストを調整するようにした。このようにして作ったフィルターにテスト信号を入れて特性を確認した。比較のため、ノイズ除去の目的で使われる場合も有る「ガウスぼかし」の特性も一緒にプロットしている。

    5_lpf

    FIR フィルターは浮動小数点で計算し、結果を画像データの形式に変換した。「float」と表示したプロットが浮動小数点の内部データで、狙った特性が出ている。これを「tiff16」形式に変換すると高い空間周波数のレベルが若干上昇する。変換する形式が「tiff8」では高い空間周波数のレベル上昇が大きい。どうやらこれは切り捨て誤差ないしは量子化雑音、と言うことらしい。

    以前の記事を書いているときはスタック前の画像にフィルターを適用するよう考えていた。しかしこれは処理量が多いので、スタック済の画像に適用するよう変更した。処理対象画像数が数十~数百倍違うのでこの差は大きい。

    5b_tiff16_8

    FIR フィルターを構築するのに当初使っていた画像処理ライブラリーが tiff16 形式をサポートしていないので別のツールで tiff8 形式に変換していたのだが、Fig. 5 の結果を見て考え直した。Wavelet のような強調処理はノイズも誇張してしまう場合が多いので、そう言った処理を行う対象画像のノイズはなるべく減らしておいた方がいい。しかし tiff16 形式の読み書きともにちゃんとサポートしている道具は意外と少ないので、実際どの程度影響するのか調べてみた。(tiff8 でもあまり影響が無ければそれで誤魔化したい)

    6_uint8_effect

    ようかん氏に提供していただいた中にスタック済 tiff16 画像データがあったので、これをそのまま Wavelet 処理した場合と一旦 tiff8 形式に変換してから Wavelet を行った場合を比較したものだ。 tiff8 形式に変換すると高い空間周波数領域のレベルが明らかに上昇している。

    仕上がり画像を別々に見ても分からないが、並べて比べると違いが分かる。ただし違うと分かるだけで、どちらが良いかまでは判別できない程度の違いである。しかし数値にすると明らかに差がある。一旦 tiff8 に変換してしまうと高い空間周波数領域の特性の違いがノイズに埋もれて判別できなくなる。画質に対しても悪影響が無いとは思えないので、tiff16 をちゃんとサポートしているモジュールを探して使うようにした。

     

    結果の検証

    実際のスタック済画像にフィルターを適用して Wavelet 処理を行った画像を使って検証を行う。フィルターを適用せずに Wavelet 処理を行った画像と比較して変化を確認するのだ。どちらも同じ Wavelet 設定: 「フィルターを適用していない状態でノイズが目立ち始める限界の設定」を使っている。

    7_fft_relative_filtered

    フィルターは、 X-M1 の画像センサー解像度の半分よりも高い空間周波数の成分を除去するようにカットオフを設定した。数値では狙った通りの効果が得られたが、プロットを見ると意味のある信号を少し削ってしまっているようだ。

    問題は画像の仕上がり具合だ。同じ条件で比較するため、フィルターを適用した画像についてノイズが目立ち始めるまで Wavelet を強くしていったのだが、その際のノイズの出方がずいぶん違う。

    7a_moon90

    上は過剰に Wavelet を適用したものだ。ふつう砂嵐的なノイズの出方になるが、フィルターを適用してあると偽像 (artifact) のような感じになる。砂粒の大きさが2倍になっただけなのだが、1つの砂粒を構成するピクセルが増えるため丸みを帯びてくる。そのため「ノイズが目立ち始める」ポイントが把握し辛い。言い換えればノイズが目立ちにくくなるようだ。

    7b_moon

    フィルターを適用した画像は、適用していない同じスタック画像数のものよりも1段画像数の多いものに近い仕上がりになっているように見える。スタック画像数2倍の効果が得られているようだが、同時に画質が少し劣化してしまったようだ。エッジが鈍くなったり小さなクレーターが大きくなったりしてしまっている。やはりカットオフの設定が低過ぎたようだ。

    カットオフをセンサー解像度の 70% にして比較をやり直してみた。

    8_fft_relative_filtered

    これなら意味のある信号の損失はほとんど無いはずだが、同時にノイズ除去効果も減少しているはずだ。

    8b_moon

    フィルターを適用したことによる画質劣化は無いと言ってよいだろう。またノイズ除去効果はこちらの方が優れている様に見える。画像がシャープになったのでその様な印象を受けるのだろう。スタック画像数 36 枚のものにフィルターを適用すると、私の眼にはフィルター無しの 64 枚より優れているように見えるし、フィルターあり 16 枚のでもフィルター無し 64 枚に肉薄している(これは少し苦しいか?)。

    重要なのは目で見た印象なので、これで良いと言うことだ。

    ちなみにフィルターを適用した n=4~36 の画像は、 Wavelet のレイヤー1以外は使う必要が無かった。また n=64 の画像ではハイライト部分が白トビ気味になるのを抑えるためレイヤー2以上に -5 を設定している。

     

    課題

    今回は機能の実現を優先したため、パフォーマンスは二の次になってしまった。そのため処理能力に課題を残している。

    今回 32bit 版 Python を使ったが、トリミングしていない X-M1 の画像 (16Mピクセル) はメモリー不足で扱えない。 3,200x2,700、つまり約 8M ピクセルが上限で、これは何とか今回の三日月が収まる大きさだ。これまでの比較は VGA サイズ (640x480) の画像を切り出して行った。処理のし易さを優先したデータの持ち方にしているのが原因だと考えられ、これを直せば同じ処理環境でも 24M ピクセル位まで対応できるのではないかと予想している。

    もう一つは処理速度だ。VGA サイズの画像の処理に 12秒かかっている。16M ピクセルの画像だと 10分位かかるはずだ。移動平均の係数行列の対称性を利用すると簡単に約 1/2 にできる。またアルゴリズムで頑張れば、マルチコアのような力技に頼らなくても更に 1/2~1/4、最終的に1分台に持ち込むことは可能ではないかと考えられる。なお計算量の多い部分は C のモジュールで行っているので Python を使ったことによる影響は2倍程度、フィルター処理を C または C++ で書くと1分を切れるかもしれない。

     

    代替手段について

    フィルターを使わなくても同じような効果の得られる機能が標準的なワークフローで使っているツールの中に隠れているかもしれない。もしそう言った機能で代替可能なら敢えてフィルターを使う必要は無い。あるいかそう言った機能があっても今回のフィルターを使うべきなら、そのことを明らかにしておく必要があるだろう。

    以前の記事を書いたときは代替手段を探しきれなかったが、今回改めて探すと2つ候補が見つかった。

    1つは現像ソフト「RAW FILE CONVERTER EX powered by SILKYPIX」の「ノイズリダクション」設定である。

    X8a_nr

    これまで使った画像は「ノイズ除去」の設定がゼロで現像されているが、これを強くするとどうなるかと言うことである。

    X8b_devel_nr

    RegiStax を使う前の、現像しただけの画像による比較だ。どうやら「ノイズ除去」の実体はぼかしらしい。ノイズが減る効果よりも画質が甘くなる弊害の方が大きい。もっとノイズの多い画像だと効き方が違うのかもしれないが、少なくとも今回の月面画像に使うべき機能ではない。

    もう一つ見つかったのは RegiStax の Wavelet で「Wavelet filter」で「Gaussian」を選んだ時に使える「Denoise」設定である。

    X8c_dn

    Wavelet 処理と同時にノイズ除去を行うと、かなり高い効果が得られる場合があるかもしれない。しかし少し試してみた感触では、これもガウスぼかしに近い挙動のような印象を受けた。従って FIR フィルターを併用する余地がありそうだ。

    今回の Wavelet filter は Default だ。ようかん氏から設定ファイルを提供していただいたので、それをそのまま使っている。 Gaussian に切り替えると Wavelet の効き方が全然変わってしまうので、一から設定をやり直すことが必要になる。こうなると定量的な比較うには相当な作業量が要るので、これ以上踏み込まないことにした。

     

    FIR フィルターの有効性と限界

    今回のように FIR フィルターが効果的なのは、望遠鏡の分解能がカメラのセンサー解像度を下回っている場合の様だ。今回の例では Fig. 2 に示したように望遠鏡の分解能はセンサー解像度の大体半分くらいになる。

    仮に2倍テレコンバーターを使わずに F8 だったと仮定すると、この場合の分解能はセンサー解像度とほぼ同じになるので意味のある信号の損失無しに LPF を適用することは不可能だ。カメラのセンサー上に結像する画像の大きさが半分になることを考えれば、何が起こるか容易に想像できるだろう。

    別の言い方をすると、今回の月面画像はオーバーサンプリング状態になっていた。オーバーサンプリングされた信号に LPF を適用して S/N 比を稼ぐのはデジタル信号処理でよく使われるテクニックである。この時多くの場合シャープなカットオフ特性を持つ FIR フィルターが使われる。

    大気の揺らぎが問題になる場合、望遠鏡の分解能ではなく揺らぎで大きくなった星像の大きさを基準に考えるべきかもしれない。ただしこれは主に大口径の望遠鏡の場合の問題だ。私には縁のない世界の話である。

     

    今回のまとめ

    F16 程度の光学系と 16 メガピクセル APS-C センサーの組み合わせで月面写真を撮る場合、FIR 型空間ローパスフィルターを利用するとスタック(コンポジット)画像数を2倍にしたのと同じ効果が得られることが分かった。光学系とセンサーの組み合わせについて有効な条件の範囲を予測できるが、被写体が異なる場合にどのような差異があるか不明である。これを明らかにするには更に実写で試す必要があるだろう。

    今回の記事は良質な元画像が多数あったことにより可能になった。文末ながら、画像など多数のデータを提供していただいた「ようかん」氏に謝意を表したい。

    ありがとうございます。

    続報: microSD カードの寿命を調べる

    $
    0
    0

    5日位で勝負がつくかもしれないと思って始めた実験だが、2か月近く経った今ようやく先が見えてきた。

    2015/2/21 23時追記あり。

    /*-----------  -----------*/

    最新状況

    Figure_1

    グラフ上に丸い点を打っているのがファイルを読んで書き込んだ内容と不一致が検出された場合を表している。磁気研究所(MAG-LAB)のサンプルのプロット(赤)の終わりの方に点が集中しているのが分かると思う。しかしプロットの線が途中で大きく落ち込んだことが目を引くので、そのことから触れることにしよう。

     

    空きスペース不足

    前半でプロットが威勢よく右肩上がりになっていたのは microSD カード上のルートファイルシステムの空き容量が少なくなることが主な原因だったらしい。磁気研究所のサンプルは書き込み量が 4T バイトを超えるあたりからプロットが急上昇し、頻繁に Linux がフリーズするようになったのでいよいよ終わりが見えたか、と思ったのだが間違いだった。

    嫌な予感がして df コマンドで調べたら、ファイルシステムの空きが 6.6M バイトまで減少している事が分かった。

    volumio@volumio220:~$ df -h
    Filesystem      Size  Used Avail Use% Mounted on
    rootfs          1.8G  1.7G  6.6M 100% /
    /dev/root       1.8G  1.7G  6.6M 100% /
    devtmpfs        248M     0  248M   0% /dev
    tmpfs            50M  516K   50M   2% /run
    tmpfs           5.0M     0  5.0M   0% /run/lock
    tmpfs           512M     0  512M   0% /run/shm
    Ramdisk         512M     0  512M   0% /run/shm
    

    4G バイトの micorSD に 2G バイト用の Volumio イメージを書き込んでテストを始めた時 150M バイト程度の空きだった。決して多くは無いが、ログは全てローテートされているから問題ないと考えルート区画のサイズは変更せずにテストを進めていたのだ。調べると「ログは全てローテートされている」と言う思い込みが間違いの元だったことが分かった。

    volumio@volumio220:/var/log$ ls -l
    total 133140
    (中略)
    -rw-rw-r-- 1 root        utmp     135851136 Feb  3 14:07 wtmp
    

    /var/log/wtmp はログイン履歴の記録だ。これはディフォルトでローテートされるようになっていない事を見落としていた。ログイン履歴を管理しないのでこのログが出ないようにしてしまっても構わなかったが、ほかにも似たようなことがあるかもしれないのでルート区画を microSD の容量いっぱいまで拡張した。そのためプロットに不連続が生じたという次第。お粗末でした(汗)。

    この後しばらく順調に推移したので、空きスペース不足が原因の問題だったと考えて間違いないだろう。

     

    比較エラーの状況

    比較で不一致が検出されるようになった部分を拡大した。

    Figure_2

    書き込み量が 8T バイトに達する少し手前で1回不一致が検出されているが、その後 1T バイト程度は何事もなく推移している。しかしその先で不一致が頻発するようになり、今では1セット 1G バイトの書き込み x 5で毎回不一致が検出されるようになっている。Transcend のプロット(緑)にも不一致が出始めたが、今のところ小康状態の様だ。

    磁気研究所のサンプルでは Linux のファイルも壊れてきているようで、起動時の「Waiting for /dev to be fully populated...」で長い時間待たされた挙句に alsactl の起動に失敗したり、 sudo が使えなくなったりしている。

    volumio@volumio220:~$ sudo ls /
    Illegal instruction
    volumio@volumio220:~$ su
    Password: 
    root@volumio220:/home/volumio# ls /
    bin   dev  home  lib64  mnt2  proc  run   selinux  sys  usr
    boot  etc  lib   mnt    opt   root  sbin  srv      tmp  var
    root@volumio220:/home/volumio# exit
    exit
    volumio@volumio220:~$
    

    su を使えばやりたいことができているのでテストを継続しているが、もう終わりにしても良い状況なのかもしれない。

    2015/2/21 23時 追記:
    この記事を書いてほんの数時間したらテストを継続できない状態になってしまった。テストプログラムを動かしている Python を起動しようとすると Segmentation fault が起こるようになってしまったのだ。

    volumio@volumio220:~$ python
    Segmentation fault
    volumio@volumio220:~$ su
    Password: 
    root@volumio220:/home/volumio# python
    Segmentation fault
    root@volumio220:/home/volumio#
    

    こうなると一巻の終わり。総書き込み量 9.3T バイトである。どんな状態になっているのか調べるために SDフォーマッター 4.0 (https://www.sdcard.org/jp/downloads/formatter_4/) で上書きフォーマットを行ったら全く問題なくできてしまった。試しに 6M バイトほどファイルをコピーして比較してみたが不一致は無い。常識的には正常と言うべき状態だ。しかし今までやってきたことを考えると、とてもそうは思えない。

    もっと詳しく調べて、改めて別の記事にしたいと思う。

     

    もう少し詳しいデータ

    区画を拡張したのと同じタイミングで1回の書き込みと読出し処理の時間を別々に測れるようにしてみた。

    Figure_3

    ここで目を引くのが、磁気研究所のサンプルの読出し時間が著しい増加傾向を示している事だ。現状では読出しの方が書き込みより時間がかかる状況が頻発しているが、他のサンプルではこのような状況は発生していない。

    読出しデータの不一致が発生する以前から一貫して同じ傾向を示しているので、寿命が尽きかけたことの表れではなく、このサンプルの個性なのだろう。磁気研究所のこの製品共通の特徴である可能性が高いが、1つしか試していないので断言することはできない。

     

    書き込み量モニタリングに不都合な真実

    今回書き込み量を把握するのに dumpe2fs と iostat コマンドを使っている。実際の運用時のモニタリングにも使えないか試す目的もある。

    前回の記事に Linux が異常終了した時 dumpe2fs が表示する Lifetime 値が更新されない、と言う問題があることを書いたが、これ以外にも困った現象が見つかってしまった。

    Mon Feb  9 20:08:19 JST 2015
    mmcblk0          77.28         0.80         3.99     418270    2090545
    Mon Feb  9 20:08:19 JST 2015
    Check OK!
    ## I/O time: operation total max min
    #WRT_256k  56.1   2.161   0.004
    #WRT_256M 160.6  54.090  52.587
    #RD_256k   54.4   2.015   0.049
    #RD_256M  141.9  47.444  47.012
    Mon Feb  9 20:30:40 JST 2015
    mmcblk0          77.27         0.80         3.99     419298    2095678
    Mon Feb  9 20:30:40 JST 2015
    Check OK!
    ## I/O time: operation total max min
    #WRT_256k  52.9   2.314   0.004
    #WRT_256M 164.6  55.750  53.982
    #RD_256k   53.6   2.017   0.049
    #RD_256M  142.4  47.460  47.448
    Mon Feb  9 20:52:30 JST 2015
    mmcblk0          77.27         0.80         0.01     420325       3659
    Mon Feb  9 20:52:30 JST 2015
    Check OK!
    ## I/O time: operation total max min
    #WRT_256k  52.5   1.956   0.003
    #WRT_256M 163.8  55.133  53.830
    #RD_256k   53.8   1.865   0.049
    #RD_256M  142.1  47.657  47.017
    Mon Feb  9 21:14:49 JST 2015
    mmcblk0          77.27         0.80         0.02     421352       8792
    

    これは実際のテスト用スクリプトが吐き出すログの抜粋で、「mmcblk0」で始まる行が「iostat -m | grep mmcblk0 | tee -a $log」の結果だ。つまり行の末尾の数字が Linux が起動して以来のメガバイト単位の書き込みデータ量なのだが、2095678の次が3659に減ってしまっている。

    これは推測だが、ディスク I/O の最小ブロックサイズである512バイト単位の値が 232-1 を超えるとゼロに戻ってしまうらしい。つまり 3659 = 2095678 + 5132 - {512 x (232-1) / 1024 / 1024} ではないか、と言うこと。

    (232-1) は符号無し32ビット整数の最大値だ。同様の現象が「dumpe2fs -h」の結果にも見られるので、kernel が管理している512 バイトブロック数単位の I/O カウンターがオーバーフローしているからではないかと推定している。

    今回のように継続的にログを取っていればこのような増えることはあっても減ることのない値のおかしな挙動は簡単に見つかるし、補正も可能である。確か iostat コマンドを含む sysstat パッケージはログを作成して継続的な監視を行うよう設定できたはずだ。こうすれば iostat または sar コマンドなどでもカウンターのオーバーフローへの対策が取れているのかもしれない。そうでないとサーバーで使うときに困るはずだ。これを調べるのは宿題にしよう。

     

    今回のまとめ

    テストを開始して2か月してようやく終わりが見えた。と言ってもまだ 1/4 だが。

    磁気研究所のサンプルはもう少しテストを続けて、最後にどうなるか見届けたいと思う。Linux がフリーズして、再起動を試みても一部のファイルが壊れていて起動しない、と言うシナリオになるだろうと予測しているが、もしかすると思いもつかない現象があるかもしれないからね。

    これまでの結果から microSD にその容量の 2,000 倍のデータを書き込んでも大丈夫、と言う感触が得られた。これは容量 4GB だとひたすら書き込みを続けて2ヶ月かかった作業だ。普通の使い方なら少なくとも1年間の連続稼働に匹敵するのではないかと思う。単純計算で容量 16GB なら 4年以上 OK と言うことになる。microSD 故に寿命が心配、と言うのは杞憂だろう。

    続報2: microSD カードの寿命を調べる

    $
    0
    0

    磁気研究所ブランドの microSD がついにご臨終になったようだが、Windows の環境で調べるとまだ大丈夫のように見える、と前回の記事に追記した。今回はその続きで、何が起こっているのか考察してみる。

    /*-----------  -----------*/

    テストプログラムを Windows で動かす

    テストプログラムは Python で書いていたので Windows 上でも動かすことができる。実際に試すとがっかりする結果になった。

    
    J:\>python wrt_chk.py
    Check OK!
    ## I/O time: operation total max min
    #WRT_256k 526.7   1.942   0.173
    #WRT_256M 1245.2 417.828 412.405
    #RD_256k    2.7   0.294   0.002
    #RD_256M    2.0   0.680   0.674
    
    J:\>
    

    結果に表示した処理時間は秒単位である。やたら書き込みに時間がかかっているが、これが寿命が尽きかけていることが原因なのかそうでないのか、新品の状態で同じテストを行っていないので分からない。

    がっかりしたのは読出しが異様に早く終わっていること。これは間違いなくキャッシュを読んでいる。Windows はストレージに書き込んだのと違うデータが読み出される事態を想定していないから、書き込みデータがキャッシュに残っていれば読み出しに行った時無条件にそれを返して来る。これではテストにならない。

     

    ATTO Disk Benchmark を使う

    これはディスクの I/O パフォーマンスを測るプログラムだが、Direct I/O に加えて I/O Comparison をサポートしている。書き込んだデータが正しく読み出せているか確認する機能である。ブロックサイズと総書き込み量は Python のテストプログラムに合わせた。

    Atto

    やはりこれだとエラーが山ほど出る。新品の SD カードやハードディスクでエラーが出ることはあり得ないので、テスト対象の microSD の寿命が尽きかけている事の表れと考えて間違いない。

    これは Direct I/O だから分かることだ。書き込んだデータを WinMerge などで普通に比較したのではエラーが見つからない。

    今回の記事の本題ではないが、製品の保証の事を考えるとこれは結構厄介な事態を引き起こすかもしれない。「パソコンで正常に読み書きできるなら製品は正常。うまく読み書きできないスマホ(or デジカメ etc.)に問題がある。」と言い逃れされそうな気がする。もちろん今回やったようなテストは「通常の使用」に該当するかどうかおおいに怪しいから、今話題にしている microSD の保証を求めるつもりはない。しかし実際に「通常の使用」中に同じような状態になったらどうだろう、と言うことである。

     

    microSD の寿命に関する数式モデル

    単純化して数式モデルを作ってみた。

    • C: microSD の総容量 [バイト]
    • Ds: テストで書き変わらないデータ量 [バイト]
    • W1: 1回のテストで書き込むデータ量 [バイト]
    • Wt: 寿命に到達するまでに書き込めるデータ量 [バイト]
    • WA: Write Amplification  [無単位]
    • E: 寿命 [消去&プログラム回数]

    バイト単位と表示したものは、同じ単位ならキロバイトでもメガバイトでも良い。テストプログラムは毎回同じファイル名で上書きする想定だ。

    • Wear Leveling を全く行っていない場合: E = Wt / W1
    • Dynamic Wear Leveling を行っている場合: E = WA × Wt / (C - Ds)
    • Static Wear Leveling を行っている場合: E = WA × Wt / C

    Wear Leveling を行っていない場合は単純に上書き回数が寿命になるはずだ。Dynamic Wear Leveling を行っている場合、書き込みは microSD の空き容量全体にまんべんなく行われるが、1回のテストでフラッシュメモリーに実際に書き込まれるデータ量は Write Amplification を考慮する必要がある。Static Wear Leveling なら書き込みは microSD 全体にまんべんなく行われる、と言うこと。

    今回行ったテスト条件と結果をこの数式モデルに当てはめると以下のようになる。

    • C = 4 × 109
    • Ds = 1 × 109
    • W1 = 10243
    • Wt = 9.3 × 1012

    WA と E の正確な値は分からない。今回の条件だと WA は1に近いと考えられる。また E は数千~1万程度と言われている。従ってこれらの情報からつじつまの合いそうなシナリオを考えることになる。

    WA ≒ 1 はかなり確実そうなのでこの通りと仮定し、各 Wear Leveling 方式の場合の E を計算してみよう。

    • Wear Leveling を全く行っていない場合: E = (9.3 × 1012) / (10243) ≒ 8,700
    • Dynamic Wear Leveling を行っている場合: E = 1 × (9.3 × 1012) / ( 4 × 109 - 1 × 109) ≒ 3,100
    • Static Wear Leveling を行っている場合: E = 1 × (9.3 × 1012) / (4 × 109) ≒ 2,300

    通常 E は数千の後半だと考えられるので、この結果から以下の可能性が考えられる。

    1. 仮定通り WA ≒ 1 で Wear Leveling を全く行っていない
    2. 仮定に反して WA = 2~3 で Dynamic Wear Leveling を行っている
    3. 仮定に反して WA = 3~4 で Static Wear Leveling を行っている
    4. 仮定通り WA ≒ 1 で何らかの Wear Leveling を行っているが、寿命の短いフラッシュメモリーを使っている

    ここで他の microSD サンプルとの関係を考えると W1 は全く同じ、C および Ds もほとんど同じである。そうなるとよほど特殊な事情が無い限り WA も同じになるはずだ。もしそうだとすると上記 2. および 3. の可能性はあまり無さそうだ。

    つまりこう言うこと。

    他のサンプルで現在の書き込み量が 1.6 × 1013バイト近くになっているものがある。このサンプルに上記可能性 2 および 3 の前提条件をである WA = 2~4 を当てはめて考えると、Static Wear Leveling を行っていて WE が2.5 以下の場合を除き E が1万を超えてしまうからである。

    従って WE は最大 2.5。この上限は現在の値で、テストが進むともっと小さくなる可能性がある。限りなく 1 に近い、と言う仮定が正しいようだ。磁気研究所ブランドのサンプルについては上記 1. または 4. の可能性が高い。

    問題は Wear Leveling を行っているかどうか。これを調べるにはそれなりに手間がかかるが、やってみる価値はあるだろう。

     

    Wear Leveling を全く行っていないかどうか調べる

    少量のデータを繰り返し上書きすると Wear Leveling を全く行っていない場合その領域は比較的短時間で寿命に達する。このことを利用して調べることができないか試した。

    ATTO でTotal Length を小さくすれば、現状でもほとんどエラーが出ることは無い。

    Atto2

    ATTO は指定したドライブのルートに benchtst.$$$ と言う固定した名前のファイルを作るのでテストを行う都度上書きしているはずだ。

    ここで Run Continuously にチェックを入れてテスト実行してみる。この場合実行時間を指定できる。1回のテストが約 12 秒かかるので 20 分を指定すれば約 100 回上書きを行っていることになる。まずこれでどの程度エラーが発生するか調べるのだが、実際にやってみるとエラーは全く発生しなかった。

    Atto3

    次に 200 分 ≒ 1,000 回を指定して繰り返しテスト行い、発生するエラー数がどのように変化するか調べた。比較的短時間と言っても 200 分 = 3 時間 20 分である。今までのテストに比べれば短時間、と言う意味だ。

    200 分の 11 回目でエラーが発生した。

    Atto20011

    しかし不一致情報はログされていない。またこの後エラーが引き続き発生することもなかったので microSD カードの接触不良のような一過性の問題だった可能性が高い。

    更にテストを続けると 200 分の 15 回目で不一致のエラーが記録され始めた。

    Atto20015

    この時のログの先頭は以下の通りだ。

    Friday, February 27, 2015   4:59 PM
    Running Untitled....
    Bench32 logged 542 errors for drive (j:)
    
    Transfer Size:	Buffer Index:	Expected Value:	Actual Value:
    256.0		8198		64D84512	64C84512
    256.0		8207		23252E8C	21256E8C
    256.0		8208		69B96B22	69B9EB22
    256.0		8209		57A75338	D7A75338
    256.0		8210		3E73535D	3C71535D
    256.0		8213		5AA54932	5AAD4932
    256.0		8215		13D22026	13D22226
    256.0		8219		237D6A88	237C6A88
    (以下省略)
    

    この後もエラーが出続けたので 17 回目を最後に打ち切った。15 回目は 542 件、16 回目は 2,385 件、17回目は 644 件エラーが発生した。

    200 分のテストでは 256k バイトのデータを約 1,000 回上書きしているので、書き込みデータ量としては 256M バイト弱である。15 回繰り返したことによる総書き込み量は約 375M バイトだ。

    僅か 375M バイト書き込んだだけでエラーが出始めたのは Wear Leveling を全く行っていない証拠、と言いたいところだが、この事実だけでそう言い切ることはできない。既に 9T バイトを超える書き込みテストを行っているので寿命を迎える直前の状態で今回のテストを始めた可能性を否定できないからだ。

    しかし 15 回目以降継続してエラーが発生するようになったことを併せて考えると、Wear Leveling を全く行っていない可能性がかなり高い、と言えるだろう。Wear Leveling を行っていれば毎回エラーが発生するような状況になるのはおかしいと考えられるからである。ただし全体として寿命に到達したため、それまで行っていた Wear Leveling を停止した可能性もある。

    結論:現状は Wear Leveling を全く行っていない可能性が高い。しかし新品状態でどうだったかについては分からない。

    数日の時間を費やしたが、残念ながら決定力に欠ける結果になってしまった。

     

    今回のまとめ

    テストを開始2か月で4サンプル中1つの結果が得られた。Wear Leveling を全く行っていないと考えてもおかしくない程度の結果である。

    そうなると、普通この程度は持つだろうと私が考えている結果が得られるのはまだ少し先、と言うことだ。気長に待つしかない。


    続報3: microSD カードの寿命を調べる

    $
    0
    0

    磁気研究所ブランドに続き、Silicon Powerブランド microSD の寿命が尽きたようである。磁気研究所ブランドのサンプルの状況は前々回および前回の記事を参照してほしい。

    /*-----------  -----------*/

    寿命が尽きるまでの状況

    最初に寿命が尽きた磁気研究所ブランドの microSD と似た経過をたどった。

    • 理由もなく時々 Linux が固まるようになった
    • テストプログラムが書き込んだデータを読みだしたとき不一致を検出するようになった
    • Linux が起動しなくなった

    最後の「Linux が起動しなくなった」と言うのは、具体的には以下のような状況である。

    U-Boot 2013.04-dirty (Jul 10 2013 - 14:02:53)
    
    I2C:   ready
    DRAM:  512 MiB
    WARNING: Caches not enabled
    NAND:  No NAND device found!!!
    0 MiB
    MMC:   OMAP SD/MMC: 0, OMAP SD/MMC: 1
    *** Warning - readenv() failed, using default environment
    
    musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, HB-ISO Tx, SoftConn)
    musb-hdrc: MHDRC RTL version 2.0 
    musb-hdrc: setup fifo_mode 4
    musb-hdrc: 28/31 max ep, 16384/16384 memory
    USB Peripheral mode controller at 47401000 using PIO, IRQ 0
    musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, HB-ISO Tx, SoftConn)
    musb-hdrc: MHDRC RTL version 2.0 
    musb-hdrc: setup fifo_mode 4
    musb-hdrc: 28/31 max ep, 16384/16384 memory
    USB Host mode controller at 47401800 using PIO, IRQ 0
    Net:   

    not set. Validating first E-fuse MAC cpsw, usb_ether Hit any key to stop autoboot:  0 gpio: pin 53 (gpio 53) value is 1 mmc0 is current device micro SD card found mmc0 is current device gpio: pin 54 (gpio 54) value is 1 SD/MMC found on device 0 reading uEnv.txt 808 bytes read in 4 ms (197.3 KiB/s) Loaded environment from uEnv.txt Importing environment from mmc ... Running uenvcmd ... mmc1(part 0) is current device mmc_send_cmd : timeout: No status update mmc0 is current device 3245640 bytes read in 676 ms (4.6 MiB/s) Booting from external microSD... 23801 bytes read in 50 ms (464.8 KiB/s) ## Flattened Device Tree blob at 80f80000    Booting using the fdt blob at 0x80f80000    Using Device Tree in place at 80f80000, end 80f88cf8 Starting kernel ... Uncompressing Linux... XZ-compressed data is corrupt -- System halted

    Linux kernel を起動しようとした時、kernel イメージの解凍に失敗しているようだ。
    磁気研究所ブランドのサンプルでは Python が動かなくなったが、これは壊れた場所が違うだけで、Linux を構成するファイルの一部が壊れたことに変わりない。

    不一致を検出した状況も磁気研究所ブランドのサンプルとさほど違わない。

    Figure_1

    不一致が出始めたあたりから拡大すると以下の様である。

    Figure_2

    読み書きの処理時間の推移は若干異なる。

    Figure_3

    不一致が発生するようになるのと同時に読み書きとも処理時間が急に増加し始めている。
    この現象をとらえれば microSD が寿命に到達したのを検出できそうだ。しかし今回は一定の条件でテストを繰り返しているから分かったが、通常の使用状況で検出するのはかなり難しそうである。

    今回寿命が尽きた Silicon Power ブランドのサンプルは 17.7x1012 バイト (16.1TB) 書き込んだあたりから兆候があり、19.86x1012 バイト (18.1TB) 書き込んだ時点で Linux が起動不能に陥った。この microSD カード全体の容量が3,974,743,744 バイトなので、 Linux が起動不能に陥るまでにカード容量の 5,000 倍を書き込んだことになる。

     

    寿命が尽きた後の状況

    磁気研究所ブランドのサンプル同様、SDフォーマッター4.0で上書きフォーマットを行うと一見マトモに使える。しかし ATTO Disk Benchmark で I/O Comparison を行うと比較エラーが出る状況である。

    Atto

     

    Ware Leveling について

    磁気研究所ブランドのサンプルについて、Ware Levelingの方式ごとに推定したフラッシュメモリーの消去・書き込みサイクル寿命は以下の通りだった。

    • Ware Leveling なし: 8,700
    • Dynamic Ware Leveling: 3,100
    • Static Ware Leveling: 2,300

    Silicon Power のサンプルは全く同じ条件でテストを行い、寿命が尽きるまでに磁気研究所ブランドのサンプルのほぼ2倍の書き込み量に到達しているので、上記数字を単純に2倍すればよいことになる。

    消去・書き込みサイクル寿命 17,400 はどう考えても大き過ぎるので、Ware Leveling を行っていないと言う可能性は除外してよいだろう。

    Dynamic Ware Leveling を行っていると仮定した場合の 6,200 はかなりそれらしい数字である。英語版 Wikipedia の Ware leveling の項に Dynamic Ware Leveling の典型的な使用例として USB Flash Drives が挙げられているが、microSD カードも同様ではないかと考えられる。

    Static Ware Leveling を行っていて消去・書き込み寿命 4,600 と言う可能性は否定できないが、Dynamic Ware Leveling を行っていると考えるのに比べると違和感がある。

     

    今回のまとめ

    Silicon Power ブランドのサンプルは全容量の 5,000 倍を書き込んで寿命が尽きた。去年の大晦日にテストを開始しているので、丸々5カ月の間休みなく書き込み続けた結果である。

    デジタルカメラのような使用パターン、容量いっぱい近くまで使い初期化するのを繰り返すのであれば、このサイクルを 5,000 回以上繰り返すことができる、と言う事だ。毎日初期化しても 13年以上なので、このような使い方には十分な寿命である。

    このサンプルは Dynamic Ware Leveling を行っていると考えられる。と言う事は、空き容量が極端に少ない状態でファイルの上書きを繰り返すと、割と短時間で寿命が尽きる可能性がある。これには注意する必要があるだろう。

    BBB などで使う場合、今回のテストの条件で使うと、休みなく書き込んでも5カ月程度使える。しかしこのような書き込みを行うと I/O 待ちがボトルネックになってレスポンスが極端に悪くなる。書き込み負荷が 1/2 またはそれ以下でないと実用にならないだろう。つまり実用的な使い方をしているなら、少なくとも1年くらいは今回の Silicon Power のサンプルは寿命に達しないはずである。

    BBB で長期安定運用を狙う場合、できるだけ容量の大きな microSD を空き容量の多い状態で使うのが手間がかからない割に効果的ではないかと思う。ちなみに BBB は 32GB までサポートしているようだ。使用量も含め全てが比例関係で8倍になるとすれば、今回と全く同じ条件で寿命が尽きるまで 40カ月かかる計算になる。実用的な条件なら 80カ月、6年以上である。

    32GB の microSD カードは1千円台半ばで入手できるから、費用が問題になる場合は多くないはずだ。

    前々回の記事に「2か月近く経った今ようやく先が見えてきた」と書いたが、これは見通しが甘かったようだ。

    最終回: microSD カードの寿命を調べる

    $
    0
    0

    残っていた Transcend と TOSHIBA ブランドの microSD だが、それぞれ6月25日と7月24日に寿命を迎えたようである。どちらも Linux が正常に起動しなくなったのだが、その状況は対照的だ。

    なおこれまでの経緯は以下の記事を参照してほしい。

    http://mitaka1954.cocolog-nifty.com/blog/2015/01/microsd-34a8.html
    http://mitaka1954.cocolog-nifty.com/blog/2015/02/microsd-43a6.html
    http://mitaka1954.cocolog-nifty.com/blog/2015/03/microsd-4ee4.html
    http://mitaka1954.cocolog-nifty.com/blog/2015/05/microsd-3dd7.html

    /*-----------  -----------*/

    テストログ

    寿命が尽きるまでの経過は、Transcend および TOSHIBA ブランドの製品とも、それ以前に寿命を迎えたサンプルとずいぶん異なっている。

    Figure_1

    テストプログラムが検出したエラーを丸点で示している。

    早く寿命を迎えたサンプルはエラーが多発している。

    それに対して Transcend ブランドの製品は割合と早い時期からエラーが散発的に発生しているが、多発することなく寿命を迎えた。また TOSHIBA ブランドの製品は、テストプログラムで一切エラーを検出できなかった。

     

    Transcend ブランドの製品が寿命を迎えた状況

    Linux が起動しなくなったのだが、その際コンソールに EXT4 ファイルシステムのエラーが記録されていた。

    [   29.908439] EXT4-fs error (device mmcblk0p2): __ext4_ext_check_block:480: inode #18155: comm nginx: bad header/extent: invalid magic - magic aacd, entries 57684, max 54277(0), depth 8871(0)
    [   29.944698] EXT4-fs error (device mmcblk0p2): __ext4_ext_check_block:480: inode #18155: comm nginx: bad header/extent: invalid magic - magic aacd, entries 57684, max 54277(0), depth 8871(0)
    [   29.979697] EXT4-fs error (device mmcblk0p2): __ext4_ext_check_block:480: inode #18155: comm nginx: bad header/extent: invalid magic - magic aacd, entries 57684, max 54277(0), depth 8871(0)
    [   30.003743] EXT4-fs error (device mmcblk0p2): __ext4_ext_check_block:480: inode #18155: comm nginx: bad header/extent: invalid magic - magic aacd, entries 57684, max 54277(0), depth 8871(0)

    Linux が起動しないので寿命と言う事で良いと判断し、以前行ったのと同じように SDフォーマッター4.0 で初期化して ATTO Disk Benchmark の I/O Comparison を 30 分間連続して行ってみたが全くエラーは発生しなかった。これだとイメージを書き直せばテスト継続できるはずだ。

    これは少々困った状況である。まだ完全に寿命を迎えた訳ではないのかもしれない。しかし極めて消極的な理由、これ以上テストを続けるのは疲れたと言う理由で、一旦致命的な状況になった事をもって寿命とすることにした。

    逆に厳しい見方をすると最初にエラーを検出した時点で寿命と言うべきかもしれないが、そののちかなりの期間あまり問題なく使えているので、これは少し厳し過ぎるだろうと判断した。

    ただし散発的であってもテストプログラムが検出できるエラーが発生するのはこのサンプルの問題である。

     

    TOSHIBA ブランドの製品が寿命を迎えた状況

    この場合 microSD に対する I/O のタイムアウト・エラーがコンソールに記録されていた。

    [    5.390514] mmcblk0: timed out sending r/w cmd command, card status 0x400900
    [    6.673604] mmcblk0: timed out sending r/w cmd command, card status 0x400900
    [    6.681031] mmcblk0: timed out sending r/w cmd command, card status 0x400900
    [    6.688443] mmcblk0: timed out sending r/w cmd command, card status 0x400900

    こうなってしまうと SDフォーマッター4.0 による初期化すらできない。完全に寿命を迎えたと迷いなく言える。

     

    全サンプルのまとめ

    今回はブランド毎に1サンプルしか試していないので、個体差による偶然の影響がある可能性を否定できない。これは統計的な可能性だ。しかしその一方で以下のような結果が得られた事実がある。従って異なる事実が見つかるまでは、今回得られた結果を、仮説として各ブランドの平均的な傾向だとすることに合理性があるはずだ。

    ブランドエラー発生開始寿命「寿命」の際の状況
    磁気研究所810再フォーマット可
    ATTO でエラー有
    Silicon Power1820再フォーマット可
    ATTO でエラー有
    Transcend1141再フォーマット可
    ATTO でエラー無し
    TOSHIBAなし61再フォーマット不可
    注:数値は書き込みデータ量概数(単位:1012バイト)

    私が次に microSD を買う場合の優先順は以下のように考えている。

    1. TOSHIBA
    2. 今回テストしなかったブランド
    3. Silicon Power
    4. Transcend

    磁気研究所ブランドは選択肢にない。「今回テストしかなったブランド」はブランドイメージの良いもの(例えば SanDisk )を選ぶ、と言う事である。

    TOSHIBA ブランドは寿命が長いが、寿命を迎えた時の状況にやや不安があるのは事実だ。他のブランドだといくつか読めないファイルが出て異常に気付けば大半のデータは回収可能だと考えられる。それに対して TOSHIBA ブランドの microSD が寿命を迎えた際に必ず今回と同じ状況になるようだとデータの回収は全く望めないからだ。ただこれはハードディスクがクラッシュするのと同じようなことなので、予めそのことを織り込んで運用すれば済むことだと思う。

    Transcend の順位が低いのは散発的にエラーが検出されたからだ。これがこのブランドの平均的傾向としてしまうのには若干抵抗を感じるが、氷山の一角かもしれないので、積極的にこのブランドを選ばなくてもよいだろう、と言う意味である。

    いずれにせよ microSD はテストを始める前に考えていたよりもはるかに長持ちする、と言うのが一番強い印象である。テストでは microSD はほぼ 100% Busy の状態で使っていた。通常の使用ではおそらく 10% よりも少ないと考えられる。また結果が早く得られるよう小さなカード容量(4GB)の製品を使ったことも考え合わせると、16GB の製品を使えば一番早く寿命を迎えたブランドと同じ条件を想定しても3年程度、一番長持ちしたものの条件だと 20年程度(!?)の稼働期間が期待できるからだ。

    カメラのファインダーについて考える

    $
    0
    0

    久しぶりの更新だ。
    今回はカメラのファインダーについて書こうと思う。

    以前の記事に「Fujifilm X-E2のファインダーがもの凄くイイけど、高いから買わない」と書いた。その続きのようなものである。ただし「やっぱり買っちゃいました~」と言う内容ではないので、期待した人には申し訳ないが悪しからず。

    今回のテーマは「使い易いファインダーってどんなのだろう」と言う事。
    主に一眼レフとEVF(電子式ファインダー)を対象に考えてみる。
    「見易い」のは「使い易い」の必要条件だが、多分それだけではない。

    /*-----------  -----------*/

    ファインダーの性能指標1: 視野率

    「撮影される画像の何%が見えるか」と言うもので、「100%が理想」と、実にわかりやすい性能指標だ。また同時に「ファインダーで見えているのに写らないものがあるのはケシカラン」と言うことで100%を超えるのはタブー視されている。

    現在製造されているデジタル一眼の場合、中~高価格帯の製品は視野率: 公称100%のものがほとんどで、Canonによれば実態は99±1%になっているとのこと。エントリークラスのデジタル一眼だと95%程度である。

    数字ではなかなか実感がわかないと思うので実例を見てみよう。

    Coverage

    これはファインダーの中を別のカメラで写した画像に、撮影した画像を半透明にして重ねたものだ。緑枠は撮影した画像、青枠はファインダー内に見える画像の大きさを表している。

    いちばん上に記載した数字はそれぞれの枠の画素単位の大きさを画像処理ソフト上で測り、それからファインダー視野率を計算している。なお上の画像はブログに掲載できるよう縮小しているので記載した数字と画素数が異なる。また計算は縦横それぞれの寸法で行う事などがCIPA(カメラ映像機器工業会)の「デジタルカメラの仕様に関するガイドライン(改訂版)」に規定されている。

    上の画像はPENTAX *ist DLの例で、計算値の縦横とも96%はカタログ通りである。

    ちなみにEVFは視野率100%であるものがほとんどだ。これは原理的に100%ピッタリにできる。ただし稀に100%でないものもあるので注意が必要である。

    最近は「ファインダー視野率100%でない一眼レフはダメ」とでもいうような風潮があるようだが、私の感覚では上の視野率96%で支障があるとは思えない。これは撮影スタイルや撮った後の画像の取扱い方によって変わるものなのだと思う。本当に視野率100%ピッタリのファインダーでないと支障のある人はEVFを使うべきである。

    赤枠は後程実例で紹介する銀塩・マニュアルフォーカス時代の一眼レフの視野率92%に相当する範囲を画像処理ソフトで描き加えたものだ。さすがにここまで余白が大きいと困りそうな印象だが、実際に問題になったことはほとんどない。詳細は後程述べる。

     

    ファインダーの性能指標2: 倍率

    もう一つの良く参照される指標である。「ファインダーを通してみた場合、肉眼の何倍に見えるか」と言うもので、望遠鏡の倍率と同じ考え方である。

    ところで「肉眼でものを見た場合の大きさ」をどう表すか?
    同じ物でも近くにあれば大きく見えるし、遠くにあれば小さく見える。

    「m」とか「mm」のような長さの単位では表せないので「見かけの角度」使う必要があり、倍率も角度の比で表すことになる。これは望遠鏡と全く同じである。ちなみに観察対象(被写体)の光学系内の位置が決まっている顕微鏡の倍率は、見えている虚像の大きさと観察対象の大きさの割り算で定義できる。しかし観察対象や被写体の位置が一定しない望遠鏡やカメラのファインダーではそうはいかない。

    下の図はファインダーを含む一眼レフの光学系を模式的に表したものだ。倍率に本質的に無関係な、像を正立させるためのフリップミラーとペンタプリズムまたはミラー、および性能や機能を向上させるためのコンデンサーレンズやスーパーインポーズ用の光学系など省略している。ただし実際には省略したそれらの要素が幾何学的・光学的な光路長に影響することを、最終的に加味することが必要である。

    Finder_mag

    結局近軸領域近似を使って寸法の比率で表すことができたが、本来これが成り立つのは光軸近傍の微小領域だけである。しかしご心配なく。実はこの結果をファインダー像全体に使えるのだ。実用的な程度にファインダー像に歪が無いと言う立場に立つと、倍率は像のすべての場所で同じになる。

    ペンタミラーを使っている場合L2は幾何学的寸法そのものだ。しかしペンタプリズムを使っている場合、光学的な光路長は幾何学的寸法よりも短くなる。従ってペンタプリズムを使ったほうがファインダー倍率を高くできる。厚みのあるガラスに垂直から多少ずれた角度で入射する光線の経路を考えれば、その理由を容易に理解できるはずである。

    ファインダー倍率が大きければ像が見易い。特に手動でピントを合わせるとき重要になる。ただ大きければ大きいほど良いのかと言えば、これは程度問題である。詳細は後程触れる。

     

    ファインダーの性能指標3: 視野角

    視野角はファインダー像全体に対する見かけの角度、前の図のθ2で、通常対角線の大きさに対するものである。

    ファインダーを覗いた時、第一印象としての見え方の大小は主に視野角の違いが原因であると考えられるが、視野率や倍率ほど話題にならない。一眼レフについて、最近後者はほぼ間違いなく公表されているが前者はそうでないことが原因だろう。

    また視野角は視野率、倍率および撮影される画像サイズから一意に計算できるので、視野率100%を絶対的な前提とすれば視野角と倍率の議論は定性的に同じと言えるのも事実だ。しかし今回は視野率が100%ではない昔のカメラや安価な一眼レフも話題にするので、視野角の性格を理解しておく必要がある。

    Field_size

    上に示した通り、視野角は視野率、倍率および撮影される画像の大きさから計算できる。顕微鏡に倣って明視の距離にある虚像を見ていると想定すれば、虚像の大きさも同じデータから計算することができる。

    さらに上の図から興味深いことが分かる。

    ファインダーで見えるフォーカシングスクリーンの大きさ(今後表現を簡素にするため「フォーカシングスクリーンの大きさ」をこの意味で使う)Bdが変化した際、フォーカシングスクリーン以降の光学系が相似形を維持して大きさを変えると仮定すると、視野角および虚像の大きさが一定になるのだ。相似形なのでBd/L2が一定になるからである。

    視野率を下げると倍率が上がり、結局相殺されて視野角は一定、とも言える。

    L2がペンタプリズムまたはミラー内部の光路長だけなら上の仮定が成り立つ余地があるが、実際はそうではない。今まで省略していたコンデンサーレンズの厚さやスーパーインポーズ用光学系などの光路長は比例関係で変化するとは考えられない。比例関係より変化が少ない、あるいは一定だと考えられる場合も少なくないだろう。そのためBdが小さくなると視野角は減少する傾向になることが予想され、現実にそのとおりになっている。

    もう一つ相似形を保てないと考える理由がある。仮に相似形を保って大きさを変えられたとすると、アイレリーフも比例して変化するはずである。小さくしていく場合を考えると、これは具合が悪い。一定以上のアイレリーフを保とうとすると相似形を崩さざるを得ないと考えられるからである。

     

    アイレリーフについて

    私は眼鏡を使っている。眼鏡をかけたままファインダーをのぞくには比較的長いアイレリーフが必要である。ただし必要なアイレリーフ長は見口付近の構造、例えばアイカップの構造やその有無などとの兼ね合いで変わるので、一律何mmあればOKと言えないのが悩ましい。

    アイレリーフが長すぎるのも意外と使いにくいものである。

    最近の製品にはないと思うが、昔数十mmのアイレリーフがあるファインダー売られていたようである。私はこのようなファインダーを使ったことがないが、同程度のアイレリーフを持つライフルスコープを使った経験からすると目の光軸合わせに慣れが必要だと思う。特にスコープ単体だと目安になるものがないので苦労するが、カメラのファインダーは常にこれと同じような状況になるのではないかと思う。

    今売られているカメラのファインダーのアイレリーフはせいぜい20mm台が上限のようなので、長すぎて困ることを心配する必要はなさそうである。

     

    最近のカメラの動向

    参考のため、現在新品で入手できるデジタル一眼レフカメラの光学ファインダーのデータをまとめてみた。なるべく新しいもの、と言うことで、未発売だが仕様が発表済のものも含めている。

    各社デジタル一眼 光学ファインダーの視野率と倍率
    ブランド型式サイズペンタ視野率
    [%]
    倍率視野角
    [deg 対角線]
    虚像サイズ
    [mm 対角線]
    (@明視距離)
    ※センサーサイズ
    [mm]
    (幅x高さx対角線)
    アイレリーフ
    [mm]
    (レンズ中心より)
    CanonEOS-1D X Mk2フルプリズム1000.7636.316435.9x23.9x43.120.0
    NikonD5フルプリズム1000.7234.515535.9x23.9x43.117.0
    PENTAXK-1フルプリズム1000.7033.615135.9x23.9x43.121.7
    CanonEOS 80DAPS-Cプリズム1000.9528.612722.3x14.9x26.822.0
    NikonD500APS-Cプリズム1001.0031.614123.5x15.7x28.316.0
    PENTAXK-3 IIAPS-Cプリズム1000.9530.013423.5x15.6x28.222.3
    CanonEOS-800DAPS-Cミラー950.8223.610422.3x14.9x26.819.0
    NikonD5500APS-Cミラー950.8224.811023.5x15.7x28.317.0
    PENTAXK-100DAPS-Cミラー960.8526.011523.5x15.7x28.321.5

    個別の論評や比較は避けるが、特に目を引くものについて補足しておく。

    35mmフルサイズのグループでCanon EOS-1D X Mk2がある程度長いアイレリーフを確保しながら視野角がとびぬけて大きい。同社のWebによればペンタプリズムに特別な高屈折率の素材を使っているとあるので、その効果の可能性がある。

     

    実際にファインダーの見え具合を確かめてみる

    私が調べられる範囲の、以下のカメラについてファインダーの見え方を調べてみた。

    ファインダー画像実写カメラ一覧
    ブランド型式発売年月
    PENTAXME Super1979年12月
    CONTAXT21999年11月
    PENTAX*ist DL2005年7月
    RICOHGX200+VF12008年7月
    SonyRX100M32014年5月
    PENTAXK-S22015年3月

    同じコンパクトカメラ・同じズーム状態(ワイド端)でファインダーの中を撮影した。これはケラレなどに関して眼鏡をかけてファインダーをのぞいた時の条件に近い。視野角を大まかに比較することができる。

    ファインダー全体の画像は最も視野角の大きいカメラのファインダーに合わせて全て同じようにトリミングし、ブログに掲載できる大きさまで縮小した。それに加えてファインダー中央付近を原寸、いわゆるピクセル等倍で切り出したものを詳細確認用に掲載している。

    以下発売の古い順に掲載する。

     

    PENTAX ME Super (1979年12月発売)

    項目備考
    画像フォーマット35mmフル
    画像サイズ43.3mm対角線
    ファインダー方式ペンタプリズム
    ファインダー視野率92%メーカー公表値
    ファインダー倍率0.95メーカー公表値 (50mm・∞)
    ファインダー視野角41.4°対角線
    虚像サイズ189mm対角線@明視距離

    Me_super

    Mesuper

    メイン機として使っているときは意識しなかったが、こうやって比べると実に広大なファインダーである。それに倍率0.95は突出して高い。なお上の写真ではME Superのピントが若干手前にずれていたはずである。

    マニュアルフォーカスしか無かったこの時代だからピント合わせを優先してこのようなファインダーになったのかと思い、同じ時代の他社製品と比較してみた。なお掲載したCanon製カメラでは上下と左右の視野率が異なるが、差はわずかなのでCIPAのガイドラインに従い計算した平均値を用いた。

    同時代他社製品との比較
    ブランド型式視野率
    [%]
    倍率視野角
    [deg 対角線]
    PENTAXME Super920.9541.4
    OlympusOM-1970.9242.2
    NikonF31000.838.2
    NikonFE930.8638.2
    CanonFE92.50.8236.3
    CanonA-194.40.8337.5

    どやら当時PENTAXがOlympusと小型軽量一眼で競い合っていた影響らしい。

    ボディ小型化のためフォーカシングスクリーン以降の光学系を簡素化した。そのため光路長が短縮され、大きな視野角になったのだと考えられる。PENTAXは小型化でOlympusの上を行くため視野率を下げた。こうするとペンタプリズム周りを小さくできる。その結果倍率が上がった、と言う事ではないかと思う。

    しかしこの広大な視野角は、少なくとも私には大き過ぎたようだ。左側のシャッター速度表示を見るためには視線を動かす必要がある。良好な視認性を確保するためには、画像周辺に配置されたファインダー内表示まで含めた視野角は40°位、画像部分だけなら視野角35°位が上限ではないかと思う。

    「なぜペンタミラーにしなかったのか」との思いがよぎったが、これは小型化に逆行するはずだとすぐ気づいた。ペンタミラーは鏡面の外側に剛性を保つための構造が必要である。そのため同じ大きさのフォーカシングスクリーンならペンタプリズムより大きくなってしまう。軽量化には貢献するものの小型化の役には立たない、と言う事らしい。

    前の方に「(視野率92%でも)実際に問題になったことはほとんどない。」と書いた。このカメラではほぼネガフィルムだけを使っていたことが原因ではないかと思う。

    ネガフィルムだと同時プリントのサービス判で最初に写り具合を確認することになる。コンタクトプリントは小さくてよく見えないと言う理由でこうしていた。印画紙の縦横比が3:2ではないため左右が有無を言わさずトリミングされる。またフィルムのコマの上下端に乱れがある場合に備えて縦方向にも若干トリミングされていたと思う。フチ無しならこの通りだが、フチ有でも上下左右のフチの幅はほぼ一定だったと記憶しているので、それが正しければフチ無し同様にトリミングされていたはずである。

    従って視野率92%のファインダーで見えていなかったものが写っていても多くの場合トリミングされてしまい、めでたしメデタシ、と言うことになっていたようだ。リバーサルフィルムで写した写真をプロジェクターで見るような使い方が多かったら違っていたと思う。

     

    CONTAX T2 (1999年11月発売)

    項目備考
    画像フォーマット35mmフル
    画像サイズ43.3mm対角線
    ファインダー方式逆ガリレオ+ブライトフレーム
    ファインダー視野率85%メーカー公表値 (対38mm画角@フレーム)
    ファインダー倍率0.60メーカー公表値 (38mm・∞)
    ファインダー視野角31.0°対角線 (∞@フレーム)
    虚像サイズ139mm対角線@明視距離

    Contax_t2

    Contaxt2

    実にヌケの良いファインダーである。フォーカシングスクリーンが無いことの効果が大きい。レンズの数が少なくて済む逆ガリレオ式であることも貢献している。

    なお視野率がブライトフレームを基準にしたものであることに注意してほしい。公表資料には明記されていないが、逆ガリレオ式の場合ファインダー像全体の位置と大きさがアイレリーフなどにより変化してしまうため、このように取り扱うことになっていたはずである。ファインダー像全体だと視野率は90%を超えていると思う。

    フレームが二重になっているが、外側が無限遠用、内側が最短撮影距離(0.7m)用である。撮影距離が近くなると視差が変わり、またレンズの繰り出しにより画角が減少することに合わせたものだ。

    今回調べてみてフォーカシングスクリーンの無いファインダーの良さを再認識した。

     

    PENTAX *ist DL (2005年7月発売)

    項目備考
    画像フォーマットAPS-C23.5mm x 15.7mm
    画像サイズ28.3mm対角線
    ファインダー方式ペンタミラー
    ファインダー視野率96%メーカー公表値
    ファインダー倍率0.85メーカー公表値 (50mm・∞)
    ファインダー視野角26.0°対角線
    虚像サイズ115mm対角線@明視距離
    アイレリーフ21.5mmメーカーFAQ

    Ist_dl

    Istdl

    APS-Cペンタミラー機なので倍率が小さく視野角も狭く、手動でピントを合わせるのは辛い。しかし「各社デジタル一眼 光学ファインダーの視野率と倍率」の節に掲載した表で同クラスの他社製品を見ると、このカメラはかなりマシな方であることが分かる。「PENTAXはファインダーを頑張っている」と言われる所以だろう。その副作用でファインダー像が暗いというようなことを読んだことがあるが、実際どうなのか未確認である。

    四隅が暗くなっているのはケラレが生じているためだ。眼鏡をかけて使う場合はアイカップを外すべきなのかもしれない。

     

    RICOH GX200+VF1 (2008年7月発売)

    項目備考
    画像フォーマット1/1.7"7.5mm x 5.6mm
    画像サイズ9.6mm対角線
    ファインダー方式電子式 (EVF)液晶ビューファインダー (VF-1)
    ファインダー視野率100%メーカー公表値
    ファインダー倍率0.234メーカー公表値 (ワイド端)
    ファインダー視野角22.5°メーカー公表値
    虚像サイズ100mm対角線@明視距離
    アイレリーフ13.6mmメーカー公表値 (接眼枠から)
    表示画素数約20.1万ドット相当 メーカー公表値 (3x299x224?)

    Gx200

    Gx200_2

    「EVFのついた撮像素子の(比較的)大きなコンパクトカメラ」と言う製品ジャンルに先鞭をつけた製品である。その意義は大きいと思うが、いかんせん見辛いEVFであまり使ったことがない。

    ファインダーの視野角が小さいことが原因だと思っていたが、上の原寸画像を見ると画素数、つまり解像度が圧倒的に足りていなかったのだと分かった。RGB 3ドットで1画素だとするとQVGAよりも小さい。対角線を基準にすると、iPhone5の画面を目の前に置いているのと同じ大きさの虚像を見ていることを考えれば約20.1万ドットでは到底足りない。

    GX200背面の液晶モニターが2.5型で約46万ドットなので、これまたアンバランスだ。
    このファインダーではどんな画像が撮影されるか想像するのが難しい場合がある。それでは困る。

    発売当時の技術で、妥当なコストで作ることのできるEVFはこの程度が限界だったのかもしれない。今日の基準ならVGA解像度相当の約92万ドットが許容できる最低ラインではないかと思う。

    このEVFをほとんど使わなかったもう一つの理由は外付けだったからだ。カメラ自体コンパクトなのでジャケットやコートのポケットに入れて持ち歩きたい。しかしEVFを付けてしまうと引っかかって出し入れしづらくなるし、さらにその際うっかり壊してしまいそうである。そのため稀に使う場合は都度着脱していたが、これは結構煩雑である。ネックストラップでぶら下げるようなサイズのカメラだったらEVFを付けっぱなしでも良かったのかもしれない。

     

    Sony RX100M3 (2014年5月発売)

    項目備考
    画像フォーマット1"13.2mm x 8.8mm
    画像サイズ15.9mm対角線
    ファインダー方式電子式 (EVF)
    ファインダー視野率100%メーカー公表値
    ファインダー倍率0.59メーカー公表値 (35mm判換算、50mm・∞)
    ファインダー視野角27.5°対角線
    虚像サイズ122mm対角線@明視距離
    アイレリーフ19.2mmメーカー公表値 (接眼枠から)
    表示画素数144万ドットメーカー公表値 (3x750x640?)

    R100m3

    Rx100m3

    最近のEVFの標準的品質と言えるのではないかと思っている。まだ一眼レフの光学ファインダーに及ばない印象だが、かなりのところまで肉薄している。M4では解像度が上がり、X-E2に匹敵する仕様になっているから、一眼レフの光学ファインダーとそん色無い水準に達したのではないだろうか。

    ちなみに一眼レフの光学ファインダーはマット面の粒状性の制限があるので、意外と解像度は高くないのではないかと考えている。

    普段はボディに収まっていて必要な時にだけポップアップするのは、この小さなカメラの携帯性をスポイルしない工夫だ。これは実によい。いかにもSonyらしい印象だ。

    改善してほしい点もあるが、今後ファインダーは光学式からEVFに移る流れを確信できるような製品である。

     

    PENTAX K-S2 (2015年3月発売)

    項目備考
    画像フォーマットAPS-C23.5mm x 15.6mm
    画像サイズ28.2mm対角線
    ファインダー方式ペンタプリズム
    ファインダー視野率100%メーカー公表値
    ファインダー倍率0.95メーカー公表値 (50mm・∞)
    ファインダー視野角30.0°対角線
    虚像サイズ134mm対角線@明視距離
    アイレリーフ20.5mmメーカー公表値 (接眼枠から)

    Ks2

    Ks2_2

    APS-Cペンタプリズム機では標準的な大きさのファインダーである。決して広々としているわけではないが、手動でピント合わせも普通にできる。

    上の両角と下側のファインダー内表示にケラレが見られる。このカメラも眼鏡着用時はアイカップを外した方が快適に使えるかもしれない。

     

    今回のまとめ

    見やすいファインダーの条件は視野率 100%で倍率はできるだけ大きく、ただし視野角35°以内と言うことになる。視野率100%は絶対の条件ではなく、写真を楽しむスタイル次第で95%でも全く問題ない場合もあるだろう。

    視野率100%で視野角35°の場合の倍率は:

    • 35mmフルサイズ: 0.73
    • APS-C: 約1.1

    である。

    35mmフルサイズは現実の製品がほぼ上記の条件に合致するが、APS-Cの場合現状より倍率を上げて見えやすくする余地があると言えるだろう。ただしアイレリーフなど他に制限となる要素があるかもしれず、また製品戦略上フルサイズ機とは差別化が必要と考えるかもしれない。

    以上は光学式ファインダーを念頭に置いたものだ。EVFの場合も「35mmフルサイズ換算」で考えた場合に「見やすいファインダーの条件」がそのまま当てはまる。

    EVFの場合さらに解像度の問題がある。現在新品を入手できる高倍率ズームレンズを搭載したコンパクト機に20万ドット前後のEVFを搭載したものが多数あるが、これはお勧めできない。私見だが約92万ドットと表示しているものが最低ラインである。現在存在する製品に関する限りドット数が多いほど良いと言える。後はサイフと相談、だろうか。

    これまた私見だが、コンパクトカメラで外付けEVFが使える製品であっても、よほど何かそれ以外に魅力的な事が無い限りその製品を選ぶべきではない。何であれ外付けアクセサリーを使う前提だと、コンパクトカメラはもはや「コンパクト」ではなくなると肝に銘じるべきだ。

    さらに私見をもう一つ。今後カメラのファインダーはEVFが主流になる。光学式ファインダーが無くなるとは思わないが、趣味性の高いニッチな製品限定でしか残らないだろう。実用的な意味で高性能・高機能なカメラは全てEVFを搭載するようになる。光学ファインダー搭載機はその製品の性格と販売数からかなり高価になるが、性能・機能的にEVF搭載機の後塵を拝むことになるはずだ。現在の製品の水準差と技術の伸びしろの違いを考えると、光学ファインダーでよほど画期的な技術革新が起こらない限り、この結論にしかならないはずだ。

    DSDはピアノ・ピアニッシモを奏でられるのか?

    $
    0
    0
    きっかけは20年ほど前の論文を読んだこと。
    小型電気炉の温度をPID制御するのに、出力をΔ-Σ変調したオン・オフ信号にしても全然問題なく制御できる、と言った内容。

    Δ-Σ変調器 (DSM: Delta-Sigma Modulator) は少ないオーバーサンプリング率の1ビットADCから十分な分解能が得られる技術と理解していた。これは主に周波数領域で考えた場合の理解である。これを時系列領域に読み替えると「同じ分解能を得るために必要な遅れが少ない」になる。なるほど。またADCだけでなくDACにも使える。確かに。

    数百円以内で入手できるマイクロコントローラーでDACが用意されているものは稀である。アナログ出力が必要な場合PWMが使われる場合が多い。これをソフトウエアで実装したDSMで置き換えることが有効な場合がありそうだ。

    電話音声品質程度ならオーディオ出力用にも使えるかもしれないと思い、容易に実装できる一次DSMについて調べたのだが意外とダイナミックレンジが狭い。同じ技術に基づくDSDやSACDは大丈夫だろうか、と少し詳しく調べてみた。

    今回調べたのはデジタル信号処理方式としての特性である。ダイナミックレンジやS/N比は、計算で好きなだけビット幅の大きな信号を生成できるような、全くノイズを含まない信号源を想定した場合の議論だ。実際のオーディオソースのようにもともとノイズを含んでいたり、アナログ部分でノイズを発生したりすることは考慮していない。

    /*-----------  -----------*/

    一次 DSM

    一次DSMはノイズシェーピングが弱いのでオーディオ信号用に使われることはまず無いが、動作を直感的に理解しやすいので手始めには好適である。また構成にバリエーションの余地がほとんど無いのも都合が良い。

    fig.1はz変換で表した一次DSMだ。

    Fig1

    実は私があまりなじみないのでz変換形式だけだとやや心許ない。fig.1のzで表した箱の内訳を書き直したのがfig.2である。

    Fig2

    上段が一次DSMで使っているもので、積分器の後ろに遅れ要素が一つ入った形だ。下段は若干結線を変えると遅れ要素の無い積分器になる、と言うもの。これは後程二次および三次DSMで登場する。

     

    一次DSMのシミュレーション

    非常に簡単な仕組みなので中核を成す部分は数行で書き表せる。これは使うプログラミング言語にあまり関係ないだろう。しかしシミュレーションとなると入力データを準備したり結果を表示したりする部分が馬鹿にならない。

    DSDやSACDを念頭に、以下の条件でシミュレーションを行った。

    • DSM動作周波数: 44.1kHz x 64 = 2.8224MHz
    • 入力信号: 1kHz, -6dbFS
    • シミュレーション時間: 0.1秒 (FFT分解能10Hz)

    DSDやSACDの場合、歪を避けるため最大信号レベルが-6db になっているという記述があったため、このシミュレーションでもそれに合わせた。

    Fig3a

    ノイズフロアが約-90dbと読み取れる。この時の入出力波形は以下のとおりである。

    Fig3b

    上段のグラフではほとんどベタ塗になってしまったが、青がDSM出力、赤は隣接するサンプル2つずつの移動平均で、こうすると正味のパルス密度変調波形が得られる。正味パルス密度変調波形は、元の波形と同じ極性だけに出ているのが特徴的だ。

    以上の結果に特に不思議なところはない。しかしノイズフロアから1kHz付近のダイナミックレンジは約84db (= -6db - (-90db) ) だと考えたのだが、これが違っていた。

    入力信号レベルを-90dbFSにするとマトモな信号が出てこない。少しずつレベルを変えて探った、ぎりぎりマトモそうな信号が得られる限界は約-56dbFSだった。ダイナミックレンジとして50dbである。

    Fig4a

    Fig4b

    なぜノイズフロアより34db (50倍) も高いレベルなのかはさておき、これが限界なのは割と簡単に説明できる。

    fig.3bの赤のグラフのようなパルス密度変調で表現できるアナログ信号レベルは、ゼロの次に絶対値が小さいのは元の波形半分当たり正味のパルス1個の場合である。動作周波数2.8224MHzで1kHzの信号を表現しようとしているので、元の波形半分当たりのパルス数は最大1,411.2個である。個数に端数があるのは十分長い時間の平均値と言う意味だ。元の波形が矩形波なら表現可能な最低レベルは1/1411.2だが実際は正弦波なので、矩形波と正弦波の面積の比2/πを掛けて約1/898が得られる。

    1/898は-59dbFSだ。これは理論値であり、安定に動作させるため3db余計に高いレベルにする必要があった、と考えれば良さそうである。

    fig.4bから、この場合の出力には高調波が盛大に含まれていることが分かる。奇数次・偶数次両方の高調波が出ていたり、20kHzより上の周波数でレベルが下がっていたりしているので、完全に0.5ms毎に正負のインパルスが交互に出ているのではなく、若干バラついているのだと考えられる。いずれにせよ歪率 (THD) は100%を超えている。

    なお「ノイズフロア」と呼んでいるものの実体は通常「量子化雑音」と呼ばれるものである。振る舞いが雑音的なのでそう呼ぶのにあまり違和感がないが、「量子化誤差」と呼ぶ方がより正確ではないかと思う。無音、つまり入力信号が継続してゼロの場合誤差の発生する余地がなく、ノイズフロアは観察できない。アナログ回路と対比した場合「雑音」よりも「歪」と言った方がより近いはずだが、慣例的に「雑音・ノイズ」と言う場合が多いので、この記事でもその呼び方を使うことにした。

     

    二次及び三次DSMの場合

    二次以上のDSMは様々なバリエーションがあり得る。これは次数が上がるほど顕著だ。今回はなるべくシンプルな構成を探し、以下の情報を参考にした。
    http://classes.engr.oregonstate.edu/eecs/spring2016/ece627/lecturenotes.html (このページの#22)
    http://www.eetimes.com/document.asp?doc_id=1207238

    Fig5

    Fig6

    fig.6のa23を通るフィードバック経路はノイズシェーピング特性にゼロを作り目的帯域内のノイズパワーを減らすためのようだ。a23のゲインを大きくするほどゼロの周波数が上昇する。図示した最大値1/9は参考資料に記載されていた値である。今回はこれを使わず、基本的な特性を調べた。条件は一次DSMの場合と同じである。

    なおこの三次DSMは入力信号が-6dbFSを超えて0dbFSに近づくと動作が破たんする。前に触れた「歪を避けるため最大信号レベルが-6db になっている」と言う記述はこのような現象を指していたのかもしれない。

    Fig7a

    グラフから読み取ったノイズフロアは、二次が-148dbFS、三次が-185dbFSである。

    Fig7b

    二次DSMの場合、正味のパルス密度変調波形を得るためには4区間の移動平均をとる必要がある。絶対値が0.5のパルスが見られること、および正負のパルスが混在する区間があることが一次DSMと比べた際の大きな違いである。

    Fig7c

    三次DSMの場合4区間の移動平均が正味のパルス密度変調波形を正確に表しているかどうか確信はないが、それに関連した波形を示しているものと考えられ、一応の目安になるはずだ。一次DSMとは明らかに違うが、二次DSMとの違いはこのグラフからはよくわからない。

    一次DSM同様にぎりぎりマトモそうな波形の得られる最小信号レベルを探った結果、二次は-120dbFS (ダイナミックレンジ114db)、三次は-180dbFS (ダイナミックレンジ174db) だった。どちらも十分小さなレベルまで再現できているので詳細な波形は省略する。ただし二次DSMではノイズフロアより28db高い値にとどまっている。これは一次DSMが34dbだったのと有意差があると言えるかどうか怪しい。その一方三次DSMではノイズフロアとあまり違わない信号レベルまで再現できている。これはこれで後の議論に謎を残す原因となる。

     

    ノイズフロアとダイナミックレンジ、分解能 (有効ビット数)

    そもそもノイズフロアって何だろうと問うた時、結構怪しいものであることに考え至った。このことが一番よくわかりそうなのがCD品質のLPCM信号のノイズフロアである。今回一連のDSMと同じ条件でノイズフロアを調べた結果が以下の図である。

    Fig8

    図からノイズフロアは-120db前後と読み取れる。LPCMだと最大信号レベルは0dbFSまでOKなので、ノイズフロアが基準になると考えるとダイナミックレンジは120dbと言う事になる。しかしその一方で16ビットLPCMのダイナミックレンジは概ね96db (= 16 x 6db) だと言う事実がある。この食い違いは重大な違いを無視したことに原因がある。

    LPCMの分解能やダイナミックレンジを考える場合、量子化雑音 (量子化誤差) 全体の電力を考えなくてはならない。しかし FFTの結果では量子化雑音は狭い周波数範囲 (上の例では10Hz) 毎に分割されてしまうので概ね分割数だけ小さくなる。これは量子化雑音が周波数全体にわたって概ね均一に分布していると考えられるからである。その一方目的信号は周波数的な広がりがないので、個々のFFT結果の周波数範囲がいくら小さくてもレベルは小さくならない。

    必要帯域の上限周波数を20kHzとし、FFT分解能が10Hzだと、ノイズフロアは全量子化ノイズ電力よりも約33db低く見えることになる。これをfig.8に当てはめるとノイズフロアは-129dbに見えるはずである。先ほどの数値は9dbほど高いが、目見当なので必要以上にグラフのピーク部分に注目してしまっていた可能性が考えられる。

    つまりFFT結果を目で見て得たノイズフロアはダイナミックレンジの基準には使えない値である (そもそも「目で見て」の時点で相当怪しい)。またADC分解能 (ビット数) もこのノイズフロアから計算するのは不適当だ。

    ここまでの議論を踏まえると三次DSMで1kHzの信号がノイズフロア近くのレベルまで再現できたのがうまく説明できない。次数が3以上のDSMだと何か特別な事情があるのかもしれないが、それが何なのか含め謎である。

    それはさておき、

    SDMのダイナミックレンジや有効ビット数を求めるには必要周波数帯域内の全量子化雑音電力を基準にする必要がある、と言うことである。具体的な方法を考えると、

    • FFT結果からパワースペクトラムを求め、必要帯域内の合計を得る (合計電力: Pt、合計したFFTスペクトルの数: Nt)
    • 目的信号を含むスペクトラムの合計電力を計算する (ここで得た合計電力: Ps、合計に使ったスペクトル数: Ns)
    • ノイズ電力 Pn の計算: Pn = Nt x (Pt – Ps) / (Nt – Ns)
    • S/N比: SNR = 10 x log10(Ps/Pn) [db]
    • 有効ビット数: ENOB = (SNR – 1.76) / 6.02 [bit]

    今回調べた条件で、DSMとLPCMについて必要周波数帯域の上限を20kHzとした場合の有効ビット数を計算した結果は以下のとおりである。

    • DSM1:  7.2 [bit]
    • DSM2: 11.2 [bit]
    • DSM3: 13.2 [bit]
    • LPCM: 14.6 [bit]

    DSMはこれが実力だが、LPCMは信号レベルが最大値の半分なので1ビット少ない結果になっている。これを見る限りオーディオ信号を扱うには、DSMの次数は3では足りない、と言う事になる。三次DSMで係数を変えてゼロを持たせると1ビット強分解能が向上するがまだ足りない。

    ただしこの結論と若干矛盾する興味深い事実があった。二次または三次DSMは1kHz の信号を16ビットLPCMよりはるかに低いレベルまで再現できることが分かっている。もしかするとDSDやSACDが「情報量が多い」と評価される原因はこのことにあるのかもしれない。

     

    比較対象はCD品質で良いのか

    今回試したDSDやSACDの毎秒2,822,100ビット (1チャンネル当たり) は通常のCD: 44.1kHz x 16bit = 毎秒705,600ビットに比べて4倍の情報量になる。これだけ情報量の違うもの同士を比べるのはどう考えてもフェアでない。

    また毎秒2,822,100ビットは96kHz/24bit LPCMの毎秒2,30,400ビットよりもまだ大きいが、かなり近いので、比較対象とするのはこちらだろう。と言う事で96kHz/24bit LPCMについて調べてみた。比較のため44.1kHz/16bit LPCMおよび三次DSMも一緒にプロットしている。

    Fig9

    ダイナミックレンジの非常に広い範囲を見ているので、目的信号周辺は窓関数の特性 (サイドローブ) が顕著に見えてしまっていることにご留意されたい。

    三次DSMは可聴領域上端およびそれより高い周波数のノイズフロアが44.1kHz/16bit LPCMよりも高くなっている。DSDなどで利用されるであろうもっと次数が高く最適化されたDSMは今問題にしている部分のノイズフロアがもっと低くなっているものと考えられるが、96kHz/24bit LPCMのナイキスとバンド内でそれに匹敵する水準になっているとは考えにくい。現実の音楽ソースなどを考えると無意味に低いレベルだと考えられるからだ。

    DSDやSACDの信号は可聴域上端付近から96kHz/24bit LPCMの上限周波数までの範囲で、本来の波形にない信号を96kHz/24bit LPCMと比較してより多く含んでいる可能性があり、これは本来の波形に忠実ではないと言う事である。つまりHiFiではい、と言う事。ただしこの事がDSDやSACDにとって聴感上プラスに働く場合があるかもしれない。

    また96kHz/24bit LPCMが再現できるもっとも小さな信号レベルは-145dbFS程度だが、三次DSMでも-180dbFS程度のレベルの信号を再現できる可能性がある。

    ただどちらもCD品質信号のダイナミックレンジの下限をはるかに下回る信号レベルの領域の現象だ。これらの違いを耳で聴き分けられるようにするには、色々な装置に相当お金をつぎ込まないと到達できないような気もする。たぶん私には無縁の世界だろう。

     

    今回のまとめ

    今回の表題「DSDはピアノ・ピアニッシモを奏でられるのか?」の答えは「安心してください。ちゃんと奏でられてますよ」だろうか。陳腐なギャグはさておき、

    DSDやSACDの技術を直接調べていない。それらと同じ原理で動いていてより性能が低いと考えられる三次DSMを調べて、可聴周波数範囲の重要な領域で通常のCDのダイナミックレンジ下限を下回る信号が再現可能であることが確認できたと思う。

    そもそものきっかけだったフィードバック制御系の操作信号に使うのは、残念ながら具体的な用途が簡単には思いつかないが、数百円のマイクロコントローラーで加熱炉よりもっと速い応答が必要な制御対象にも使えるPIDコントローラーが組めそうな感触がある。

    また音声信号出力に使うことを考えた場合、この用途にはデジタル音声信号をDSMの動作周波数までオーバーサンプリングするための補間器も必要なので、数百円のマイクロコントローラーで実現するのは厳しいかもしれないが、200MHzのクロックで動作しているBBBのPRUなら何とかなりそうな気もする。

    ヤマハルーターのL2TP/IPsecが遅い

    $
    0
    0

    中古のRTX1100を入手して自宅LANにリモートアクセスするためのVPNサーバーを構築してみた。iperf3でスループットを測ると10Mbpsを切っている・・・ナンデ?!

    /*-----------  -----------*/

    試したこと

    以下のWebを参考にさせてもらいVPNサーバーを構築した。

    「Eleclog (見習い赤魔道士のメモ帳): RTX1100をVPNサーバとして使う」
    http://eleclog.quitsq.com/2015/04/rtx1100-vpnserver.html

    Setup

    既存環境への影響を最小限にするにはVPNルーターではなくサーバーとして構築した方が好都合だし、いろいろとテストするにもグローバルIPの世界まで出ていかなくても済む。ただしインターネットとつないでいるルーターの機能を兼ねることも可能なので、結果が良ければそうすることも視野に入れていた。

     

    こんなものらしい

    RTX110のカタログ仕様によるとIPsecスループットは最大120Mbit/s (AES+SHA1、双方向)である。L2TPを併用しているとは言え10Mbpsに届かないのは何かおかしいのではないか?

    もちろん真っ先に設定の間違いを疑ったわけだが、半時間ほどGoogleして、そうではないらしいことが分かった。

    2014年11月25日のRBB TODAYの記事「最大2Gbpsを実現!ヤマハの新VPNルータ「RTX1210」の特徴とは(後編)」にRTX1100を含む歴代VPNルーターの速度比較スライドの写真があり、その中にL2TP/IPsecスループットに関するものが含まれていた。

    L2TP/IPsec VPNパフォーマンス比較
    モデルL2TP/IPsecスループット
    スライド写真から読み取り
    IPsecスループット
    カタログ値(双方向)
    RTX110013Mbps120Mbps
    RTX120025Mbps200Mbps
    RTX121040Mbps1.5Gbps

    L2TP/IPsecのスループットはIPsecのカタログ値の1/10~1/40位になる、と言うこと。RTX1100でL2TP/IPsecスループットを測っているときWeb AssistanceでCPU利用率を見るとほぼ100%に張り付いていた。明らかなCPUボトルネックである。カタログと実態、および双方向と片道の違いで説明できる差ではない。

    RTX1100のCPUはMIPS32/200MHzとかなり非力であることを考えると、純然たるIPsecについてはCPUがほとんど介在すること無く処理できるようなハードウエアが用意されているのではないか。そうでなければこのCPUで120MbpsのIPsecスループットは実現できるとは思えない。RTX1210およびRTX1200でも似たような事情ではないかと思う。

    私が試した結果は紹介したWebの数値より遅いが、インターネット接続用を念頭にフィルター定義なども一緒に設定してしまったためだと思う。

    なおRTX1100の暗号化サポートはAES128/SHA1までだ。AES256/SHA2はサポートしていない。パフォーマンスを測ったときのVPN接続はAES128-CBCで暗号化されていることを確認している。これなら当面問題ないはずである。

    VPNはいわゆる格安SIMを使ったモバイルネットワークでつなぐことになるが、少し混雑した場所だと結構遅いので、RTX1100のスループットはあまり問題にならないのかもしれない。しかし利用者が少なければ下りで20Mbps台の実力はあるので、できればVPNもこのくらいのスループットが得られるとうれしい。

    他の方法を試してみることにした。

     

    代案

    Beaglebone Black (以下BBBと略)およびOrange Pi Plus2 (以下OPiと略)を使いL2TP/IPsec およびIKEv2 VPNサーバーを構築してどのくらいのスループットが得られるか調べてみた。また同時にCPUの負荷も測った。負荷があまり高くなければ他の機能、例えばNASなど、を兼用させる余地も出てくる。

    CPU負荷測定はsarコマンドを使い、1分間スループットを測定する期間の中ほど30秒間について測った。表に記載していない分類 (ni, wa, hi, & st) は全てゼロだった。

    BBB とOPiはあまりポピュラーではないと思う。それぞれRaspberry Piの1 Model Bおよび3 Model Bに相当するような構成で、CPU性能が何割か高い – 倍までは届かない – ようなものと私は理解している。どちらも暗号処理ハードウエアを持っているが、SoftEtherでは使われていない可能性がある。なおOPiのイーサネットはGBE(ギガビット)である。

    それぞれ使用したLinuxイメージは以下のとおりだ。カーネルは特に再構築などは行わず、以下記載の通りイメージ付属のものをそのまま使っている。

    ファイル名: bone-debian-8.7-iot-armhf-2017-03-19-4gb.img.xz
    Web: https://rcn-ee.com/rootfs/bb.org/testing/2017-03-19/iot/
    Kernel: 4.4.54-ti-r93

    ファイル名: Armbian_5.25_Orangepiplus_Debian_jessie_default_3.4.113.7z
    Web: https://dl.armbian.com/orangepiplus/archive/
    Kernel: 3.4.113-sun8i

    なおBBBもOPiも手元にあったから利用したまでで、どちらも推奨しているわけではない。特にOPiはソフトウエアのサポートが弱く、ハードウエアは魅力的だが、長期間継続して利用するのはどうかと思う。実際に試してはいないが、Raspberry Pi 3B辺りのほうが実績も多く安心できそうな気がする。

    VPNソフトウエアは、L2TP/IPsecにはSoftEtherを、IKEv2にはStrongSwanを使った。それぞれの構築手順は以下のWebを参考にさせていただいた。

    SoftEther: 「俺の技術メモ: Raspberry Pi 2 Model B で L2TP/IPSec VPNサーバを構築してみた(その1~3)」
    http://xn--u9j0md1592aqmt715c.net/raspberry-pi2-vpnserver-part1/
    http://xn--u9j0md1592aqmt715c.net/raspberry-pi2-vpnserver-part2/
    http://xn--u9j0md1592aqmt715c.net/raspberry-pi2-vpnserver-part3/

    StrongSwan: 「Tutorial: How to Set Up an IKEv2 VPN Server with StrongSwan on Ubuntu 16.04 (DigitalOcean)」
    https://www.digitalocean.com/community/tutorials/how-to-set-up-an-ikev2-vpn-server-with-strongswan-on-ubuntu-16-04

    VPNパフォーマンステスト結果 (TCP)
    VPNプラットフォームスループットCPU
    使用率
    us%sy%si%id%
    L2TP/IPsec
    (FW 8.03.94)
    RTX11006Mbps100%
    L2TP/IPsec
    (SoftEther)
    BBB24MbpsCpu0:6417190
    OPi45MbpsCpu0:
    Cpu1:
    Cpu2:
    Cpu3:
    14
    14
    15
    63
    9
    9
    9
    11
    2
    2
    1
    15
    75
    75
    75
    11
    全平均:269560
    IKEv2
    (StrongSwan)
    BBB28MbpsCpu0:<126433
    OPi66MbpsCpu0:
    Cpu1:
    Cpu2:
    Cpu3:
    0
    <1
    <1
    0
    0
    <1
    <1
    <1
    0
    0
    0
    79
    100
    100
    100
    21
    全平均:<1<1396

    BBBおよびOPiを利用したVPNサーバーはどれも目安と考えていた20Mbps台にとどいている。OPiでは同時2スレッドで動いていると考えるとCPUの性能差に見合ったスループットの違い、と言うことができそうだ。ただしOPiのIKEv2の場合のCPU負荷の数字が少しおかしい。

    個別コアと全平均の数字のつじつまが合っていない。正確な原因はわからないが、コア毎に独立した可変クロックになっていてその補正の関係か何かではないかと想像している。

    いずれにせよIKEv2の方がL2TP/IPsecよりもスループットが高くCPUの負荷は低くなっている。IKEv2ではL2TPの処理が無いから当然と言えるが、もしかするとSoftEtherはIPsec関係の暗号処理もKernelのAPIを使わずに自前で行っているかもしれない。この点は確かめられなかった。

    なおOPiの場合si (Software Interrupt) の値が特定のコアだけ高いのが目立つ。siはIP通信関係の処理を行っている部分でマルチコアCPUでは特定のコアでのみ実行するのがディフォルト、と言うことらしい。従ってこれで正常なのだろう。特にこのことがパフォーマンスを制限するような状況ではないので問題はない。

    VPN接続は、L2TP/IPsecではAES128-CBCで、IKEv2ではAES256-CBCで暗号化されていたことを確認している。これはクライアント側の事情で決まるらしく、VPNサーバーの設定で同じにそろえることはできなかった。

    「低いCPU負荷で高いスループットが得られるIKEv2が良さそうだ。これならBBBでも他の機能を載せることもできる。」と思ったのだが、ちょっとした落とし穴があった。

     

    UDPパフォーマンス

    スループットが問題になるようなものでUDPが利用されている用途はあまり多くない。私がVPN経由で使う可能性のあるのはVoIPくらいのものだが、これはせいぜい100kbps位の世界なのでパフォーマンスを気にする必要はほとんどない。

    じゃあなぜUDPパフォーマンスを調べたか?

    ハンドシェイクが要らない分、TCPで測ったスループット程度のトラフィックはもっと楽に扱えるのではないかと考え、ちょっと確かめてみよう、と言った程度の軽い気持ちだった。しかしかなり想定外の結果が得られた。RTX1100とBBBによるL2TP/IPsecはほぼ想定通りだったが、それ以外はUDPのパフォーマンスがなぜか低いのだ。

    VPNパフォーマンステスト結果 (UDP)
    VPNプラットフォーム設定
    帯域幅
    パケット
    損失率
    CPU
    使用率
    us%sy%si%id%
    L2TP/IPsec
    (FW 8.03.94)
    RTX11006Mbps0.35%未測定
    L2TP/IPsec
    (SoftEther)
    BBB24Mbps1.3%Cpu0:60101317
    OPi45Mbps計測不能 (iperf3異常動作)
    30Mbps59%Cpu0:
    Cpu1:
    Cpu2:
    Cpu3:
    4
    4
    2
    34
    2
    6
    2
    2
    <1
    <1
    2
    8
    94
    90
    94
    56
    全平均:113383
    IKEv2
    (StrongSwan)
    BBB28Mbps計測不能 (iperf3異常動作)
    5Mbps90%Cpu0:<12692
    OPi66Mbps計測不能 (iperf3異常動作)
    30Mbps12%Cpu0:
    Cpu1:
    Cpu2:
    Cpu3:
    <1
    <1
    0
    0
    2
    5
    <1
    0
    0
    0
    0
    34
    92
    95
    100
    66
    全平均:<12692

    UDPの場合送信側から指定された帯域幅のトラフィックを送り、受信側に届かなかったパケットの割合=パケット損失率を調べることになる。損失率が高いとテスト処理の制御情報が伝わらなくなりiperf3の動作がおかしくなる場合がある。

    RT1100とBBBのL2TP/IPsec以外はTCPで得られたスループットを帯域幅に指定したのでは正常にテストできなかった。上記は帯域幅の指定を徐々に下げて一応テストができる状態になったときの結果である。

    BBBによるIKEv2が特に悪く、帯域幅を5Mbpsまで下げても大半のパケットが失われている。損失率が10%を切るためには1Mbpsまで帯域幅を下げる必要があった。

    OPiで損失率が10%を切る概略の帯域幅は、L2TP/IPsecの場合で10Mbps、IKEv2だと20Mbpsだった。どれもBBBによるL2TP/IPsecの場合よりも低い値である。

     

    市場動向

    L2TP/IPsecをサポートしている市販ルーターについて調べてみた。

    BuffaloとPlanexからコンシューマー向けハイエンド、ないしは小規模事業向けの位置づけの製品が出ている。

    VR-S1000
    VR500-A1

    両方ともL2TP/IPsecのパフォーマンスが100Mbpsを超えているというレビューがある。

    清水理史の「イニシャルB」: L2TP/IPSec接続でも実効100Mbpsを実現 バッファロー有線LANルーター「VR-S1000」
    http://internet.watch.impress.co.jp/docs/column/shimizu/629585.html

    iT-STUDIO: SOHO最強のおすすめVPNルーター VR500-A1 を徹底レビュー!
    https://it-studio.jp/vr500-a1-review/

    本当にそんなに速いのか気になる製品だが、幅広いデバイスとつなげるには暗号化を3DESに設定しなければならないなど、別の意味で気になる点も少なくない。信頼性・設定の柔軟さなど、総合的な「安心感」を考えると多少高くてもやっぱりYamahaの製品?と思わなくもないが、

    RTX-1210

    自宅用ルーターにここまでの費用をかけるのが正しい判断と思えないのも事実である。

    そうやってあれこれ探しているうち、かなり衝撃的なものを見つけてしまった。

    Cisco 841MJ

    いつまでこの値段で買えるかわからないが、あのCiscoの製品が2万円を切っている!と言うのは実に衝撃的である。
    (この記事を書いた時点で¥16,600)

    正式サポートなのかどうか少し微妙だが、一応L2TP/IPsecは使える。

    bisonicr keep walking: Cisco 841MJほかシスコルータのリモートアクセスVPNまとめ
    (最後の方「■実は「L2TP/IPSec」もちゃんと使えます。」)
    http://bisonicr.ldblog.jp/archives/55427998.html
    bisonicr keep walking: Cisco IOSルータでAndroid端末をL2TP/IPSec接続する。
    http://bisonicr.ldblog.jp/archives/54147837.html

    シスコサポートコミュニティ: C841M CCP Express 3.3 L2TP/IPsec VPN の設定ガイド
    https://supportforums.cisco.com/ja/document/13273836

    訳あって自宅のインターネット接続が100Mbpsまでなので、衝動買いは辛うじて踏み止まった次第 。 (^-^;

     

    今回のまとめ

    RTX1100について「IPsecのカタログ値が120MbpsなのにL2TP/IPsecだと10Mbpsに届かない」と言う第一印象だったが、実際はIPsecの方をハードウエア処理でずいぶん頑張っていると言うべきらしい。CPUの性能を考えれば妥当なL2TP/IPsecパフォーマンスである。

    また想定するL2TP/IPsecのユーザーが私一人であることを考えると、数Mbpsのスループットでも多くの場合問題にならない。モバイルネットワークがボトルネックになる可能性が高いからだ。実際にデスクトップPCのネットワーク接続をVPN経由にして半日ほど使ってみて、確かに遅いが、大きなファイルを操作する場合を除きフラストレーションを感じるほどではなかった。

    当初構想通りインターネットとつないでいるルーターをRTX1100で置き換えてL2TP/IPsec VPN機能を持たせることにした。これなら消費電力の増加なしにVPN機能を追加できる。しばらくこれで運用してみて、もし遅さが目立つようなら別途VPNサーバーを追加するようにすれば良いはずだ。

    Viewing all 60 articles
    Browse latest View live