なんとなくもう一台を作りたくなったので作っています。実は基板自体はだいぶ前(数ヶ月以上前)に作っておいたのですが、設計ミスがあったりして面倒なのでちゃんと作りはじめてませんでした。

AD8307

AD8307を使ってログアンプ検波するバージョンの SWR 計の例があることは知っていましたが、前回はそこまですることはないと思ってとりあえず簡単な方法で作りました

というのもログアンプは大変高価だからです。秋月でAD8307のDIP版が売っていますが、単価が1100円します。なお DigiKey で買うともっと高価なので、秋月は安いほうです。

(最近知りましたが中華性AD8307というセカンドソース品、というよりコピー品があり、こちらは単価が50円!!と激安のようです。SOICで、ebay で手に入ります)

方向性結合器 + 検波 + ADC

例の回路をほぼ完全にパクって実装しました。

方向性結合器は、タンデムマッチで、FT82-43 を使い、20T にしてみました (26.02dB のカップラに)。線間容量を減らして、高い周波数での特性が改善しないか?と思い巻数を減らしています。#43 は透磁率が高いので、多少巻数を減らしてもインピーダンスは高いままですが、ロスは多くなるはずです。

検波部は結合器からの出力をアッテネータ(16.1dB)を通し、インピーダンス変換を行なって AD8307 に入力しています。AD8307 のオフセットや切片調整はしていないので、25mV/dB の出力にはるはずです。

方向性結合器で 26.02dB、アッテネータで16.1dBなので、AD8307 には 42.12dB 減衰された信号が入力されます。言いかえると、AD8307の入力範囲は -72〜+16dBm ですから、-29.88〜+58.12dBm の入力範囲 (約1μW〜648W) にシフトしたことになります。

ADC は ADS1015 という 4ch + PGA 付き I2C デバイスにしてみました。ここは入手性の問題からオリジナルと違います。

実装

最初は方向性結合器の部分も基板を起こしていましたが、どうも作りにくいので立体配線に変えました。2つのトロイダルコアの間に容量結合防止のためのGNDを立てたいわけですが、プリント基板だとかえって面倒でした。

そんなこともあろうかと、基板を作る段階で途中で切って使えるような感じにしておいたので良かったです。

検証

作ったはいいのですが、どうもうまくいかず悩みました。

一つはコイルを逆付けしていてまともに方向性結合器として動いていなかったのが原因でした。

もう一つはAD8307の出力の問題で、どうしても入力電力から計算される出力電圧が出ず、未だ完全に理由がわかっていません。

AD8307 の出力

最初は 3.3V で動かしていたのですが、どうしても途中から出力電圧が上がりませんでした。定格上では 3.3V でも +10dBm までは入力可能のはずなのですが、-2dBm ぐらいから出力が上がらなくなり、全くよくわかりませんでした。

5V で動かしてみたところ、とりあえずこれは解決したように見えました。

しかし電源電圧を 5V に変えても、入力電力に応じた出力電圧にならず難儀しました。どうしても 25mV/dB の傾きになっておらず、オフセットが含まれているように見えました。切片調整もしていないし、オフセットがどこから入っているのかもわかりませんでした。

結局これはキャリブレーションと称してプログラム上で補正をかけることにしました。どっちにしろ 25mV/dB の傾きは定格上でも 23〜27mV/dB の範囲があるので調整を入れなければなりません。

ということで、適当に係数を求めたら、だいたいそれっぽい値が出るようにはなりました。

正確な電力を計る方法がないので、一定以上は調整しようがありません。

Google Spreadsheet に実測と理想を書いて比較してがんばりました。。。

方向性結合器

追記:FT82-61 を使ったバージョンに変更しました。
自作 デジタル SWR 計(再) 2 | 方向性結合器の改善編 | tech - 氾濫原

SWR はこんな感じでした

SWR だとよくわからないので、リターンロスでみるとこんな感じです

肝心のディレクティビティなどの特性です。蓋をあけた状態で電圧をオシロで計って50Ω換算で出しています。残念ながら前回作ったものよりも良くありません。

ログアンプの効果

ダイオード検波の場合、微小電力ではダイオードの Vf を超えることができず、それはそのまま誤差になります。

ログアンプ検波することで、ダイオード検波の欠点はなくなり、微小電力から計れるようになりました。具体的には、スペアナのトラッキングジェネレータ出力を 0dBm にして計っても、多少の誤差はありますがちゃんと 1mW ぐらいの値が出てきます。

