ECM音センサの作り方

 

こんなこと、やります。

  • エレクレットマイク(ECM)を使って音センサーの制作
  • 交流信号を直流信号へ変換する
  • ADコンバータを使ってラズパイで音を認識させる
  • 音量に合わせてLEDを点灯させる

ラズパイで使えるECM音センサーの作り方
ラズパイで使えるECM音センサーの作り方

ラズパイで音が感知できるように実験してみました。この記事では音センサーの作り方をメインにご紹介します。音センサーは交流回路の勉強にもなって楽しいので、ぜひ挑戦してみてください。

こちらの動画のように、ラズパイと自作のECMマイクを使って、音量に合わせてLEDを点灯させるサウンドレベルインジケーターのようなことやっていきます!

音センサーの概要

音センサーを実現するための概要を説明します。

音センサーの仕組み

今回製作した音センサーの仕組みは次のようになります。

エレクトレットマイクからラズパイまでのフロー図
エレクトレットマイクからラズパイまでのフロー図

  1. マイクロフォン(ECM)で音声を集音
  2. アンプ回路で音声を増幅
  3. 音声の交流信号を直流信号に変換
  4. 直流信号をADコンバータでデジタル変換
  5. SPI通信でデジタル信号をラズパイで読み取る

エレクレットマイク(ECM)

音を感知するためのECMマイクは、以前に自作したものを使用します。作り方はこちらの記事をご参考になさってみてください。

作るのが面倒という方は、ECMとアンプがモジュール化されたものを使うと便利です。

また、ラズパイはお好きなものをお使いください。

マイクアンプの製作

ECMで集音した信号は、電圧が数十mV程度と小さすぎます。よって、そのままでは使えないのでアンプを通して十分大きな信号に変換してあます。

マイクアンプを通して微弱信号を増幅させる
マイクアンプを通して微弱信号を増幅させる

非反転増幅回路

オペアンプを使って、非反転増幅回路でマイク信号を増幅させます。この回路では、1kΩと470kΩの抵抗によって470倍の信号増幅が可能です。

マイクアンプの電子回路図
マイクアンプの電子回路図

非反転増幅回路の詳しくは、こちらの記事をご参考になさってみてください。

今回は音質に拘らないので、NJM4558やTL072などの安価なオペアンプで十分です。

増幅回路の波形を観察

ファンクションジェネレータでサイン波を鳴らし、マイクで集音して増幅回路に通してみました。その時の入力側と出力側の波形のようすです。

マイクアンプの増幅をオシロスコープで観察
マイクアンプの増幅をオシロスコープで観察

写真のように10mVp-p程度だったECM出力の電圧が、アンプを通したことで4Vp-p程度まで増幅されました。ただし、過増幅のために波形は歪んでいます。人間の耳で聞けば割れた音になっていますが、センサーの用途ですのでこれで問題ありません。あくまで音を感知できればいいので、音質は気にしなくて良いです。

発振器のすすめ

ところで、こういった低周波の実験には「発振器」があると便利です。発振器は「ファンクションジェネレータ」や「オシレーター」とも呼ばれます。ご参考になさってみてください。

▼ ファンクションジェネレータは自作することも可能です。

交流信号を直流信号に変換する(AC-DC)

マイクアンプで増幅された信号は、GNDの0Vを中心にプラスマイナスへ振れる交流信号です。よって、このままではADコンバータに入力できません。そこで、交流信号を直流信号に変換するAC-DCコンバータを作っていきます。

作ると言っても、とてもカンタンです。つぎのように半波整流回路を利用します。

AC-DCコンバータの回路

半波整流でAC-DC変換する電子回路図
半波整流でAC-DC変換する電子回路図

このAC-DCコンバータの回路の仕組みはつぎのとおりです。

  1. 0Vを中心に上下する交流信号の「プラス側の信号のみ」をダイオードで取り出す
  2. ダイオードを通過した信号は、1uのコンデンサに蓄電され、そして100kΩの抵抗へ流れていく
  3. 出力が3.3V以上の電圧にならないよう、ツェナーダイオードでリミッターをかける

AC-DC変換後の波形はこんな感じのものになります。

ACからDCへ変換する説明
ACからDCへ変換する説明

▼ ダイオードとツェナーダイオードは、小信号用のものをお使いいただけます。

なお、ダイオードを通過した信号はOUTへも流れますが、OUT先の入力抵抗(入力インピーダンス)は非常に高いと想定しているため、1uに蓄えられた電荷のほとんどが100kΩの抵抗へ流れることになります。このことは、インピーダンスについて学ぶと理解できますので、詳しく学びたい方はこちらの書籍をオススメしておきます。(私のバイブルです)

AC-DCコンバータの実際

こちらの写真はマイクアンプから出力された信号と、「ダイオードのみ」を通した時の信号をオシロスコープで観察したものです。

ダイオードのみを通した時の信号をオシロスコープで観察
ダイオードのみを通した時の信号をオシロスコープで観察

ダイオードを通すと、プラス側の信号のみを取り出すことができます。またダイオードの向きを反対にすれば、マイナス側の信号のみを取り出せます。

ダイオードでは順方向電圧があり、ダイオードを通った信号は0.6Vほど電圧が低くなります。上の写真からもそのようすが観察できます。

つまり、0.6V以上の入力信号でないとこの回路は動作しません。ですから、アンプ回路でECMの微弱信号を大きな電圧に増幅する必要があったのですね。

もしも0Vから動作させたい場合は、理想ダイオード回路を使って実現できます。詳しくはこちらをご覧ください。

