LC共振周波数を利用したインダクタンスメータ
2008/05/25 Nishimura Hiromi
最近のデジタルテスターには抵抗値やコンデンサーの容量を計測できるようになっています。でもコイルのインダクタンスを計測できるテスターはめったに見ません。とりあえず必要になったのでいつもの秋月電子からM-3870Dを購入。候補にはSLCR-9073もあがっていたのですがM-3870Dなら普通のテスターにも使えるし....と思ったもので。
結果的に失敗、というかよく吟味しなかったのが失敗の原因でした。その原因とは、測定レンジが最低で 400mH で最小桁が10μHだったのです。私が使おうと思っていたインダクタンスの範囲は1μH〜数mHです。よって全然使えないインダクタンスメータだったのです。
そんな訳で、また探す事に。インターネットで検索したら色々ありました。秋月電子のキット製作記事が多いようです。他にも色々ありましたが、特に興味を持ったのが「おじさん工房のLCメータ」や「PY2WMさんのLCmeter」でした。そこで同じようなキットが無いか探したらストロベリー・リナックスに「ポケットL/Cメーターキット」なるものがありました。でもページを見ると
どうも発売終了のようです。
[2008/09/04] 追記
ストロベリー・リナックス社の「ポケットL/Cメーターキット」ですが Ver.2 が発売されていました。よって発売終了ではなかったようです。とはいっても、もう自作してしまったので購入どうするか。間違った情報を書いてしまっただけ に義理でも購入かな? さっそく注文しようとアクセスしたら代引きは¥10000以上だって! 私はネットで代引き以外の購入はしないことになっているの で止めました(残念です!)。前回、USBガイガーカウンタの時は¥20000を超えていたので代引きが使えたようです。
原理は判っているのだからこうなりゃ作るしか無い、ということで作ってしまいました。このLCメータは既知値を持つコンデンサー Cと測定対象のコイルLのLC共振周波数からインダクタンスを計算するタイプです。計測時の周波数におけるインダクタンスを測る装置ということになります。
● 発振回路
LC発振回路は色々ありま すが計測範囲のインダクタンスで確実にしかも安定して発振できる回路はそう多くありません。そこで今回はフランクリン回路を使う事にしました。回路図を下 記に示します。

図1:フランクリン発振回路
C-MOSインバータを 使っています。Rはバイアス用です。発振条件は非常に緩くC<Ca<Cbであれば数Hzから数MHzまで安定して発振するよ うです。ただCa,CbとRで自走発振するので計測範囲の発振周波数に入らないようにした方が良いようです。色々試したら上記回路の定数が広い範囲で発振してくれそうなので、これに決定しました。
もう一つ、この回路には面 白い特徴があります。それはLC共振回路のかわりに外部から交流信号を入力すると入力した信号に同期した出力が得られるという点です。もうおわかりです ね。LC共振周波数を利用したインダクタンスメータは図1の発振回路と、その周波数を計測する周波数カウンタからなります。ということは計測端子に未知の 周波数の信号を入力するとその周波数が計測できる、そうですLC共振周波数を利用したインダクタンスメータは何の改造もなしに周波数カウンタとしても使え る訳です。
● 実際の回路
図1のままではキャリブ レーションができません。そこで次のような回路で計測端子をショートしたときキャリブレーションできるようにします。周波数カウンタやコイルの自己共振周波数を計測するときはLo,L,Cを取り外します。

図2:キャリブレーションが できる回路
図2を見て判るよう、単に 未知のLと直列にコイルLoを追加しただけです。このLoによりLをショートしても発振は停止しません。Lのショートはキャリブレーション時に使います。
● Lの計算
計測端子をショートした時 の共振周波数をfo、未知のインダクタンスを持つコイルLxを接続した時の共振周波数をfxとします。これを式で表すと次のようになります。

この式からLxを求める と、