通常送信機の電力測定ではこんな微小電力まで計れる必要は特にないかと思いますが、SWR 計として反射電力を計りたい場合、SWR が低いときには反射電力も非常に小さくなりますから、ダイナミックレンジの広い測定が必要になります。ダイオード検波と通常のリニアなADCを使うことに対する最大のメリットはここだと思います。

方向性結合器部分はまだ追試が必要

SWR計としてまとめるのではなく、方向性結合器として一旦作って評価をしてから、検波回路を外付けするほうが安定したものが作れそうです。次はそのようにしたいと思います。

制御

インターフェイスはまともに作っていなくて、Arduino で I2C から値を呼んで計算させてシリアルに出力だけさせてテストしていました。今のところまだ実用にはなっていません。

  1. トップ
  2. tech
  3. 自作 デジタル SWR 計(再) | ログアンプを使いQRP〜1KWまで

mbed の API 経由でできる以上のことをやろうとする場合、結局 mbed 側で何をやっているか (どのAPIでどのレジスタが変更されるか) は理解していないといけない。

つまり mbed のラッパーのソースコードが手元にないと、プログラムできない。しかし実際のコードがどこにあるのかわかりにくい。

基本的には mbed のライブラリ経由でできることが殆どだとは思うが、例えば高度なスリープを行いたいとか、ウォッチドッグタイマを使いたいとなると、低レベルなレジスタアクセスが必須になる。

ghq で全部落としとくぞ

Mercurial (hg) のレポジトリとして公開されている。

 ghq get https://cho45@developer.mbed.org/users/mbed_official/code/mbed-src/
 ghq get https://cho45@developer.mbed.org/users/mbed_official/code/mbed/ 

してmbed 関係のヘッダと実装を手元に置いておく

mbed LPC1114

メインのレポジトリはこっちなのですが、ヘッダファイルだけ
https://developer.mbed.org/users/mbed_official/code/mbed/file/252557024ec3/TARGET_LPC1114/TARGET_NXP/TARGET_LPC11XX_11CXX/TARGET_LPC11XX

実装は mbed-src にあった。
https://developer.mbed.org/users/mbed_official/code/mbed-src/file/a11c0372f0ba/targets/cmsis/TARGET_NXP/TARGET_LPC11XX_11CXX/TARGET_LPC11XX/system_LPC11xx.c

mbed 関係ない部分

LPC1114 のリファンレス
http://www.nxp-lpc.com/images/LPC111x_UM_Rev.00.15_Japanese.pdf

NXP による LPC の定数定義
https://developer.mbed.org/users/mbed_official/code/mbed/file/252557024ec3/TARGET_LPC1114/LPC11xx.h

  1. トップ
  2. tech
  3. mbed のフレームワークの温度感

トランジスタ技術 2016年 2月号 - トランジスタ技術編集部

トランジスタ技術編集部

3.0 / 5.0

ここ1ヶ月ぐらい GPSDO に興味があって調べていたのですが、先月のトランジスタ技術がまさにGPSの特集だったようでした。

なんか知らずに流行りに乗ったみたいでかっこわるい…… というのはおいといて、おもしろそうなので買って読んでみました。

GPSDO については1記事だけでした。しかしMCUなしでの製作という、男らしい感じなのですが、残念ながらあんまり参考になりませんでした…… 使っているモジュールはちょっと前に買ってみたNEO-6Mで親近感がありました (というか1PPS出せて安いのをebayで探すとこれが最安なので第一候補になるわけですが)

ublox のモジュールは TIMEPULSE ピンに 1PPS に限らず安いものでも10kHzぐらいまで可変で出せるのですが、製作記事でもこの機能を使っていました (MCUを使わないことによる副作用として)。個人的にはこの機能を使うのはいまいちというか、他のGPSモジュールとの互換性がなくなるのがなあと思ってしまいます。

読んでていて疑問に思った点

  • 出力にバンドパスフィルタをつけてサイン波にしているのは?
    • 普通はサイン波で出すから?
    • 高調波成分が含まれるのが嫌?
    • 矩形波出力で立ちあがりを高速にしたほうがクロックとして有利なイメージがあるけどそうではない?

そもそも基準クロックというのに疎いので根本的なところがよくわかっておらず難しい。

出力を4分配にしているところで、バッファ+トロイダルコアを4つ使って分配しつつ直流的に?アイソレーションしているみたいでしたが、1つのバッファアンプ+ハイブリッドのほうが部品点数は減りそうだけど、うまくいかないのだろうか?とか机上の空論を考えてました。

精密なAD変換器のような非常に敏感な回路などではこの問題を避けるために、矩形波の代わりに正弦波をタイミング基準として使用する。

https://ja.wikipedia.org/wiki/%E7%9F%A9%E5%BD%A2%E6%B3%A2