理想ダイオード回路は、本格的なVUメーターやdB測定器などで精密な測定器に使われたりします。今回の用途では精度は求めませんので、簡易的な方法でAC-DCコンバータを実現させました。

この簡易的なAC-DCコンバータ回路は、他にも土壌センサーやコンプレッサーなどのエンベロープ発生に使われています。

コンデンサ(1u)後の抵抗値(100k)を変えることで、信号による追従速度を変化させられます。たとえば抵抗値を大きくすると、コンデンサに貯まった電荷が逃げにくくなるため、音声信号の追従が遅くなります。ここら辺は実際に回路を組んで調整します。

ADコンバータ

さて、AC-DCコンバータで直流になったアナログ電圧をラズパイで読み取るためには、ADコンバータが必要です。ADコンバータはアナログ信号をデジタル信号に変換するものです。

ADコンバータは、SPIで通信する2チャネル・8ビットのMAX1118を使いました。MAX1118の使い方はこちらの記事をご覧ください。

他にもADコンバータはいろいろあります。

お好きなADコンバータをお使いいただけますが、ラズパイで使う場合はI2CまたはSPI接続のADコンバータがカンタンです。

音量に合わせてLEDを点灯させるPythonプログラム

ここまで準備ができたところで、さいごにラズパイを使って音センサを使ってみます。音量に合わせてLEDを点灯させるPythonプログラムを書いてみました。ラズパイのGPIOに、1kΩの抵抗を介してLEDを5個配線しています。

# -*- coding: utf-8 -*-
import spidev
import time
import RPi.GPIO as GPIO

LED0 = 4 # GPIO番号
LED1 = 14
LED2 = 15
LED3 = 17
LED4 = 18

Vref = 3.336  # ラズパイの3.3V電源をテスターで実測

GPIO.setmode(GPIO.BCM)
GPIO.setup(8, GPIO.OUT)  # CNVST

GPIO.setup(LED0, GPIO.OUT)
GPIO.setup(LED1, GPIO.OUT)
GPIO.setup(LED2, GPIO.OUT)
GPIO.setup(LED3, GPIO.OUT)
GPIO.setup(LED4, GPIO.OUT)


spi = spidev.SpiDev()
spi.open(0, 0)  # bus0,cs0
spi.no_cs = True  # CSを使わない
spi.max_speed_hz = 1000000  # 1MHz
spi.bits_per_word = 8


def sendCNVST(CH):
    if CH == 0:
        GPIO.output(8, GPIO.LOW)
        GPIO.output(8, GPIO.HIGH)
        GPIO.output(8, GPIO.LOW)
    elif CH == 1:
        GPIO.output(8, GPIO.LOW)
        GPIO.output(8, GPIO.HIGH)
        GPIO.output(8, GPIO.LOW)
        GPIO.output(8, GPIO.HIGH)
        GPIO.output(8, GPIO.LOW)


def getVolts():
    adc = spi.xfer2([0x00])
    return adc[0] / 255.0 * Vref


try:
    while True:
        sendCNVST(0)
        v0 = getVolts()
        # print(v0)
        
        if v0 > 0.75:
            GPIO.output(LED0, GPIO.HIGH)
            GPIO.output(LED1, GPIO.HIGH)
            GPIO.output(LED2, GPIO.HIGH)
            GPIO.output(LED3, GPIO.HIGH)
            GPIO.output(LED4, GPIO.HIGH)

        elif v0 > 0.6:
            GPIO.output(LED0, GPIO.HIGH)
            GPIO.output(LED1, GPIO.HIGH)
            GPIO.output(LED2, GPIO.HIGH)
            GPIO.output(LED3, GPIO.HIGH)
            GPIO.output(LED4, GPIO.LOW)
        elif v0 > 0.45:
            GPIO.output(LED0, GPIO.HIGH)
            GPIO.output(LED1, GPIO.HIGH)
            GPIO.output(LED2, GPIO.HIGH)
            GPIO.output(LED3, GPIO.LOW)
            GPIO.output(LED4, GPIO.LOW)
        elif v0 > 0.3:
            GPIO.output(LED0, GPIO.HIGH)
            GPIO.output(LED1, GPIO.HIGH)
            GPIO.output(LED2, GPIO.LOW)
            GPIO.output(LED3, GPIO.LOW)
            GPIO.output(LED4, GPIO.LOW)

        elif v0 > 0.15:
            GPIO.output(LED0, GPIO.HIGH)
            GPIO.output(LED1, GPIO.LOW)
            GPIO.output(LED2, GPIO.LOW)
            GPIO.output(LED3, GPIO.LOW)
            GPIO.output(LED4, GPIO.LOW)
        else:
            GPIO.output(LED0, GPIO.LOW)
            GPIO.output(LED1, GPIO.LOW)
            GPIO.output(LED2, GPIO.LOW)
            GPIO.output(LED3, GPIO.LOW)
            GPIO.output(LED4, GPIO.LOW)

        time.sleep(0.01)


except KeyboardInterrupt:
    spi.close()
    GPIO.output(LED0, GPIO.LOW)
    GPIO.output(LED1, GPIO.LOW)
    GPIO.output(LED2, GPIO.LOW)
    GPIO.cleanup()

▼ SPI通信でデータを読み取る関数spi.xfer2は、こちらの記事で詳しく解説しています。

▼ 作った音センサのようすは、こちらの動画をご覧ください。

記事に関するご質問などがあれば、
@tosisico または お問い合わせ までご連絡ください。
この記事で紹介した商品
関連記事