前回はある程度うまくいきそうというところまでやりました。7MHz 帯のグラフが波うっているのが気になったので詳しく原因を探して解決しました。

いくつかのバンドで測定してみると、7MHz よりも上の周波数では該当する現象が起きないないし起きにくいことに気付きました。そこで 7MHz で固定発振させて出力波形を見てみると、なんとクリッピングしていました……

RFアンプの設計能力がなさすぎて完全にネックになっています。帰還抵抗だけ修正して増幅率を抑えてみました。

おそらく歪みが残っているとは思いますが見た目的には綺麗になっています。

出力が変わっていますがプログラム上では自動的に入力電力で正規化しているので回路の修正以外はいりません。

修正後の 7MHz のグラフ


まだちょっと変ですが大幅に改善されました。既製品と比べ R 成分が大きく観測されている現象もあったのですがそれもなくなっています。

他のバンドのグラフ

ついでに他バンドのグラフをはっておきます。7Mhz 以外は非常に綺麗にグラフが描けます

14MHz

18MHz



21MHz

28MHz


50MHz

抵抗負荷でのグラフ

以下は50Ωダミーロードを測ってみたグラフです。BNC SMA 変換コネクタ経由で、SMA 1W のダミーロードを繋いでいます。非常に綺麗にでます。 が、なぜか抵抗値が高くでています…

75Ωのカーボン抵抗をBNCコネクタに直接つっこんだグラフです。

同じく100Ωカーボン抵抗です。

さらに 150Ωカーボン抵抗。どうもインピーダンスがずれすぎるとだいぶおかしくなります。反射の影響でしょうか?

水晶発振子

目的外ですが水晶発振子の共振特性も見てみました。いずれも水晶単体をBNCコネクタに直接つっこんで見ています。思ったより綺麗にグラフにでました。

12MHz 水晶


20MHz 水晶

コンデンサ

0.1uF セラミック

0.01uF セラミック

47pF セラミック

インダクタ

円筒型の 10uH インダクタ

メモ

綺麗にグラフが書けないことがある。歪んでいるかなにかしてそう

  1. トップ
  2. tech
  3. 簡単かつ安く高精度なアンテナアナライザーを自作したい (2)

いろいろ回路の説明を見たりしていたのは自分で作ってみたかったからです。既製品を1つ持っていますが、海外製なので壊れたときに不安です。自分で作れれば既製品に頼る必要がひとまずなくなるので安心できますし、自分にニーズに応じてニッチな機能を足しやすくなります。

設計というほどではないですが、手軽に作れそうでベストな回路で作ってみることにしました。