Wikipedia にも書いてありましたが、クロックの高調波の影響を排除するために正弦波を使うんですね。無知でした。

その他

現在 GPS に載っている発振器のほとんどがルビジウムオシレータでびっくりしました。なんとなく全てセシウム原子時計が載っていると思い込んでいました。

AD9851 は Arduino で一度動かしてみましたが、LPC1114/mbed な環境でも動かしてみました。


DDS モジュールの定格は5Vですが、3.3Vで動かしてみています。振幅は当然減りますが、ちゃんと70MHzぐらいまでは波形が確認できました。

コード

Arduino のコードとほぼ一緒です。というか殆ど正規表現で置換しただけで動かすことができました。GPIO の操作だけなので本当に頭を一切使わずに移植できました。

GCC かつ -std=c++14 な環境なため mbed のオンラインコンパイラではコンパイルできないと思います (すこし修正すればいけるはずですが C++14 が使えない環境に興味がないので……)

また、なんとなくシリアル経由で周波数を変えるインターフェイスにしてみました。mbed のライブラリに CircularBuffer があるので簡単です。C++ の STL に circular buffer / ring buffer 相当のものがないのが不思議なんですが、いつか入る予定はあるんでしょうかね?

#include "mbed.h"
#include <CircularBuffer.h>
#include <cstdlib>
#include <string>

template <uint32_t CLKIN, bool MULTIPLIER>
class AD9851 {
	static constexpr double PHASE_FACTOR = 0x100000000 / (double)(CLKIN * (MULTIPLIER ? 6 : 1));

	DigitalOut PIN_DATA;
	DigitalOut PIN_FQ_UD;
	DigitalOut PIN_W_CLK;
	DigitalOut PIN_RESET;

	void serial_write(uint32_t freq, uint8_t phase, bool powerdown) {
		// freq (delta phase)
		for (int i = 0; i < 32; i++) {
			PIN_DATA = (freq>>i & 1);
			PIN_W_CLK = 1; wait_us(4);
			PIN_W_CLK = 0; wait_us(4);
		}

		// control bits
		PIN_DATA = MULTIPLIER ? 1 : 0;
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);
		PIN_DATA = 0;
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);

		// powerdown
		PIN_DATA = powerdown ? 1 : 0;
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);

		// phase
		for (int i = 0; i < 5; i++) {
			PIN_DATA = (phase>>i & 1);
			PIN_W_CLK = 1; wait_us(4);
			PIN_W_CLK = 0; wait_us(4);
		}

		PIN_FQ_UD = 1; wait_us(4);
		PIN_FQ_UD = 0; wait_us(4);
	}

public:
	AD9851(
			PinName data,
			PinName fq_ud,
			PinName w_clk,
			PinName reset
		) :
			PIN_DATA(DigitalOut(data)),
			PIN_FQ_UD(DigitalOut(fq_ud)),
			PIN_W_CLK(DigitalOut(w_clk)),
			PIN_RESET(DigitalOut(reset))
	{
		PIN_DATA = 0;
		PIN_FQ_UD = 0;
		PIN_W_CLK = 0;
		PIN_RESET = 0;
	}

	/**
	 * W0 ... W31  -> Freq (LSB first)
	 * W32, W33    -> Control (for factory test)
	 * W34         -> Power-Down
	 * W35 ... W39 -> Phase (LSB first)
	 */

	void reset() {
		// ensure low
		PIN_DATA = 0;
		PIN_FQ_UD = 0;
		PIN_W_CLK = 0;

		// reset
		PIN_RESET = 1; wait(1);
		PIN_RESET = 0; wait(1);

		// reset to serial mode
		// Pins of D0, D1 = 1, D2 = 0 for serial mode
		PIN_W_CLK = 1; wait_us(4);
		PIN_W_CLK = 0; wait_us(4);

		PIN_FQ_UD = 1; wait_us(4);
		PIN_FQ_UD = 0; wait_us(4);
	}

	void set_frequency(uint32_t frequency) {
		set_frequency(frequency, 0);
	}

	void set_frequency(uint32_t frequency, uint8_t phase) {
		uint32_t deltaPhase = PHASE_FACTOR * frequency;
		serial_write(deltaPhase, phase, 0);
	}

	void powerdown() {
		serial_write(0, 0, 1);
	}
};

AD9851<30000000, true> ad9851(/*data*/dp28, /*fq_ud*/dp26, /*w_clk*/dp25, /*reset*/dp1);

//AnalogIn adc1(dp9);
//AnalogIn adc2(dp10);
//AnalogIn adc3(dp11);
//AnalogIn adc4(dp13);

Serial serial(USBTX, USBRX);

