ebay で見つけて買ったやつシリーズです。表題のようなものを買ったので動かしました。

https://github.com/adafruit/Adafruit_LED_Backpack が割とよくできていて、これ使えばすぐに動かせました。

#include <Arduino.h>
#include <Wire.h>
// https://github.com/adafruit/Adafruit_LED_Backpack
#include "Adafruit_LEDBackpack.h"

// Adafruit_LEDBackpack matrix = Adafruit_LEDBackpack();
Adafruit_8x8matrix matrix = Adafruit_8x8matrix();


void setup() {
	Serial.begin(9600);
	Serial.println("begin");
	matrix.begin(0x70);
	matrix.setBrightness(10);
	matrix.setTextSize(1);
	matrix.setTextWrap(false);
	matrix.setRotation(1);
}


void loop() {
	char* message = const_cast<char*>("Hello, World!\n");

	int16_t x, y;
	uint16_t w, h;
	// getTextBounds は \n で終わってないと width を正しく計算しない。
	matrix.getTextBounds(message, 0, 0, &x, &y, &w, &h);
	Serial.println("getTextBounds: ");
	Serial.print("  x = "); Serial.println(x);
	Serial.print("  y = "); Serial.println(y);
	Serial.print("  w = "); Serial.println(w);
	Serial.print("  h = "); Serial.println(h);
	Serial.println("");

	for (int16_t x = 8; x >= -(int16_t)w; x--) {
		matrix.clear();
		matrix.setCursor(x, 0);
		matrix.print(message);
		matrix.writeDisplay();
		delay(50);
	}
}
  1. トップ
  2. tech
  3. I2C 8*8 LED dot Matrix module HT16K33

BMP180 搭載のモジュールを ebay で買ってみたので試しました。約$2。どの気圧計にしろ温度計が必要で内部補正には使われていたりしますがだいたい内部用で外から値がとれません。このモジュールは温度もI2C経由で測れて一石二鳥モジュールです。

こんな感じのモジュールで、BMP180 以外に実装があります。これは 3.3V レギュレータで、5V 供給しても大丈夫なようになっています。(I2C のロジックレベル変換は簡易的ですが)。なので 5V の Arduino でも使えます。

BMP085 というものと互換性があるみたいで (BMP085はディスコン) それ用のライブラリがそのまま使えます。

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>

// https://github.com/adafruit/Adafruit-BMP085-Library
Adafruit_BMP085 bmp;

void setup() {
	Serial.begin(9600);
	int ok = bmp.begin();
	if (!ok) {
		Serial.println("bmp.begin() failed.");
		for (;;);
	}
}

void loop() {
	Serial.print("Temperature = ");
	Serial.print(bmp.readTemperature());
	Serial.println(" *C");

	Serial.print("Pressure = ");
	Serial.print(bmp.readPressure() / 100.0);
	Serial.println(" hPa");

	Serial.println();
	delay(1000);
}
Temperature = 19.40 *C
Pressure = 1011.48 Pa

Temperature = 19.40 *C
Pressure = 1011.47 Pa
  1. トップ
  2. tech
  3. BMP180 I2C 気圧・温度計センサー

ebay で買ったシリーズです。$3 ぐらいで買いました。以下らへんのモジュールとよく似たものです。

MQ-135 のほかすこし実装 (LM393など) があります。LM393 はコンパレータで、基板上の半固定で設定した閾値でデジタル出力できるようになっています。アナログ出力は MQ-135 直結です。

MQ-135

空気の汚染度に感度があるセンサーで、ベンジン・アルコール・煙などに反応しやすいと書いてあります。CO2 にもある程度反応するみたいで、ググると poor man's CO2 センサーとしても一定の人気があるみたいです。

自分としては、換気扇ごしに外からタバコの煙が自宅に入ってくることがあってほとほと不愉快なので、どんな時間帯にそういう状況になるかをつきとめたいというモチベーションがありますが、そういう用途に使えるかはわかりません。というかテストのためにタバコを買うのも絶対に嫌なのでテスト不可能です。

仕様

MQ-135 自体がデータシートでプリヒートを24時間以上求めています。常時起動してないとダメですね。とはいえ1時間ぐらいで値はほぼ安定しているようには見えます。

MQ-135のデータシート的には10kΩ〜47kΩの負荷抵抗を想定しているみたいですが、このモジュールは 102 (1kΩ) の抵抗が負荷抵抗になっているように見えますので、普通に使うより感度が低くなりそうです。