これが未知のコイルLxの インダクタンスを計算する式です。
例
C = 0.1012E-6; ~ 0.1012μF
fo = 74110; ~ 75.110KHz
fx = 15744; ~ 15.744KHz
Lx = (fo^2-fx^2)/(fx^2*fo^2)/(4*π^2*C);
Lx*1000;
0.9642
.OK.
未知のコイルLxのインダク タンスは 0.9642mH であることが判りました。
● Loの注意
Lo に使用するコイルはで きるだけトロダイル型(磁束が外部に漏れないというより外部の影響を受けない)が望ましいです。理由は外部の環境、たとえばキャリブレーションをとっても 計測時にLoの近くに透磁率の異なる物があると影響を受けます(私はこれで失敗しました)。特にμH単位のコイルの計測時には大きな影響を受けま す。シールド用にアルミケースに入れても残念ながらダメです。アルミは磁気的に紙みたいなものでまったく効果ありません。実際に磁気センサーはセンサー保 護にアルミパイプを使っている位ですから。
● Cの計算
上記式はLとCを交換して もなりたちます。すなわちLC共振周波数を利用する方法ではインダクタンスだけではなくキャパシタンスメータとしても使えることになります。先の周波数カ ウンタも含めると一台で3つの機能を持つ計測器が作れる訳です。
● LCメータ&周波数カウンタ
実際に作ったLCメータ& 周波数カウンタの回路図を下記に示します。LCD表示部分は以前のDDS制御に使ったものです。
インダクタンスの計測時に は0.1μFのコンデンサーを使い、キャパシタンスの計測の時には0.001μFのコンデンサーを使うようにしています。同 じコンデンサーを使っても良いのですが分離した方がより広範囲で安定した計測結果が得られるためです。インダクタンスの計測範囲は 1μH〜200mHで、キャパシタンスは 1pF〜5μF程度です。周波数カウンターは自走周波数が4~7Hzなのでそのだいぶ上の50Hz付近から2.2MHzまででした。上限は PICのクロックが10MHzのためです。
● 感想
はっきりいって、今回のインダクタンスメータは非常に安定した値が得られ、作って正解でした。1μH以下も計測できるのではないと思われる程です (アマチュア用としては十分ではないかと)。問題点は2つあります。まず共振回路の安定がいまいちで電源ONから数分待たないと周波数が安定しません。そ のため1μH付近では電源ONで即計測とはなりません(程度の問題で私は気にしませんが)。100μH以上だと殆ど影響ありません。もう一つ は温度の影響です。室温に結構影響されます。特に積層セラミックを手でつまんでから計測すると容量が小さく表示され室温になるまで容量が上昇します。これ はLCメータの問題ではなく計測対象の温度特性が問題なんでしょうが非常に温度に敏感な点が気になります。回路内部にも積層セラミックを多用している(共振部分ではないですが)ので.... まあ表示桁数が多いだけに数値が変動するのが気になるだけかもしれません。そう、表示桁数を3桁におさえれば全く変動なしなので気になる方は小さくして下さい。
今回作ったLCメータはLCメータとして使うだけではなく周波数カウンタとしても使うことができました。更に別の使い方として周波数カウンタモードでコイ ルを接続すると自己共振周波数が判ります。またタンク回路を接続すると共振周波数が判ります。当初はインダクタンスメータとしてだけ使う予定だったのです が今ではフィルタ製作の方に多用しているような状態です。
実はいつもの癖で作ったインダクタンスメータはこれだけではありません。秋月のキットと同じ同期検波方式のインダクタンスメータも試してみました。悪くは 無いですがアナログなだけに調整が面倒。コイルの抵抗成分が大きいマイクロインダクタでは正確な値が得られない。他にもコイルに加える交流電圧と電流の カーブ、この面積からインダクタンスを求める方法も試してみました。非常に正確な値が得られます。またDDSの出力を増幅しコイルに加えるので特定の周波 数におけるインダクタンスが計測できました。でも同期検波方式と同じくコイルの抵抗成分により計測範囲が決められ簡便ではありません。結局、共振回路を 使った方がレンジ切換え無しで 1μH〜200mHの計測ができ、便利だったので残り2つは宝(ジャンク)箱へ直行となりました。
● PICプログラム
下記はPIC16F88用の プログラムです。参考程度にお使いください。
■ LC Meter & Frequency Counter
//***********************************************************
// L/C Meter & Frequency Counter
// 2007/11/05 by Nishimura Hiromi
//
// 2007/11/05 ver 1.0.0
// 2007/11/06 ver
1.0.1
周期計測から周波数計測に変更
// 2007/11/06 ver
1.0.2
周波数表示をHzからKHzにちょっと改良
// 2007/11/07 ver 1.0.3 校 正方法を根本的に改良
//***********************************************************
#include "LCMeter.h"
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#ZERO_RAM
//***********************************************************
#use fast_io(a)
#use fast_io(b)
#define Amode 0x32 //port A initial mode
#define Bmode 0x01 //port B initial mode
#byte db
= 6
//port
B
#byte da
= 5
//port
A
//***********************************************************
#define LEDout PIN_A0 // OUT 計 測ステータス表示用LED
#define FreqCntYNin PIN_A1 // IN Low で周波数カウンタモード
#define LCchangeRY PIN_A2 // OUT Low でLメータ
#define CounterGate PIN_A3 // OUT High でカウント開始
#define LCcheckIn PIN_A5 // IN Low でLメータモード
#define doCalibration PIN_B0 // IN キャ リブレーションの実行
#define Cap0 0.098900E-6 // L メータ時に使用するコンデンサーの容量
#define Cap1 0.001018E-6 // C メータ時に使用するコンデンサーの容量
//***********************************************************
// Port define and link LCD library
//
#define rs PIN_B1 //LCD chip select
#define rw PIN_B2 //LCD read/write
#define stb PIN_B3 //LCD strobe
//
#include "lcd_lib.c"
//
//***********************************************************
// 大 域変数
int mode; // 計 測モード
// mode=0 L 計測モード
// mode=1 C 計測モード
// mode=2 周 波数カウンタモード
// mode=3 L キャリブレーションモード
// mode=4 C キャリブレーションモード
int beMode; // 前 回のモード
int mesDoing; // 計 測実行ステータス
long tcovf; // タ イマーカウンタオーバーフロー
float freq; // 周 波数
float CFref; // C キャリブレーション値(周波数)
float LFref; // L キャリブレーション値(周波数)
float Loref; // 基 準インダクタンス
float Coref; // 基 準キャパシタンス
//
//***********************************************************
// 割 り込み処理
//
// 入 力信号をカウントする
#int_RTCC
void RTCC_isr()
{
tcovf++;
}
// CPU のクロックをTMR1で分周しカウント周期時間を作る
#int_TIMER1
void TIMER1_isr()
{
int32 fr1,fr2;
// 基準時間に達したら割り込みを禁止する
disable_interrupts(GLOBAL);
disable_interrupts(INT_RTCC);
disable_interrupts(INT_TIMER1);
// 信号入力ゲートを閉じる
output_low(CounterGate);
// 信号の周波数を得る。結果は大域変数のFreqへ代入
fr1 = (unsigned int32)get_timer0();
fr2 = (unsigned int32)tcovf;
freq = ((float)tcovf*256.0+(float)fr1)*4.768371582;
// 周波数計測が終了したことを知らせる
mesDoing = false;
}
//
//***********************************************************
// LCD へ文字列を表示
//
void lcd_dispString(char *str)
{
int i;
for(i=0;i<strlen(str);i++) lcd_data(str[i]);
}
//
//***********************************************************
// 割 り込み禁止
//
void disable_LCMeterInterrupt()
{
disable_interrupts(GLOBAL);
disable_interrupts(INT_RTCC);
disable_interrupts(INT_TIMER1);
}
//
//***********************************************************
// 周 波数計測開始
//
void startMesure()
{
// タ イマーの設定
setup_timer_0(RTCC_EXT_H_TO_L|RTCC_DIV_1);
set_timer0(0);
tcovf = 0;
// 割 り込みを許可し計測モードに入る
mesDoing = true;
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
output_high(CounterGate); // TMR0 入力ゲートON
set_timer1(0);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
//
}
//
//***********************************************************
// モー ド表示
//
void disp_ModeType()
{
if(mode==2){
lcd_clear();
lcd_cmd(0x0c);
lcd_data("FreqencyMode");
}
// lcd_clear(); lcd_cmd(0x0c);
// if(mode==0) lcd_data("L-Meter Mode");
// else if(mode==1) lcd_data("C-Meter Mode");
// else lcd_data("FreqencyMode");
}
//
//***********************************************************
// L メータモードリレー設定
//
void setup_LMeterRelayMode()
{
mode = beMode = 0;
output_low(LEDout); // LED を赤の状態にする
output_low(LCchangeRY); // リ レーをLメータモードにする
output_low(CounterGate); // TMR0 入力ゲートOFF
}
//
//
//***********************************************************
// L メータモード設定
//
void setLMeterMode()
{
// 割 り込みを禁止する
disable_LCMeterInterrupt();
//
setup_LMeterRelayMode();
//
// disp_ModeType();
startMesure();
}
//
//***********************************************************
// C メータモードリレー設定
//
void setup_CMeterRelayMode()
{
mode = beMode = 1;
output_low(LEDout); // LED を赤の状態にする
output_high(LCchangeRY); // リ レーをCメータモードにする
// output_low(LShortRY); // 入 力を開放モードにする
output_low(CounterGate); // TMR0 入力ゲートOFF
}
//
//***********************************************************
// C メータモード設定
//
void setCMeterMode()
{
// 割 り込みを禁止する
disable_LCMeterInterrupt();
// リ レーを設定
setup_CMeterRelayMode();
// 計 測の開始
// disp_ModeType();
startMesure();
//
}
//***********************************************************
// 周 波数カウンタモード設定
//
void setFCounterMode()
{
// 割 り込みを禁止する
disable_LCMeterInterrupt();
// リ レーを設定
mode = beMode = 2;
output_low(LEDout); // LED を赤の状態にする
output_high(LCchangeRY); // リ レーをCメータモードにする
output_low(CounterGate); // TMR0 入力ゲートOFF
// 計 測の開始
disp_ModeType();
startMesure();
//
}
//
//***********************************************************
// 周 波数を表示する
//
void disp_FreqValue(float f)
{
char str[16];
sprintf(str,"Frq=%8.3f KHz",f/1000.0);
lcd_cmd(0xC0);
lcd_dispString(str);
}
//
//***********************************************************
//
//
void calcLoCo()
{
if(LFref>0.0) Loref = 1.0/(4.0*PI*PI*LFref*LFref*Cap0);
Coref = Cap1;
}
//
//***********************************************************
// モー ドを変更する
//
void changeMode(int mode)
{
if(mode==0) setLMeterMode();
else if(mode==1) setCMeterMode();
else setFCounterMode();
}
//
//***********************************************************
// イ ンダクタンスのキャリブレーションを実行
//
void doCalInductance()
{
int c = 0;
float tmp = 0.0;
// 割 り込みを禁止する
disable_LCMeterInterrupt();
//
setup_LMeterRelayMode(); // TMR0 入力ゲートOFF
// 校 正計測中の表示
lcd_clear(); lcd_cmd(0x0c);
lcd_data("L-Meter Cal.");
disp_FreqValue(freq);
// 計 測開始
startMesure();
// 20 回の平均を使用
while(true){
if(mesDoing==false){
if(freq>210000){
tmp += freq;
c++;
if(c>=20) break;
}
disp_FreqValue(freq);
startMesure(); // 計 測再開
}
}
LFref = tmp/20.0;
disp_FreqValue(LFref);
output_high(LEDout);
delay_ms(100);
}
//
//***********************************************************
// キャ パシタンスのキャリブレーションを実行
//
void doCalCapacitance()
{
int c = 0;
float tmp = 0.0;
// 割 り込みを禁止する
disable_LCMeterInterrupt();
// リ レーの設定
setup_CMeterRelayMode();
// 校 正計測中の表示
lcd_clear(); lcd_cmd(0x0c);
lcd_data("C-Meter Cal.");
disp_FreqValue(freq);
// 計 測開始
startMesure();
// 20 回の平均を使用する
while(true){
if(mesDoing==false){
if(freq>155000){
tmp += freq;
c++;
if(c>=20) break;
}
disp_FreqValue(freq);
startMesure(); // 計 測再開
}
}
CFref = tmp/20.0;
output_high(LEDout);
disp_FreqValue(CFref);
delay_ms(100);
}
//
//***********************************************************
// バー ジョンの表示
//
void disp_version()
{
lcd_clear(); // clear display
lcd_cmd(0x0c); // no cursor
lcd_data("LCMeter V 1.0.3"); // version
// lcd_cmd(0xC0);
// lcd_data(" 2007/11/07 NiS");
delay_ms(1000);
}
//
//***********************************************************
// キャ リブレーションが必要であることを表示
//
void need_calibration()
{
lcd_clear();
lcd_cmd(0x0c);
lcd_data("Need");
lcd_cmd(0xC0);
lcd_data(" Calibration");
delay_ms(100);
}
//
//***********************************************************
// 実 行開始時の初期設定
//
void setup_pic()
{
// init PIC
//
set_tris_a(Amode); // mode set of port
set_tris_b(Bmode); // lower is input
//
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_EXT_H_TO_L|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator(False);
//
}
//
void initLCMeter()
{
setup_pic();
delay_ms(100);
//
mesDoing = false;
CFref = 0.0;
LFref = 0.0;
Coref = 0.0;
Loref = 0.0;
//
// LCD 表示
//
lcd_init(); // initialize LCD
disp_version();
//
}
//
//***********************************************************
// 最 終計測結果の計算
//
void calc_result(float *result)
{
// 周波数計測結果から値を計算
if(mode==0) {
if(Freq>100.0) *result = (LFref*LFref/(Freq*Freq)-1.0)*Loref;
else {
*result = 999.9999;
output_low(LEDout);
delay_ms(100);
}
}
else if(mode==1){
*result = (CFref*CFref/(Freq*Freq)-1.0)*Coref;
if(*result>5.0E-6) output_low(LEDout);
}
else {
*result = Freq;
if(Freq<50.0) output_low(LEDout);
}
}
//
//***********************************************************
// 桁 の処理
//
void calcFormat(char str, float result)
{
float a;
a = fabs(result);
if(a>=
1.0E-1)
sprintf(str,"%8.4f
",result);
else if(a>=1.0E-4) sprintf(str,"%8.4fm",result*1.0E+3);
else if(a>=1.0E-7) sprintf(str,"%8.4f%c",result*1.0E+6,0xE4);
else if(a>=1.0E-8) sprintf(str,"%8.5f%c",result*1.0E+6,0xE4);
else if(a>=1.0E-10) sprintf(str,"%8.4fn",result*1.0E+9);
else
sprintf(str,"%8.4fp",result*1.0E+12);
}
//
//***********************************************************
// 最 終計測結果の表示
//
void disp_result()
{
char str[20];
float result;
// 周 波数計測結果から値を計算
calc_result(&result);
// 結 果表示桁数の処理
calcFormat(str,result);
// 結 果の表示
lcd_clear(); lcd_cmd(0x0c);
if(mode==0) { lcd_data("Lx
= ");
lcd_dispString(str); lcd_data("H"); disp_FreqValue(Freq);}
else if(mode==1){ lcd_data("Cx = "); lcd_dispString(str); lcd_data("F"); disp_FreqValue(Freq);}
else {
disp_ModeType();
disp_FreqValue(Freq);
}
}
//
//***********************************************************
// メ インルーチン
//
void main()
{
//
initLCMeter();
//
while(true){
// 現 在のモードを調べる
if(input(FreqCntYNin)==0) mode = 2;
else if(input(LCcheckIn)==0) mode = 0;
else mode = 1;
// モー ドが変更されたら現在の処理を中止し指定されたモードに変更
if(mode!=beMode) changeMode(mode);
// キャ リブレーションボタンが押されたら各モードに一致したキャリブレーションを実行
if(input(doCalibration)==0){
if(mode==0) {doCalInductance(); calcLoCo();}
else if(mode==1) {doCalCapacitance(); calcLoCo();}
}
//
// 継 続モード
//
// 計 測が終了したら計測結果を表示
if(mesDoing==false){
//
// キャリブレーション済なら各モードに合わせて結果を表示
if(LFref>0.0&&mode==0||CFref>0.0&&mode==1||mode==2) {
disp_result();
output_high(LEDout);
}
else {
need_calibration();
output_low(LEDout);
}
//
startMesure(); // 計 測再開
}
}
}