CircularBuffer<char, 80> serial_buffer;

int main() {
	serial.baud(115200);
	serial.printf("init\n");

	ad9851.reset();
	ad9851.set_frequency(10e6);

	for (;;) {
		if (serial.readable()) {
			char c = serial.getc();
			if (c == 0x0D) continue; // ignore CR
			if (c == 0x0A) { // treat LF as line end
				std::string line(80, '\0');
				line.clear();

				char c;
				while (serial_buffer.pop(c)) {
					line += c;
				}
				serial_buffer.reset();

				serial.printf("GOT: %s\n", line.c_str());

				uint32_t new_freq = std::atoi(line.c_str()) * 1e6;
				ad9851.set_frequency(new_freq);
				continue;
			}

			serial_buffer.push(c);
		}
	}
	return 0;
}

メモ: mbed 移植正規表現

S/digitalWrite\(([^,]+), ([^)]+)\)/\1 = \2/
s/delayMicroseconds/wait_us/g
s/delay/wait/g
  1. トップ
  2. tech
  3. AD9851 DDS モジュールを LPC1114/mbed と

アマゾンプライムビデオがはじまったのはもちろん知ってはいましたが「PC で見れてもなぁ」と思ってました。PC で動画を見る習慣がないので結局見ません。

しかし PS4 で直接見れることに気付いて、ただただ、最高という気持ちに変わりました。

まぁアマゾンプライムビデオとかは些細なことで、未確認で進行形を見なおしてるんですが、最高です。最高です。小紅は最高に可愛い。

1000円ぐらいで買いました。このモジュールはアンテナが分離型で、1PPS 出力がとれるという特徴があります。

ublox というメーカーのGPSチップが載っています。u-center というソフトウェアから詳細な設定ができることになっています。ただし u-center は Windows のみです。

GPS Fix に時間がかかる

窓際で受信させてみましたが、いつまで経っても GPS Fix しません。u-center でしばらく眺めていると1時間〜2時間ぐらいでようやく GPS Fix しました。

スマフォ内蔵のGPSだと窓際でもすぐGPS Fixできるので、ちょっと残念なところです。

1度3D Fixまでいけば、割と安定して受信が継続されました。

NEO-6M は GPS(アメリカ)のみに対応していて、GLONASS (ロシア)やQZSS(日本)は対応していないので、そのせいかもしれません。

1PPS

自宅でGPS使って位置を知れてもあんまり意味がありません。このGPS モジュールの最大の目的は1PPSです。

1PPS (Pulse Per Second) 出力はLED が接続されており、GPS Fix 時には1秒ごとにLEDがフラッシュします。

この1PPSはGPS衛星に搭載されている原子時計と同期しているので、とても正確です。ただし、GPSモジュール内蔵クロックが48MHzなので最大42nsぐらいのジッタはありそうです。そこそこに長い目で見ると原子時計並に正確な1Hzが得られるというものです。

スペック的には以下のようになっています(いまいち各項目の意味がわかりませんでしたが…)

モジュールのピンヘッダに出ていないので、必要なら直接引き出す必要があります。

• For best timepulse performance it is recommended to disable the SBAS subsystem. 

日本にはSBASシステムがそもそもないので完全に無効にしときましょう。

NMEA を Ruby で雑に読んでみる


特にライブラリとかを使わずに、ちゃんと動いているかだけのテストをできるようにスクリプトを書きました。動かすと以下のような出力になります。

2016-02-16 15:28:5.000Z VALID:YES / 3D Fix [1: 31dB*] [3: 21dB*] [7: 26dB*] [8: 0dB] [10: 0dB] [11: 15dB*] [16: 15dB*] [17: 0dB] [22: 0dB] [27: 0dB] [28: 19dB*] [30: 0dB*]
#!ruby -v
require 'serialport'

@port = SerialPort.new(
	"/dev/tty.usbserial-A50285BI",
	9600,
	8,
	1,
	0
)

cols = `tput cols`.to_i

status = {
	using: [],
	sates: {}
}