ググると頑張って ppm 単位の絶対値出力を出そうという試みがあるのですが、素人がキャリブレーションしようがない (他の正確な絶対値センサーが必要) ので、基本的には相対的な値を範囲を一定期間モニタリングしたうえで値を把握して使うほかない気がします。

実測出力

  • 200mV / 数時間通電後の無人の部屋
  • 700mV / アルコールティッシュを近付けたとき
  • 800mV / サカムケアを近付けたとき (イソプロパノールなど)
  • 1660mV / プラモデル用接着剤を近付けたとき (アセトンなど)

意外と反応が良くて、臭いがあるとすぐ変化が出力されます。

  1. トップ
  2. tech
  3. MQ-135 Sensor Air Quality Sensor Hazardous Gas Detection LM393 MQ135 gas sensor

神道の文献は、たとえ最古の古事記(712年)であっても、仏教伝来(遅くとも6世紀半ば)後に書かれたものであるので、そもそも「仏教に影響されていない神道」というものを記録している文献はない。すなわち仏教抜きで神道を考えるというというのはそもそも現代では無理。

「復古神道」は名前に反して江戸時代の新興宗教であって、儒教・仏教色を排すという意味ではかえってそれらの影響をうけている。

C++ はながいこと食わず嫌いだった。とにかく「難しい」というイメージだけ先行していた。

しかし、あくまで better C として使う限りでは難しくないし、可読性が上がるので、 C++ を使わない手はないという気持ちになった。

これまでの漠然とした C++ への不安

書いたコードと出てくるバイナリ

C を書いていると、だいたいは書いたコードがそのままバイナリに翻訳されている感があり、安心感がある。struct はメモリ上の配置そのままだし、関数だって単に処理のまとまりに名前がついてて、呼び出しもとに自動的に戻ってくるラベルなだけだ。

C++ になるとオブジェクト指向に概念が入ってきて、これが実際どのようにコンパイルされるかに不安が出てくる。クラスはメモリ上でどう表現されているのか、メソッドディスパッチはどのように行われているか?

もちろん知っている人にとっては簡単な話で

  • class は単に struct である
    • フィールド定義はそのままメモリ上の表現となる
    • メソッド定義は関数になる
    • 実際、C++ で class と書かれた定義を struct に置き換えても問題なくコンパイルされる (フィールドのスコープがデフォルトで class は private で struct が public である違いだけ)
  • メソッドディスパッチは基本的に静的である
    • レシーバによって動的にディスパッチされる関数は virtual 関数と呼ばれる
    • コンパイラがテーブルを作って動的に呼びだし関数を変えている

ということで、virtual を使わない限りでは、C++ の class は C で struct 定義と、その第一引数にその sturct ポインタをとる関数郡でしかなく、これは C でよくやるオブジェクト指向のプリミティブな実装とよく似ている。

このようなCのコードは

#include <stdio.h>

typedef struct {
	unsigned counter;
} my_counter;

void my_counter_init(my_counter* this) {
	this->counter = 0;
}

void my_counter_incr(my_counter* this) {
	this->counter++;
}

unsigned my_counter_get_count(my_counter* this) {
	return this->counter;
}

int main() {
	my_counter counter;
	my_counter_init(&counter);

	printf("%d\n", my_counter_get_count(&counter));
	my_counter_incr(&counter);

	printf("%d\n", my_counter_get_count(&counter));
}

このようなC++のコードとほとんど同じバイナリが出力される

#include <cstdio>

class my_counter {
	unsigned counter;
public:
	my_counter();
	void init();
	void incr();
	unsigned get_count();
};

my_counter::my_counter() {
	this->counter = 0;
}

void my_counter::incr() {
	this->counter++;
}

unsigned my_counter::get_count() {
	return this->counter;
}

int main() {
	my_counter counter;

	printf("%d\n", counter.get_count());
	counter.incr();

	printf("%d\n", counter.get_count());
}

テンプレート多用するとバイナリサイズ増えるんじゃないの?

テンプレートは、複数の型に対する処理を1回でまとめて書けるという仕組みなので、原理的には、扱う型が増えるほど、出力バイナリに関数本体が増えていくことになる。

しかし一方で、テンプレートをコンパイル時計算のために使うような場合は、コンパイル時に解決されるコードがほとんどになり、出力バイナリは書いたコードの見た目の多さに反してかなり少なくなることもある

ということで、テンプレートが使われているからといってバイナリサイズが肥大化するというわけではない。

最適化はどこまで信用できるか?