構成

  • 発振器は AD9851 (DDS) のモジュール
  • 検波は AD8307 (ログアンプ)
  • 検出器はブリッジ
  • 計測ポイントは3つ
    • リファレンス電圧 (入力電圧の半分)
    • 負荷電圧 (アンテナの入力電圧)
    • 平衡電圧 (リファレンス電圧と負荷電圧の差

測れる原理はアンテナアナライザの回路 - ブリッジの三つの電位差を測るタイプ | tech - 氾濫原で確認しました。

実際の回路

センサー部

AD8307 は1つにします。というのも、AD8307 を複数使う場合、それぞれの特性があってないことを考慮する必要があって面倒だからです。キャリブレーションレスにしたいと思うと1つにするというのは必要要件です。

測定ポイントの切り替えはRFスイッチでやることにします。これには MASWSS0115 (digikey: 1465-1373-1-ND) を使いました。選定理由は

  • MASWSS0115 は単価約70円と安い
  • 電源電圧 2.3V〜5V
  • DC〜3GHz
  • アイソレーションが22dB @ 3GHz (データーシートのグラフを見ると、HF帯ではもっとある)

アイソレーションが低めなのが気になりましたがHF帯でしか使わないので大丈夫そうです。電源はスイッチ入力と共用です。

これを2つ使って、AD8307 の入力前に信号を切り替えます。

DDS+バッファ

このバッファ回路は再考の必要があります。やりたいことはただのバッファです。

MCU

MCU は LPC1114 を使っています。しかしやってることは

  • DDSの制御
  • ADC
  • シリアル通信

だけです。計算処理を入れるとROMにおさまらないので、コンピュータ側で計算します。この構成だとAVRのほうがリファレンス電圧を任意に設定できるのでアドバンテージがあります。Arduino ベースで作りなおしてもいいぐらいです。

書きこみが楽にできるようにピンヘッダを立ててあります。

使えるか

こんな感じで測定できています。なぜか波うっています。ADCの±1エラーもありそうですが、インピーダンスミスマッチでどこかで反射が起きているのかもしれません。外来ノイズ (アンテナなので普通に受信状態にある) も関係ありそうな気がします。よくわかりません。

VSWR の測定 (測定値2つの単純な割り算) では波うってないので、そんなに気にすることもないかもしれません。

既製品で測定した結果のリアクタンスを絶対値になおしたグラフが以下です。そこそこ一致しているように見えます。波うっているのさえなんとかなれば普通に信用にたる測定器がつくれそうです。

いくつかあった問題

RF バッファ

ほぼ唯一の半導体が絡むアナログ回路であるRFバッファ回路でかなり苦労しました。実際組んでみるとまともに出力がでず、かなり苦労しました。上記回路図中のバッファ回路は一応動いたレベルの定数です。どうしても正しくシミュレーションないし設計通りの計算ができず、試行錯誤しました。

  • トランジスタが思いがけず1つ壊れていた
    • ここに気付くまでだいぶ…
  • AD9851 モジュールのフィルタを通ってない出力を使っていた
    • 電流出力なので出力インタピーダンスがシミュレーションと全くあわなかった
    • フィルタ済みの出力にリワーク
  • 定数がおかしかった
    • よくわからないが試行錯誤してしまった

こんな回路もまともに組めないのか、という感じでつらい感じでした。

あとトランジスタの選定を失敗しました。無駄にfTが高いものを使っているのと、Ic が低く、SSM というパッケージだと他のものと互換性が低いので換えにくいです。

RFスイッチ

試していると、片方のRFスイッチで、信号がGND側に通りぬけて、出力レベルが下がっていることがわかりました。

RFスイッチの故障を疑ったりもしましたが、結局電源の接続がちゃんとできていなかったことが原因でした。かなり小さいICなのでなかなか気付きませんでした。

オープンドレインを出力につかっていた

基板のアートワークを作るときに、ピン配置を配線しやすいように変えたのですが、これがもとでうっかりオープンドレインピンを使うようにしてしまいました。当然動かずしばらく悩みました。リワークで対応しました。

まとめ

まだアプリケーションとしては途中ですが、ひとまず動きそうだぞというところまではできました。

測定結果が波うっているのは未解決です。また、RFバッファも微妙なのでもうちょっとマシにするか、素直にバッファICにしてしまいたいです。

  1. トップ
  2. tech
  3. 簡単かつ安く高精度なアンテナアナライザーを自作したい

例によって ebay で300円ぐらいものです。絶対的な解像度はともかく TFT カラー液晶がこの値段だと 16x2 の LCD とかが情報量的にはゴミに思えてきます。(ライブラリサイズとかの兼ね合いもあってそのまま置き換えられるわけではないですが)

購入したものは ST7735 を使っているので、Adafruit-ST7735-Library でだいたい動く雰囲気なのです。以下の2つのライブラリを使える状態にしておく必要があります。

しかし、このモジュールが想定している仕様とは異なる仕様のモジュールのようで、微調整が必要でした。ただし Adafruit-ST7735-Library はクラス構造を private にしているので、残念ながらライブラリ側を無修正のままではどうしようもありませんでした。

最低限の修正に留めるようと、以下のように private を protected にしました。

diff --git a/Adafruit_ST7735.h b/Adafruit_ST7735.h
index 0598720..3b1aa97 100755
--- a/Adafruit_ST7735.h
+++ b/Adafruit_ST7735.h
@@ -152,7 +152,7 @@ class Adafruit_ST7735 : public Adafruit_GFX {
   void     dummyclock(void);
   */
 
- private:
+ protected:
   uint8_t  tabcolor;
 
   void     spiwrite(uint8_t),

実際に使う前に public 継承して初期化処理を奪っています。実際のコードでは冒頭の gif のように millis() を連続して表示させています。

#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h> /* must modify private to protected */
#include <SPI.h>

class TFTST7735 : public Adafruit_ST7735 {
public:
	TFTST7735(int8_t CS, int8_t RS, int8_t RST = -1) :
		Adafruit_ST7735(CS, RS, RST)
	{
	}

	void init() {
		initR(-1);

		_height = 128;
		rowstart = 32;
		colstart = 0;
	}
};

#define TFT_CS     10
#define TFT_RST    9
#define TFT_A0     8

TFTST7735 tft = TFTST7735(TFT_CS, TFT_A0, TFT_RST);

void setup (void) {
	tft.init();
	tft.fillScreen(ST7735_BLACK);
}

void loop() {
	tft.setTextWrap(false);

	// font size is 5x7
	tft.setCursor(5, 5);
	tft.setTextColor(ST7735_RED);
	tft.setTextSize(1);
	tft.fillRect(5, 5, 128, 7, ST7735_BLACK);
	tft.println(millis());

	tft.setCursor(5, 20);
	tft.setTextColor(ST7735_WHITE);
	tft.setTextSize(2);
	tft.fillRect(5, 20, 128, 7*2, ST7735_BLACK);
	tft.println(millis());
	delay(24);
}

所感

128x128 は MCU で扱う解像度としてはかなり広く感じます。文字を dot by dot で表示させると 16x2 などの LCD モジュールと比べてかなり情報量が増えます。カラーなのでさらに情報量が増えます。

描画速度も 16x2 の LCD などよりは早いです。ただしバッファが1つなのであまり書き換えが早いとチラついてしまいます。

デメリットとしては制御コードが複雑になる (フットプリントが増える) ことだと思います。上記のコードはかなりシンプルに見えますがプログラムで23.3%、データで7.7%使っています。ライブラリ側の工夫でもうすこし縮められそうな気はしますが、テキスト表示するならフォントは持たざるを得ないので、16x2 と比べると確実にコード量が増えます。

  1. トップ
  2. tech
  3. ST7735 128x128 TFT カラー液晶モジュール

だいたい300円ぐらいのものです。MAX7219 というLEDドライバを使っていて、SPI で表示を変えられます。(正確には 7219 は SPI 対応とは書いてないのですが、CS の扱いが違うだけ? なのか、ほぼSPIと同じインターフェイスです。よくわかりません)

SPI を使ったことがなかったので一応自分で書いてみました。BCD のデコーダが入っており、数字ぐらいの表示なら自分でLEDとのマッピングを持つ必要はありません。

モードがいくつかあって

  • 全桁自分で制御 (7セグメント+ドットに対応するビットを自分で入れる)
  • 最下位桁だけBCDで残りは自分で制御
  • 上位4桁は自分で制御して、下位4桁はBCD
  • 全桁BCD

と選べます。7セグでアルファベット表示したい、みたいな場合は全桁自分でやる必要があります (マッピングすなわちフォント情報を持つ)

コード

書いたコードでは、全桁BCDでやるようにしてみました。マッピング持つのが面倒なのと、実質自分が使おうと思う用途だと数字以外表示しなそうだな、という気がしています (7セグでアルファベット表示させるのは視認性が悪いので好きじゃない)

SPI 通信はビット数のキリがいいのでハードウェアを使ってやっています。MAX7219 は 10MHz の SPI らしいのでそのようにしてみました。チップセレクトだけコンストラクタに渡すようにしています。

#include <Arduino.h>
#include <SPI.h>

#include <string.h>
class MAX7219 {
	uint8_t CS;

public:
	enum class ADDRESS : uint8_t {
		NOOP = 0b0000,
		DIGIT0 = 1,
		DIGIT1 = 2,
		DIGIT2 = 3,
		DIGIT3 = 4,
		DIGIT4 = 5,
		DIGIT5 = 6,
		DIGIT6 = 7,
		DIGIT7 = 8,
		DECODE_MODE = 0b1001,
		INTENSITY = 0b1010,
		SCAN_LIMIT = 0b1011,
		SHUTDOWN = 0b1100,
		DISPLAY_TEST = 0b1111,
	};

	enum class SHUTDOWN_MODE : uint8_t {
		SHUTDOWN = 0b0,
		NORMAL = 0b1,
	};

	enum class DECODE_MODE : uint8_t {
		NO_DECODE_FOR_DIGITS_7_0 = 0b00000000,
		CODE_B_DECODE_FOR_DIGIT_0_NO_DECODE_FOR_DIGITS_7_1 = 0b00000001,
		CODE_B_DECODE_FOR_DIGIT_3_0_NO_DECODE_FOR_DIGITS_7_4 = 0b00001111,
		CODE_B_DECODE_FOR_DIGIT_7_0 = 0b11111111,
	};

	MAX7219(uint8_t _cs) :
		CS(_cs)
	{
		pinMode(CS, OUTPUT);
	}

	void write(ADDRESS address, uint8_t data) {
		SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
		digitalWrite(CS, LOW);
		SPI.transfer(static_cast<uint8_t>(address));
		SPI.transfer(data);
		digitalWrite(CS, HIGH);
		SPI.endTransaction();
	}
	void begin() {
		SPI.begin();

		setDecodeMode(DECODE_MODE::CODE_B_DECODE_FOR_DIGIT_7_0);
		setScanLimit(7);
		setShutdown(false);

		setIntensity(8);

		for (int i = 0; i < 8; i++) {
			write(static_cast<ADDRESS>(i + 1), 1);
		}
	}

	void setDecodeMode(DECODE_MODE mode) {
		write(ADDRESS::DECODE_MODE, static_cast<uint8_t>(mode));
	}

	void setScanLimit(uint8_t limit) {
		write(ADDRESS::SCAN_LIMIT, limit);
	}

	void setIntensity(uint8_t intensity) {
		write(ADDRESS::INTENSITY, intensity);
	}

	void setShutdown(bool shutdown) {
		write(ADDRESS::SHUTDOWN, static_cast<uint8_t>(shutdown ? SHUTDOWN_MODE::SHUTDOWN : SHUTDOWN_MODE::NORMAL));
	}

	void print(const char* buf) {
		size_t len = strlen(buf);
		uint8_t digit = 0, dp = 0;
		for (size_t i = 0; i < len && digit < 8; i++) {
			const char c = buf[len - i - 1];
			if (c == '.') {
				dp = 1<<7;
				continue;
			} 

			uint8_t b;
			if (c == '-') {
				b = 0b1010;
			} else
			if (c == ' ') {
				b = 0b1111;
			} else
			if ('0' <= c && c <= '9') {
				b = static_cast<uint8_t>(c - '0');
			} else {
				continue;
			}

			write(static_cast<ADDRESS>(digit + 1), b | dp);
			dp = 0;
			digit++;
		}

		for (; digit < 8; digit++) {
			write(static_cast<ADDRESS>(digit + 1), 0b1111);
		}
	}
};


MAX7219 leds(10);

void setup() {
	leds.begin();
	leds.print("-1234.567");
	delay(3000);
}

void loop() {
	leds.print(String((float)micros() / 1000).c_str());
	delay(29);
}
  1. トップ
  2. tech
  3. MAX7219 8桁 7セグメント LED モジュール / Arduino

切削を2回ぐらい失敗したあと、そこそこ良さそうなのができたので、実装してみました (まだ途中ですが)。右側でブリッジしているような部分がありますがこれは設計上の意図的なもので、右側はほぼ完璧です。

マクロで撮るとスケール感がわかりにくいので右側に SOIC のパッケージのものも入れています。ほぼ同じサイズで約2倍のピンが並びます。

残念ながらプレッシャーフットなどがないのでワークのZ軸に傾きがあり、これがどうしても消せませんでした。左側は低くて、右側は高い (といっても0.1mm〜0.2mm程度の傾き) という状態です。ほとんど基板に触れない状態から切削を開始して、ダメそうなら 0.02mm ずつZを下げていきました。これ以上下げるとTSSOPの部分のパッドが消滅しそうなのでやめました。

左側は手作業でショート部分を削ったのでだいぶ汚ないです。

一応 TSSOP も実装できそうです。しかし、このサイズ (30mmx23mm程度) でも傾きがこれほど問題になるので、もっと大きな基板では現状のセッティングではまず無理そうです。プレッシャーフットを自作するか、あるいは基板を固定しているジュラコンを精密に水平出しをすればいけるのかあるいは設定を詰めればいけるのか、よくわかりません。プレッシャーフットも万能ではないのでなんともいえなそうです。


やはり気楽にやれる範囲は SOIC ぐらいだと思います。実装の点でも SOIC まではルーペなしで実装可能ですが、TSSOP ぐらいからルーペ確認が必須になってきます。

主要ピン幅

  • DIP : 2.54mm
  • SOIC: 1.27mm
  • TSSOP: 0.65mm
  • MSOP: 0.5mm

先端 0.1mm、60度のVカッターだと0.1mm の深さで幅 0.215mm。

ソルダーマスク

このように PCB Milling で普通に作るとソルダーマスクがないので、ハンダブリッジをとても起こしやすい状態になります。

いくつか作って実装してみてわかりましたが、表面実装品ではソルダーマスクがなくても案外ブリッジしません。一方でリード品をハンダづけすると高確率でブリッジします。

これはおそらく使用するハンダの量の違いだと思います。また、リード品だとリードが邪魔で正確にコテ先をあてにくいのも一因としてありそうです。

TSSOPでもパッドがしっかり成形できていれば、ハンダ付け自体にはそれほど困難に感じません。ただしフラックスは必須です。

「リード部品のほうがハンダ付けしやすい」という刷り込みを持っていたので、意外な発見でした。

  1. トップ
  2. tech
  3. PCB Milling で TSSOP

/**
zun-doko-kiyoshi in ARM Linux EABI
 */

.section .text
.global _start

.macro sys_write
        mov r7, $0x04
        svc $0x00
.endm

.macro rand_init
        /* using all high resiters for rand: r8-r12 */
        /* set seed from time */
        ldr r0, =time
        /* sys_time */
        mov r7, $0x0d
        svc $0x00
        ldr r0, =time
        ldr r8, [r0]
        /* load constant for rand */
        ldr r9, =1103515245
        ldr r10, =12345
        ldr r11, =2147483647
.endm

.macro rand
        /* random update r8 */
        mov r12, r8
        mla r8, r12, r9, r10
        and r8, r8, r11
.endm


_start:
        rand_init
        /* r6 is current zun count */
        mov r6, $0

loop:
        rand
        /* check bit / eq = zun, ne = doko */
        tst r8, $0x80
        adreq r1, zun
        moveq r2, #zun_len
        addeq r6, $1
        adrne r1, doko
        movne r2, #doko_len
        mov r0, $0x01
        sys_write
        bne check_kiyoshi
        b loop

check_kiyoshi:
        /* now this is doko state and check zun count */
        cmp r6, $5
        /* zun count is greater than 5 */
        bge call_kiyoshi
        /* failed to call kiyoshi and reset state */
        mov r6, $0
        b loop

call_kiyoshi:
        /* now this is kiyoshi state */
        adr r1, kiyoshi
        mov r2, #kiyoshi_len
        mov r0, $0x01
        sys_write
        mov r0, $0x00
        /* sys_exit */
        mov r7, $0x01
        svc $0x00

zun:
        .string "ズン\n"
zun_len = . - zun
        .align 2

doko:
        .string "ドコ\n"
doko_len = . - doko
        .align 2

kiyoshi:
        .string "キヨシ\n"
kiyoshi_len = . - kiyoshi
        .align 2


.section .data
time: .word 0

cross compile

 arm-linux-gnueabi-as ./sketch.s -o sketch.o && arm-linux-gnueabi-ld -o sketch -e _start sketch.o && qemu-arm-static ./sketch
  1. トップ
  2. tech
  3. arm-linux-eabi でのアセンブリ ズンドコ

ほんとにイライラすることばかりが起きる。なんでこんなめにあうのか。本当の意味がわからない。

いくら自分から面白いことを探そうとしても、ひたすらに不幸が追いかけてくる。嫌なことは自動的に毎日起き続けるのに、面白いことは追いかけても逃げていく。


とにかくこの毎日嫌なことばかりが起きるのをなんとかしたい。

自分の中からはただただやりたいことが沸いてくる。大半の嫌なことは他人に起因していて、

  • 嫌なことを言われる
  • 嫌なことを言われると予期される
  • 嫌なことをやらされる

となる。しかし他人に起因することは自分にどうすることもできない。無力。原因が解決しないので、運用でカバーとするしかないが、運用力がない。

もっと果てしないスルー力があれば解決するかもしれない。どのようにしてそれを手に入れればいいかはわからない。他人の重要性をもっともっと下げていきたい。お前らとかどうでもいいと思えるようになりたい。他人の評価を全て無視したい。

とにかくなんとかしてストレス解消したい。最近とことん些細なことでイライラする。

精神的余裕がないのに、追い討ちをかけるような事態しか起きない。ひどいめにあうということしかない。インターネットのほうがまだ安全ではないか。

自分は自分のルールで生きており、つまりこのルールは道徳ないし宗教なので、他人にどうこう言われるようなものではない。ただ生きてるわけでもなく、自分のルールに従って生きている限り、それをどうこう言われる筋合いは全くない。

事情を知らない人間はクソなことを言ってくる。お前の事情なんてこちらとしても存じあげない。コミュニケーションをしないやつに、コミュニケーション能力が低いと罵られる意味はなんだ。

中華AD8307のテストをしてみましたが、これはうまくいけばモジュールとして使えるようにピンヘッダを立てて作りました。

テストした感じでは使えそうなので、まずパワー計として動かしてみることにしました。

といっても、MCUのADCで読んで計算するだけです。

ただ、AD8307 そのままだと入力範囲が -76dBm〜+16dBm と、普段使うには電力範囲が小さいほうに寄りすぎているため、25dB のアッテネータを前段に挿入し、-51dBm〜+41dBm の範囲としました。

耐電力の大きなアッテネータは面倒なので、1/2W 抵抗を使い、定格1W程度、極めて短時間なら10W程度というイメージです。

使用感

実際10W入力すると3秒ぐらいでかなり発熱するのでこわいです。5W ぐらいまでなら〜5秒耐えられそうです。

確度

アッテネータの絶対的な誤差は簡単な校正で消せます (インターセプトが移動してるだけなので) 。AD8307 自体のログとの一致性は±1dB。

ただ、入力周波数によって出力電圧が結構変わりますので、確度を求めるなら周波数カウンタ機能をつけて、周波数も変数にして校正したほうが良さそうです。

例えば10MHzと500MHzだと、出力電圧にほぼ固定で10dB分の差があります (1ケタ!!)。一応、この差は周波数に応じてほぼ固定なので、入力周波数がわかっていれば簡単に補正はできます。

↓ はデータシート記載のものと、実測のもの


今回は周波数を測ってない以上、全域での絶対的な確度はあまり期待できません。

計測できた電力値が実際より大きい分にはあまり問題ではありませんが、実際よりも小さい値が表示されると、これを信じて他の機器につないだときに過大入力になることがあり、よくありません。安全策としては上限周波数で校正をかけることでしょう。

ただし、前段についているアッテネータの特性的に300MHzぐらいが上限です

用途

明確な出力が不明な信号源の場合、直接スペアナに繋ぐまえに、一旦チェックする用として使いたい気持ちです。瞬間的になら10W入力できますし、これなら壊れても痛くありません。

コード

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "interval.hpp"

static const float SLOPE = 26.367;
static const float INTERCEPT = -63.51879243;


LiquidCrystal_I2C lcd(0x27, 16, 2);
String formatWatts(const float watts) {
	if (watts < 1e-3) {
		return String(watts * 1e6) + "uW";
	} else
	if (watts < 1e-1) {
		return String(watts * 1e3) + "mW";
	} else {
		return String(watts) + "W ";
	}
}

void setup() {
	Serial.begin(115200);
	Serial.println("init...");

	Wire.begin();

	lcd.begin();
	lcd.backlight();
	lcd.setCursor(0, 0);
	lcd.print("Hello, World");
	lcd.setCursor(0, 1);
	lcd.print("TEST");
}

void loop() {
//	interval<1000>::run([]{
//		Serial.println("1000ms");
//	});

	uint16_t adc_raw = analogRead(0);
	Serial.print("ADC Got = "); Serial.println(adc_raw);
	float adc = static_cast<float>(adc_raw) / 1024 * 5;

	Serial.print("ADC Voltage = "); Serial.println(adc * 1000);

	float dBm = (adc * 1000 / SLOPE) + INTERCEPT;
	Serial.print("dBm = "); Serial.println(round(dBm));

	float watts = pow(10, dBm / 10) / 1000;
	Serial.print("W = "); Serial.println(watts);
	Serial.print("mW = "); Serial.println(watts * 1000);

	lcd.setCursor(0, 1);
	lcd.print(round(dBm));
	lcd.print("dBm");
	lcd.print("                ");

	lcd.setCursor(0, 0);
	lcd.print(formatWatts(watts));
	lcd.print("                ");

	delay(500);
}
  1. トップ
  2. tech
  3. 中華AD8307をデジタル電力計にしてみる

25dB で SMA 入出力のアッテネータが欲しくなったので作ってみました。アッテネータを作ってみるのは初めてです。

回路

アッテネータの計算機 を使って必要な抵抗値を求め、抵抗計算のサイトでどうやって近い値を作るかを調べ、このようにπ型のアッテネータ回路にしました。

ボードレイアウト

小さくつくりたかったので全部縦に並ぶようにしてみましたが、入出力が近くなるので、こう実装するのはあんまり良くなさそうな気がします。

結果

挿入損失

300MHz ぐらいまではそこそこフラットにみえます。

リターンロス

300MHz ぐらいまでなら SWR=1.2 未満になりそうです。

  1. トップ
  2. tech
  3. 高周波用アッテネータを作ってみる

中華AD8307をいくつか手に入れてみたので、ちゃんんと使えるのか実験してみました。というのも、値段的にどう考えてもコピー品だからです (単価50円ぐらい)

回路とボードレイアウト

回路はAD8307のデータシートに記載がある以下の「基本的な接続」の回路ほぼそのままです。電源のデカップリング用の 4.7Ω はフェライトビーズに変え、入力抵抗 52.3Ωは100 // 110Ωで作っています (が、手元に110Ω抵抗がなかったため100 // 220 // 220 Ω)

ボードレイアウトは以下のようにしました。PCB Milling で作るため必ずしも理想的とはいえません。

測定

手元にある信号発生器だと、スペアナのトラッキングジェネレータ出力が一番信用できるので、これを使いました。ただし出力が-20dBm〜0dBmまでを1dB単位でしか出せないので、出力がもうすこし大きくなって飽和近くになったときどうなるかはわかりません。周波数は10MHz固定です。

ということでこのようになりました。確かにログアンプになっているようで、綺麗に dB に対して直線になっています。

傾きは 24mV/dB (= (2230-1750)/20 ), インターセプトは -92.9dBm ぐらいにあります。

AD8307 本来の仕様的にはインターセプトは -87〜-77dBm なのですが、これはずれています。原因はよくわかりません。入力インピーダンスが正確に50Ωになっていない(アンテナアナライザーで測ると約52Ω)影響かもしれません。

追記

500MHz まで段階的にはかりました。

広い範囲にしてみてみると、傾き 25.5mV/dB、インターセプト-87dBm ぐらいに見えます (10MHz時)。こんなもんなのかもしれません。

まとめ

ひとまずログアンプとしては動いているようなので使えそうです。インターセプトのずれは実装の問題なのかICの問題なのかはよくわかりませんのでとりあえず保留としようと思います。自分の場合出力を必ずADCに接続するので、ここが多少ずれていても大丈夫ではあります。

余談

表面実装品のテストにPCB Millingをはじめて使ってみました。PCB Millingとしては、こういう使いかたをするのが一番の目的だったので、ひとまずうまく実験できて良かったです。SOIC は割と足の間隔が広いので、あまり細かいことができないPCB Millingでも十分いけることがわかりました。

  1. トップ
  2. tech
  3. 中華AD8307を使ってみる

ちょっと針が動いて楽しいアナログ計が欲しいなと思っても、昨今ではラジケータ(ラジオ用の精度の低い電流計の総称)もかなり高価で、秋葉原だと安くても500円〜という感じです。この値段だと、インターフェイスの味つけ程度のために買おうとは思いません。

ふと思いたって ebay で analog panel meter で検索してみると、100円程度で売られているものがありました。仕様的には AC 0-300V と、かなり高圧のフルスケールのものです。とはいえ、どうせ抵抗が入ってるだけなので、ちょっと改造すれば使えそうだと思い買ってみました。

仕様

見ての通りパネル全面にダイオードと抵抗がついています。簡単にはずせそうで便利ですね。このダイオードと抵抗は無視して、電流計本体のフルスケールと内部抵抗を測りました。

フルスケールはだいたい1500uA(1.5mA)ぐらいのようです。このとき、電圧は 620mV でしたので、内部抵抗は約413Ωです。


あまり格好いいメータとはいえませんが、スケールを貼り替えてカバーを塗装すれば多少マシになるかもしれません。ただ針の振れかたも安っぽく、ヒゲゼンマイのトルクがいまいちという感じがします。

とはいえ、ちょっとしたケースでデジタルPWMに繋いでアナログ表示させてみるみたいなケースでは使えそうです。3.3V なら 1.8kΩ、5V なら 2.9kΩ を直列に繋げばちょうどよさそうです。

  1. トップ
  2. tech
  3. 100円ぐらいで売られている中華ラジケータ(アナログパネルメータ)を試す

先日

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

http://lowreal.net/2016/02/22/1

と書きました。これの原因のちゃんと調べてみました。

まずAD8307 のデータシートには以下のような記述があります。

In most applications, the signal is single sided and can be applied to either Pin 1 or Pin 8, with the other pin ac-coupled to ground. Under these conditions, the largest input signal that can be handled by the AD8307 is 10 dBm (sine amplitude of ±1 V) when operating from a 3 V supply; 16 dBm can be handled using a 5 V supply. The full 16 dBm can be achieved for supplies down to 2.7 V, using a fully balanced drive.

要約すると、

  • シングルエンドアプリケーション時 (入力の片方のピンがAD8307のGNDに接続されている場合) は 3V のとき 10dBm までの入力が可能。
  • 差動接続の場合は2.7Vでも16dBmまでの入力が可能

と書いてあります。

これを見て 3V でも +10dBm まで使えそうだな、と思ってしまいました。

出力が頭うちに

しかし実際 3.3V で使ってみると、10dBm 入力しても想定した出力がでません。よくよく調べてみると、英語版の最新データシートだと以下のような記述がありました。

Note that while the AD8307 can operate down to supply voltages of 2.7 V, the output voltage limit is reduced when the supply drops below 4 V. This characteristic is the result of necessary headroom requirements, approximately two VBE drops, in the design of the output stage.

要約すると 出力回路に2つのトランジスタがあるので、4V未満ではこれらの 分出力が低下するよ、という感じのようです。出力回路の制限なわけですね。

が 0.7V とすれば2つで1.4V、電源電圧が3.3Vなら、出力電圧は1.9Vまで低減されます。これを入力 dBm に換算すると-8dBm付近になります (実際の によります)。

が -84 dBm、 が 25mV/dB で が 1.9Vだと -8dBm になります。

ということで、実測だと 3.3V 時に出力が頭うちになるのは完全に「仕様」なのでした。

結論

つまり、3.3V で使う場合で、-8dBm 以上入力させたいなら、傾きの調整が必須なのです。

傾きを 20mV/dB にすれば、 1.9V で +11dBm になります。20mV/dB に設定する方法はデータシートにそのまま載っていて、32.4kΩの抵抗と50kΩの可変抵抗を直列にして AD9807 の OUT と COM に接続 (内部の出力抵抗と並列に接続) して調整すれば良いようです。

といっても調整するのが面倒なんですが…

  1. トップ
  2. tech
  3. AD8307 を 3.3V で動かすときの罠

はぁほんと心底 Spring とか嫌だ…… なんでこんなクソなことをしないといけないのか。普通に書きたい……