loop do
	while line = @port.gets
		type, *rest = line.chomp.split(/,/)
		next unless type[0] == '$'
		_ = rest.pop
		case type
		when "$GPRMC"
			h, m, s = *rest[0].match(/(..)(..)(.+)/).captures.map {|i| i.to_f }
			dd, mm, yy = *rest[8].match(/(..)(..)(..)/).captures.map {|i| i.to_i }
			datetime = "%04d-%02d-%02d %02d:%02d:%02.3fZ" % [yy + 2000, mm, dd, h, m, s]
			state = rest[1]
			status[:UTC] = datetime
			status[:is_valid] = state == "A"
		when "$GPGGA"
			sate_count = rest[6]
			status[:sate_count] = sate_count
		when "$GPGSA"
			mode = rest[0]
			type = rest[1] # 1 = invalid, 2 = 2d, 3 = 3d
			sate_nums = rest[2, 12]
			status[:mode] = mode
			status[:type] = type
			status[:using] = sate_nums.map {|i| i.to_i }
		when "$GPGSV"
			total = rest.shift
			current = rest.shift
			if current == 1
				status[:sates] = {}
			end
			_ = rest.shift # count
			until rest.empty?
				num = rest.shift
				e = rest.shift
				d = rest.shift
				sn = rest.shift
				status[:sates][num] = {
					num: num.to_i,
					e: e,
					d: d,
					sn: sn.to_i,
				}
			end
			if total == current
				# done
			end
		else
			# ignore
		end
		out = "%s VALID:%s / %s Fix %s" % [
			status[:UTC],
			status[:is_valid] ? "YES" : "NO",
			status[:type] == "1" ? "NO" : "#{status[:type]}D",
			status[:sates].values.sort_by {|i| i[:num] }.map {|i|
				"[%s: %ddB%s]" % [
					i[:num],
					i[:sn],
					status[:using].find_index(i[:num]) ? "*" : ""
				]
			}.join(" ")
		]
		print "%- #{cols-1}s\r" % out
		$stdout.flush
	end
end
  1. トップ
  2. tech
  3. ublox NEO-6M GPS Module

スマフォで見たとき、ファーストビューがあまりにダサすぎたのでヘッダ部分をちょっとマシにしました。

日記のタイトル部分は SVG にしてみました。そろそろ常用してもいいかなという気持ちです。


PC 側もちょっと変えていて、本文の幅を広告と一致するようにしました。なんで今までズレたまま放っていたのが謎ですがようやくすっきりした気がします……

DIP で唯一実用になる(?) ARM Cortex-M0 マイコンです。SRAM が 4KB しかないのが心許ないですが、秋月で現在180円と、性能の割に激安です。

32bit ARM なので、32bit 演算が多少出てくるような場合は AVR より圧倒的に良い選択そうです。(FPU はありませんが)。また mbed は Arduino よりもライブラリデザインがマトモという印象があります。

platformio でコンパイルして、シリアルアダプタ経由で ISP 書きこみするというのを試しました。フレームワーク(ライブラリ)としては mbed を使っていますが、mbed の開発環境は使っていません。

platformio での開発

platformio.ini を以下にようにして

[env:lpc]
platform = nxplpc
framework = mbed
board = lpc1114fn28
build_flags = -std=c++1y

main.cpp を以下にようにしました。

#include "mbed.h"

DigitalOut led(LED1);

int main() {
	while(1) {
		led = 1;
		wait(0.5);
		led = 0;
		wait(0.5);
	}
	return 0;
}

この状態で platformio run をすると .pioenvs/lpc/firmware.bin にコンパイル済みバイナリができます。

platformio は mbed の開発環境を前提としているようで、upload では単に upload_port 先のディレクトリにコピーをしようとします。今回はシリアル経由で書きこむので、platformio 経由での upload は使いませんでした。

ピンアサイン

https://developer.mbed.org/platforms/LPC1114FN28/ このページを見るのが一番良いようです。

上記コード中で指定している LED1 は左下の dp14 になります。

書きこみ

書きこみツールは lpc21isp を使うのが一番簡単なようです。展開して make するだけで OS X でも普通に動きました。

https://sourceforge.net/projects/lpc21isp/files/lpc21isp/ からダウンロードできます。

以下にような感じで書きこめました。115200 は書きこみ時のボーレート、12000 はMCUの動作周波数をkHz単位で指定するようです。内蔵RCは12MHzなので12Mhzを指定しています。が、mbed 実行時は逓倍して48MHzで動いているようなので、どっちを指定するのかよくわかりません。

lpc21isp -control -bin .pioenvs/lpc/firmware.bin /dev/tty.usbserial-A50285BI 115200 12000

ここでは -control を指定しています

         -control     for controlling RS232 lines for easier booting
                      (Reset = DTR, EnableBootLoader = RTS)

となっており、この通りにシリアル変換の DTR を nR (RESET) 、RTS を dp24 に接続することで、自動リセットしてISPモードへ移行して書きこめます。冒頭の写真の通りの配線です。

追記:シリアル通信を行う

上記の方法だと、普通にシリアル通信を行おうとするとRTS/DTRまわりの挙動によってリセットが発生してISPモードに入ってしまうことがあります。なので普通に screen などでシリアル出力を見ることができません。これは RESET の配線を切れば問題ないのですが面倒くさいところです。