この書きかたで本当に最適化されたコードに出てくるの? という不安がある。これは難しくて、コンパイラが優秀でも、当然プログラマがちゃんと const を付けてコンパイラに意図を伝えないと、完全に最適化されたコードにはならない (インライン化されないとか)。

C にはない概念がある分、const の付けかたが複雑で、ベターCとして使おうと思うと一番ハマる。

一方で、テンプレートメタプログラミングでコンパイル時に計算することができるので、コンパイラが判断できないような高度な最適化を自力でやることができる。

なぜ組込みでこそなのか?

組込みのコードはどうしてもマジックナンバーが多くなりやすく、C で書くとマクロだらけになる。Cのマクロは文字列展開なので型がなく、当然マジックナンバーにも型を付与できない。組込みは実行時デバッグのコストが高いので、コンパイル時に見つけることができるエラーは全てコンパイル時に見付けたいが、Cではそこまでのことができない。

浮動小数点まわりについてはMCUでは非常に重い処理になるので、できるだけ事前計算した係数をつかってMCU上では整数演算にしてしまうなどの最適化をしたくなる。こういうときCのマクロだけで書くのはとても厳しい。C++ であればコンパイル時に浮動小数点計算を行って定数展開できるので、あきらかに有利になる。

浮動小数点に限らず、高いレイヤーでの最適化はコンパイラは知るよしもないので手でやる必要がある。その際C++のTMPは非常に強力に使える。

  1. トップ
  2. tech
  3. 組込みでこそ C++

測定中、10MHz 付近に急激な落ちこみが観測されることがあって気になっていました。そういうものなのかなとも思ったのですが、調べてみたら同じような問題にあたっている人がいて、まぁよく考えたらそういうものではないよなという感じです。

これは簡単に再現することができます。TGとSAを同軸で直結させて、TGを有効にし、10MHz 付近を拡大することで、変な落ちこみを見ることができます。

以下の画像がそうですが、明かに1dB 落ちこみがあるのがわかると思います。

あるいは、掲示板中にもありますが 10μH と 33pF ぐらいを直列に接続し、バンドパスフィルタを構成した上で 10MHz 付近を見ると、スカートが不自然になっているので非常に目立ちます。 冒頭の画像はこの方法での再現です。直結よりもわかりやすくおかしいことがわかります。

広いスパンで見ているときや、広いダイナミックレンジで見ているときには気付きにくいかもしれませんが、フィルタのようなものを測定するときはかなり気になる挙動だと思います。

10MHz 付近はアマチュア無線でも使う帯域ですし、基準信号付近ですから余計気になります。位相雑音がどうとかよりも致命的な問題でしょう。

現時点での解決方法

ファームウェアの 1.15 が1月22日にリリースされており、これにある程度の修正が含まれています。

最新のファームウェアは http://int.rigol.com/Support/SoftDownload/3 からダウンロードできます。

Product Series → Spectrum Analyzer → DSA815 Firmware_00.01.15.01.00 というのをダウンロードします。DSA815(DSP)update.rar というやつです。

DSA815update.sys を USB メモリのルートディレクトリにコピーして、DSA815 のフロントUSBポートに接続し、Storage の画面でこのファイルを選択したあと、Sys Update を選択すると、アップデートが開始されます。数分で終わり、再起動すると最新のファームウェアで起動します。

バッファロー USB3.0メモリ バリューモデル (8GB・ブラック)RUF3-WB8G-BK -

3.0 / 5.0

↑ 使ったUSBメモリです。自宅にUSBメモリがなく、SDカードリーダーとSDカードで代用しようと思いましたが、DSA815 では認識されませんでした。純粋な USB メモリじゃないとダメなようです。ググってみると、メーカー的にはできるだけ容量が少ないほうが信頼性が高いということになっているみたいです。とはいえ現時点で新品はもはら8GB未満は売ってません。これは USB 3.0 メモリですが、DSA815 は USB 3.0 に対応してないので、古くてもなんでもいいはずです (信頼性は別として)。

解決したか?


見ての通りです。直結の場合では不連続部分はわかりません。一方バンドパスフィルタで見たときはすこし不連続な部分が残っているようにみえます。

ということで、完全には解決しません。挙動的にはまるめ誤差みたいなのが発生しているような感じますが実装がどうなっているかはわかりません。

とはいえ、このように修正が入るので、現状の状態は Rigol のエンジニアは把握しており、直すつもりはあるようです。ファームウェアアップデートだけですめばいいんですが……

ファームウェアアップデートと保証