実はこれもlpc21ispを使って以下にようにすると、配線を変えずにシリアルモニタができるようです。

lpc21isp -termonly -control /dev/tty.usbserial-A50285BI 115200 12000

コード例

#include "mbed.h"

Serial serial(USBTX, USBRX);
DigitalOut led(LED1);

int main() {
	serial.baud(115200);

	while(1) {
		serial.printf("Hello, World!\n");
		led = 1;
		wait(0.5);
		led = 0;
		wait(0.5);
	}
	return 0;
}

ref.

  1. トップ
  2. tech
  3. LPC1114 LPC1114FN28 / mbed 開発を platformio を使ってやる

SDカードなどを接続したとき、使ってもいない写真.appがいちいち起動してだいぶ鬱陶しいです。以下のコマンドで止めることができました。

defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool YES

昔は Image Capture.app の環境設定からデフォルトの設定が変えられたはずなんですが、El Capitan ではその機能が消滅していて、GUI で変更する方法がないようです。クソですね。

  1. トップ
  2. tech
  3. El Capitan になってから、Mac の写真.appの自動起動がガチでうざい

普段からほとんど常時に「バカにされている」と感じている。基本的には特定の誰かというわけではない。ただしコンテキストによっては特定の誰かの顏が頭に浮かんでいることもある。とはいえそれも、特定の誰かが事実として常に罵倒してくるわけではない。

普通に生きていると、自分の意見というのは、ほとんど尊重されない。自分の中でこの感覚が消化された結果「バカにされている」という主観ができあがるのだろうと思う。

「尊重されなさ」はあらゆることで感じられる。

煙草、特に路上喫煙に殺意(文字通り。)が沸くのはなぜかといえば、臭い煙に困っている自分が尊重されていないと感じるからだと思う。ここで大事なのは、実際にそれをしている喫煙者が尊重してくれないということではなく、そういう喫煙者の存在を許していて、なおかつ自分の存在を許さない(と主観的に感じる)社会が尊重してくれない、ということである。

社会に自分が尊重されていないというのは、自分の存在が否定されていることと同じことです。

自分の中で全ての「尊重されなさ」は社会と通じて繋がっている。仕事で尊重されなくても、道を歩いていて尊重されなくても、それらは繋がっており、自分の中で消化され、バカにされたと感じるわけです。

なんとなく思いたったので Twitter 使うのをやめてみることにします。ここ最近のこと考えてみると、特に Twitter を使っていて得るものはないのではないか、という気がしてきました。

何か思うことがあれば日記として書こうと思います。

はてブもやめて、日記にリンクと思うところを書いたほうがいいかもしれません。そのリンクは日記に書くほどのことなのかを一旦考えてみてもいい気がします。


この日記は tech タグか photo タグ、またはアマゾンの商品リンクが含まれている場合しか Atom フィードにコンテンツを出さないようになっています。なので、クソのような日記エントリをいくら書いても誰にも迷惑になるようなことはありません。

日記はそもそも情報としての価値は低いですから、フィードリーダーで読むようなものではないという気がします。「ウェブサイトを開いて読む」というコンテキストが共有されていないと、変なことを言いだす人もいるので (メディアによって読み手が受けとるイメージが変わってしまい、フィードリーダーだと押し付けがましくなる)、このようになっています。


こういう変な仕様のブログシステムというのはASPではまずありえませんから、やはり自分でブログシステムを作っておくというは、良いと思います。

IrKit を cron から読んで朝起きたとき部屋が暖かくなるようにしていましたが、暖くなってきたので、一旦止めました。

cron の有効無効を手動でやっててアホらしいので温度センサーと連携したいところです。

定本 トランジスタ回路の設計―増幅回路技術を実験を通してやさしく解析 (定本シリーズ) - 鈴木 雅臣

鈴木 雅臣

4.0 / 5.0

定本トランジスタ回路の設計 続 (定本シリーズ) - 鈴木 雅臣

鈴木 雅臣

4.0 / 5.0

一回図書館で借りて一通り読んだのですが、トランジスタ回路の定番パターンと設計方法が一通りまとまっているのがほかになく、参照したいと思うことが多々あるので、買うことにしました。

これこそ電子書籍でPDFになっていてほしいのですが、Tech Villageにはないようです。改訂してPDFにして欲しいです。

ebay で800円ぐらいで買ったものです。

この手のモジュールにはAD9851(源クロック6倍周波数逓倍器付き)のものとAD9850のものがあり、さらに基板のタイプが2つあります。AD9850/AD9851は制御方法も含めてほとんど互換なので、源クロックとチップだけ違うものが出回っているみたいです。

試してみたのはおそらく古いタイプのもので、ブレッドボードには直接挿すことができないので、ちょっと面倒くさいタイプです。

周波数の設定・パワーダウンモードへの移行・設定位相(2台以上のDDSでsin/cos作る場合に使う)を40bitレジスタにまとめて突っ込む形になっています。

この40bitレジスタはパラレルモードとシリアルモードで設定でき、ググると大抵の例でシリアルモードを使ってるみたいです。

ただ、リセット直後はパラレルモードで起動するので、シリアルモードに変えてやる必要があります。といっても、D0=1 D1=1 D2=0 にした状態で、W_CLK パルスを送り、すぐ FQ_UD パルスを送るとシリアルモードに入るということになっています。

このモジュールの場合、ジャンパでD0=1 D1=1 D2=0 を設定できるようになっており、デフォルトでジャンパしてあるので、W_CLK と FQ_UD パルスをマイコンから送るだけで初期化できます。

コード

ライブラリみたいにしてあるのもありましたが、結局自分で書きました。

入手したモジュールは125MHzが源クロックでした。

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

template <uint32_t CLKIN>
class AD9850 {
	static constexpr double PHASE_FACTOR = 0x100000000 / (double)CLKIN;

	const uint16_t PIN_DATA;
	const uint16_t PIN_FQ_UD;
	const uint16_t PIN_W_CLK;
	const uint16_t PIN_RESET;

	void serial_write(uint32_t freq, uint8_t phase, bool powerdown) {
		// freq (delta phase)
		for (int i = 0; i < 32; i++) {
			digitalWrite(PIN_DATA, (freq>>i) & 1);
			digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
			digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
		}

		// control bits
		digitalWrite(PIN_DATA, LOW);
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);

		// powerdown
		digitalWrite(PIN_DATA, powerdown ? HIGH : LOW);
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);

		// phase
		for (int i = 0; i < 5; i++) {
			digitalWrite(PIN_DATA, (phase>>i) & 1);
			digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
			digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
		}

		digitalWrite(PIN_FQ_UD, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_FQ_UD, LOW); delayMicroseconds(4);
	}

public:
	AD9850(
			uint16_t data,
			uint16_t fq_ud,
			uint16_t w_clk,
			uint16_t reset
		) :
			PIN_DATA(data),
			PIN_FQ_UD(fq_ud),
			PIN_W_CLK(w_clk),
			PIN_RESET(reset)
	{
		pinMode(PIN_DATA, OUTPUT);
		pinMode(PIN_FQ_UD, OUTPUT);
		pinMode(PIN_W_CLK, OUTPUT);
		pinMode(PIN_RESET, OUTPUT);
	}
	
	/**
	 * W0 ... W31  -> Freq (LSB first)
	 * W32, W33    -> Control (for factory test)
	 * W34         -> Power-Down
	 * W35 ... W39 -> Phase (LSB first)
	 */

	void reset() {
		// ensure low
		digitalWrite(PIN_DATA, LOW);
		digitalWrite(PIN_FQ_UD, LOW);
		digitalWrite(PIN_W_CLK, LOW);

		// reset
		digitalWrite(PIN_RESET, HIGH); delay(1);
		digitalWrite(PIN_RESET, LOW); delay(1);

		// reset to serial mode
		// Pins of D0, D1 = HIGH, D2 = LOW for serial mode
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);

		digitalWrite(PIN_FQ_UD, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_FQ_UD, LOW); delayMicroseconds(4);
	}

	void set_frequency(uint32_t frequency) {
		set_frequency(frequency, 0);
	}

	void set_frequency(uint32_t frequency, uint8_t phase) {
		uint32_t deltaPhase = PHASE_FACTOR * frequency;
		serial_write(deltaPhase, phase, 0);
	}

	void powerdown() {
		serial_write(0, 0, 1);
	}
};

AD9850<125000000> ad9850(9, 10, 11, 12);

void setup() {
	Serial.begin(9600);

	ad9850.reset();
	ad9850.set_frequency(10e6);
}

void loop() {
}

出力

商品説明だと40MHz まで出せると書いてありました。たしかに出せることは出せるようです。

このモジュールの出力には7次のローパスフィルタがついています。これはAD9851のデータシート通りの定数のフィルタのようで、70MHzぐらいにカットオフ周波数ががあるみたいです。

なおローパスフィルタの後の出力インピーダンスは200Ωになっているみたいです。