DSA815-TG には3年保証がついているのですが、ファームウェアアップデート時にどのような扱いになるか不安になりました。(そもそも国内販売版のものが国際版と完全に同一であるかの確証もない)

国内のリゴルジャパンへメールで確認をとったところ、すぐに返信していただけました。

  • 国内販売のものでもファームウェアは共通
  • ファームウェアアップグレードしても保証期間内では無償サポート

とのことで、アップグレードしても大丈夫そうです。

1.15 での他に気になった挙動

購入直後スクリーンショットをLAN経由でとれるようにしましたが 1.15 になって、TCPソケット経由でのコマンド解釈がすこし厳密になって動かなくなったので直しました。

あと、スクリーンショットをとるコマンドは最後にリモートモードを解除するコードを入れていたのですが、動かなくなりました。リモートからコマンドを実行すると必ずリモートモードになってしまって若干鬱陶しいのでなんとかしたいのですが、こちらの原因はよくわかってません。

どうやらスリープを挟まないとダメな模様

また、デフォルトで mDNS での DNS-SD の機能が無効になってみたいです。HTTP 経由でアクセスして設定しないと DNS-SD のクエリに応答しません。

備考

元のバージョンは00.01.12 でした。

アップグレード後は 00.01.15 です。


  1. トップ
  2. tech
  3. DSA815-TG の 10MHz 付近の奇妙なバグとファームウェアアップグレード

スペアナがあったらやってみたかったことの1つとしてコモンモードフィルタ(RFチョーク)の評価というのがあります。だいたいトロイダルコアを使って作っており、トロイダルコアは再現性が高いので計算通りにやれば実用性能はでるはずなのですが、ちゃんと作れているか?はやはりはかってみなければわかりません。

スペアナがなくてもハムバンドでダミーロードを使いつつ高周波電流を頑張って測るという方法で一応検証はできるのですが、面倒くさすぎるので結局グラフ化したりまでしたことはありません。面倒くささが勝りすぎます。

その点スペアナがあれば一瞬で…… という気持ちがありました (実際は適切な治具がないと正確に測るのはやはり難しいのですが……)

概要

大地経由での電流がコモンモード電流なので、フィルタのホットとコールドをショートして、TG のホットをフィルタを通してスペアナの入力にし、TG とスペアナのコールド側をショートさせれば計れそうです。要は単にRFチョークとして測定します。

なおコモンモードフィルタはだいたい-30dB ぐらいあれば十分な性能といえるらしいです。

測定方法

まずワニグチクリップをトラッキングジェネレータとスペアナ入力に直付けし、ホットコールドをそれぞれショートさせます。

この状態でTGの出力レベルを0dBmに設定し、ノーマライズします。(なおビビリなので外付けのアッテネータは入れてませんが内蔵アッテネータは10dB入れたままです) それなりに出力がないとノイズに測定結果が隠れてしまうので気をつけます。

ノーマライズされた状態でホット側をはずしてアイソレーションを確認します。-30dB 以上なければ測定の意味がないので、アイソレーションがとれてなさそうなら諦めてスパンを狭くして再度ノーマライズからやりなおします (意味がない結果が見えていると混乱するため)。

TG 側にワニグチクリップをつけたりして配線長を増やすと50MHz〜は容易にアイソレーションがとれなくなるので注意します。以下はオープンの状態のアイソレーションです。

この状態でフィルタに接続して測ります。フィルタの入力側(TG側)の線長が長いとこれまたアイソレーションがとれないので誤差の原因になりますが、排除するのが難しいです。シールドケースに入れて測るしかない気がしますが、今回は用意できてないので多少飛びこみがあります。

結果

今回計ったのはキットものの http://www.ddd-daishin.sakura.ne.jp/ddd/dcf/dcf-rf-29l3/kit-dcf-rf-29l3-ver2.htm これです。スペック的には 50MHz ぐらいまでは -30dB 余裕でとれるみたいなグラフがあります。

一応このように雑に測った感じでも 50MHz ぐらいまでは -30dB ぐらいになっているように見えます。(0〜100MHzのスパンなので真ん中が50MHzです)。とはいえ -40dB までとれている範囲はそれほどないです。

挿入損失

ついでに挿入損失も測りました。


メモ:挿入インピーダンスとdB

入出力インピーダンス50Ωとして、例えばインピーダンスZを直列挿入した場合、入力側にかかる電圧は出力電圧を、挿入インピーダンス と入力インピーダンスで分圧した形になる。

なので、入力電圧は になる。dB で表わすと

  1. トップ
  2. tech
  3. アマチュア無線用コモンモードフィルタの特性評価