AD9850自体の出力は電流出力で、12ピンについている抵抗でフルスケールの出力電流が決まることになっています。このモジュールでは3.9kΩが実装されており、10mA フルスケールの出力に設定されています。200Ωで10mW(10dBm)。実際使う場合バッファして50Ω出力とする必要はありそうです。

片方だけにローパスフィルタが入っており、もう片方の出力は200Ωで電圧変換されて直接ピンヘッダに出ています。ということで差動出力には使えません。





  1. トップ
  2. tech
  3. AD9850 DDS モジュール

AD9850 DDS モジュール に続き AD9851 で、別基板バージョンのものです。

ジャンパとかが一切ない簡略版?なのか進化版?でしょうか。

D0, D1 は 10kΩでプルアップされているので、これらは自分でプルアップする必要はありません。D2 を GND に接続するだけでシリアルモードに入れる実装になっています。

コード

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

template <uint32_t CLKIN, bool MULTIPLIER>
class AD9851 {
	static constexpr double PHASE_FACTOR = 0x100000000 / (double)(CLKIN * (MULTIPLIER ? 6 : 1));

	const uint16_t PIN_DATA;
	const uint16_t PIN_FQ_UD;
	const uint16_t PIN_W_CLK;
	const uint16_t PIN_RESET;

	void serial_write(uint32_t freq, uint8_t phase, bool powerdown) {
		// freq (delta phase)
		for (int i = 0; i < 32; i++) {
			digitalWrite(PIN_DATA, (freq>>i) & 1);
			digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
			digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
		}

		// control bits
		digitalWrite(PIN_DATA, MULTIPLIER ? HIGH : LOW);
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
		digitalWrite(PIN_DATA, LOW);
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);

		// powerdown
		digitalWrite(PIN_DATA, powerdown ? HIGH : LOW);
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);

		// phase
		for (int i = 0; i < 5; i++) {
			digitalWrite(PIN_DATA, (phase>>i) & 1);
			digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
			digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);
		}

		digitalWrite(PIN_FQ_UD, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_FQ_UD, LOW); delayMicroseconds(4);
	}

public:
	AD9851(
			uint16_t data,
			uint16_t fq_ud,
			uint16_t w_clk,
			uint16_t reset
		) :
			PIN_DATA(data),
			PIN_FQ_UD(fq_ud),
			PIN_W_CLK(w_clk),
			PIN_RESET(reset)
	{
		pinMode(PIN_DATA, OUTPUT);
		pinMode(PIN_FQ_UD, OUTPUT);
		pinMode(PIN_W_CLK, OUTPUT);
		pinMode(PIN_RESET, OUTPUT);
	}
	
	/**
	 * W0 ... W31  -> Freq (LSB first)
	 * W32, W33    -> Control (for factory test)
	 * W34         -> Power-Down
	 * W35 ... W39 -> Phase (LSB first)
	 */

	void reset() {
		// ensure low
		digitalWrite(PIN_DATA, LOW);
		digitalWrite(PIN_FQ_UD, LOW);
		digitalWrite(PIN_W_CLK, LOW);

		// reset
		digitalWrite(PIN_RESET, HIGH); delay(1);
		digitalWrite(PIN_RESET, LOW); delay(1);

		// reset to serial mode
		// Pins of D0, D1 = HIGH, D2 = LOW for serial mode
		digitalWrite(PIN_W_CLK, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_W_CLK, LOW); delayMicroseconds(4);

		digitalWrite(PIN_FQ_UD, HIGH); delayMicroseconds(4);
		digitalWrite(PIN_FQ_UD, LOW); delayMicroseconds(4);
	}

	void set_frequency(uint32_t frequency) {
		set_frequency(frequency, 0);
	}

	void set_frequency(uint32_t frequency, uint8_t phase) {
		uint32_t deltaPhase = PHASE_FACTOR * frequency;
		serial_write(deltaPhase, phase, 0);
	}

	void powerdown() {
		serial_write(0, 0, 1);
	}
};

AD9851<30000000, true> ad9851(9, 10, 11, 12);

void setup() {
	Serial.begin(9600);

	ad9851.reset();
	ad9851.set_frequency(10e6);
}

void loop() {
}

AD9851 とほぼ同じですが、6倍の周波数逓倍器がの有効無効化のビットがあるので、その部分だけ実装を変えてあります。

出力

購入したモジュールは 30MHz の源発振のものなので、逓倍後は 180MHz になります。

40MHz ぐらいから出力が低くなります。

ZOUT2 (フィルタあり)



逓倍している分スプリアスが多いようです。


ZOUT1 (フィルタなし)


  1. トップ
  2. tech
  3. AD9851 DDS モジュール

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. アマチュア無線用コモンモードフィルタの特性評価