Raspberry Pi 作品集
サウンドセンサー LM386搭載 9534
騒音計の作成
サウンドセンサー LM386搭載 9534
騒音計の作成
音量測定の目的:長年使用している Raspberry pi 4 を冷却しているファンの音が大きくなったので、交換を機に新品ファンとの音量差を測定してみることにした。
音量測定の結果:使い物にならず、失敗。
音量測定の結果:使い物にならず、失敗。
以下、サウンドセンサー「9534」を使った「騒音計」を作成した記録。
スポンサー リンク
目 次
1. 使用中の冷却ファン
2. 音量測定に使用した部品
3. 配線
4. 事前準備
5. Python プログラムと実行結果
6. 音量レベルの変化が小さすぎる
7. キャリブレーションによる音量測定
2. 音量測定に使用した部品
3. 配線
4. 事前準備
5. Python プログラムと実行結果
6. 音量レベルの変化が小さすぎる
7. キャリブレーションによる音量測定
1. 使用中の冷却ファン
交換する前に、現在稼働中のファンに「KURE5-56」を注入してみると【音が消えた】ので、交換せずに継続して使用中。
2. 音量測定に使用した部品
■主な仕様
・メーカー / 販売元 Waveshare
・製品型番 9534
・動作電圧 3.3V〜5.3V
・インターフェース VCC↔3.3V〜5.3V
・GND↔電源グランド
・AOUT↔MCU.IO(アナログ出力)
・DOUT↔MCU.IO(デジタル出力)
・マイク感度 52dB
・周波数範囲 50Hz~20KHz
・寸法 34.42mm×18.67mm
・取付穴サイズ 2.0mm
・メーカー / 販売元 Waveshare
・製品型番 9534
・動作電圧 3.3V〜5.3V
・インターフェース VCC↔3.3V〜5.3V
・GND↔電源グランド
・AOUT↔MCU.IO(アナログ出力)
・DOUT↔MCU.IO(デジタル出力)
・マイク感度 52dB
・周波数範囲 50Hz~20KHz
・寸法 34.42mm×18.67mm
・取付穴サイズ 2.0mm
■主な仕様
・電源電圧min.:2.7V
・電源電圧max.:5.5V
・入力数:8
・分解能:10bit
・サンプリングレート:200ksps
・入力タイプ:シングルエンド・疑似差動
・インターフェイス:SPI
・変換方式:逐次比較型(SAR)
・微分非直線性誤差DNL:±1LSB
・積分非直線性誤差INL:±1LSB
・動作温度min.:-40℃
・動作温度max.:85℃
・実装タイプ:スルーホール
・パッケージ:DIP16
・パッケージタイプ:DIP16
・電源電圧min.:2.7V
・電源電圧max.:5.5V
・入力数:8
・分解能:10bit
・サンプリングレート:200ksps
・入力タイプ:シングルエンド・疑似差動
・インターフェイス:SPI
・変換方式:逐次比較型(SAR)
・微分非直線性誤差DNL:±1LSB
・積分非直線性誤差INL:±1LSB
・動作温度min.:-40℃
・動作温度max.:85℃
・実装タイプ:スルーホール
・パッケージ:DIP16
・パッケージタイプ:DIP16
Digital data output(デジタル出力)があるが、しきい値を超える音量の検知用なので、音量の測定にはアナログ出力を使用する。
3. 配線
①.サウンドセンサーの接続:
●VCC -> 3.3V
●GND -> GND
●AOUT -> MCP3008 の CH0 (アナログ入力ピン)
●VCC -> 3.3V
●GND -> GND
●AOUT -> MCP3008 の CH0 (アナログ入力ピン)
②.MCP3008 と Raspberry Pi の接続:
●VDD -> 3.3V
●VREF -> 3.3V
●AGND -> GND
●DGND -> GND
●CLK -> GPIO 11
●DOUT -> GPIO 9
●DIN -> GPIO 10
●CS -> GPIO 8
●VDD -> 3.3V
●VREF -> 3.3V
●AGND -> GND
●DGND -> GND
●CLK -> GPIO 11
●DOUT -> GPIO 9
●DIN -> GPIO 10
●CS -> GPIO 8
■GPIO ピンと SPI バスの対応:
Raspberry Pi で SPI 通信を使用する際は、以下の GPIO ピンが使用される。
プログラム内では spi.open(0, 0) によって、SPI バス 0 の デバイス 0 を指定する。

Raspberry Pi で SPI 通信を使用する際は、以下の GPIO ピンが使用される。
プログラム内では spi.open(0, 0) によって、SPI バス 0 の デバイス 0 を指定する。

Raspberry Pi のGPIOピン配置確認コマンド。
pinout
4. 事前準備
spidev ライブラリのインストール。
sudo apt update
sudo apt install python3-pip
pip3 install spidev
sudo apt install python3-pip
pip3 install spidev
SPI の有効化。
sudo raspi-config
SPI が有効になっているか確認。
ls /dev/spidev*
/dev/spidev0.0
/dev/spidev0.1
/dev/spidev0.1
5. Python プログラムと実行結果
Python プログラム。
import spidev
import time
# SPI インターフェイスの設定
spi = spidev.SpiDev()
spi.open(0, 0) # SPIバスとデバイスを指定
spi.max_speed_hz = 1350000
# MCP3008 からデータを取得
def read_adc(channel):
if channel < 0 or channel > 7:
raise ValueError("チャンネルは 0~7 の間で指定してください")
adc = spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
# 音量測定ループ
try:
print("音量測定を開始します。Ctrl+C で終了してください。")
while True:
# サウンドセンサーのデータを取得
sound_level = read_adc(0)
# 音量を出力 (0~1023 の範囲)
print(f"音量レベル: {sound_level}")
# 短い間隔を置く
time.sleep(0.1)
except KeyboardInterrupt:
print("終了します。")
finally:
spi.close()
■説明
1. spidev ライブラリ:
・Raspberry Pi の SPI インターフェイスを操作します。
・MCP3008 ADC からデータを取得します。
2. 音量の測定:
・サウンドセンサーのアナログ出力を 0~1023 の範囲で取得します。
・大きい値ほど音量が大きいことを示します。
3. リアルタイム更新:
・データを約0.1秒間隔で取得・表示します。
1. spidev ライブラリ:
・Raspberry Pi の SPI インターフェイスを操作します。
・MCP3008 ADC からデータを取得します。
2. 音量の測定:
・サウンドセンサーのアナログ出力を 0~1023 の範囲で取得します。
・大きい値ほど音量が大きいことを示します。
3. リアルタイム更新:
・データを約0.1秒間隔で取得・表示します。
静かな環境でプログラムを実行してみる・・・
表示される測定値が変動し安定しない。 → 次の対策を講じる。
表示される測定値が変動し安定しない。 → 次の対策を講じる。
■改善策①:グランド接続を最適化:
サウンドセンサーと Raspberry Pi のグランドを共有させる。
■改善策②:コンデンサの追加:
サウンドセンサーの電源ピン(VCC と GND)に 0.1 µF と 10 µF のコンデンサを並列に接続し、ノイズを低減する。
■改善策③:シールドケーブル:
センサーから Raspberry Pi までの配線に、シールドケーブルの代替としてアルミホイルを巻き付ける。
6. 音量レベルの変化が小さすぎる
静かな環境での音量レベルが【530】前後の値になり、
騒音を加えても音量レベルの変化が小さすぎて使い物にならない。
騒音を加えても音量レベルの変化が小さすぎて使い物にならない。
以下、この原因と対策に関する各種実験を行ってみる。
①.音量をパーセントに変換してみる
import spidev
import time
import RPi.GPIO as GPIO
# SPIの設定
spi = spidev.SpiDev()
spi.open(0, 0) # SPIバス0、デバイス0
spi.max_speed_hz = 1350000
# MCP3008からアナログ値を読み取る関数
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
# サウンドセンサーのピンの設定
SENSOR_CHANNEL = 0 # MCP3008のCH0に接続
# メイン処理
try:
while True:
# アナログ値の読み取り(0-1023の範囲)
sound_level = read_adc(SENSOR_CHANNEL)
# 音量をパーセントに変換(簡易的なスケーリング)
sound_percentage = (sound_level / 1023.0) * 100
print(f"Sound Level: {sound_level} (Approx. {sound_percentage:.2f}%)")
time.sleep(0.5) # 0.5秒ごとに測定
except KeyboardInterrupt:
print("\nMeasurement stopped by user")
finally:
spi.close() # SPI接続を閉じる
GPIO.cleanup() # GPIO設定をクリーンアップ
静かな環境で測定を開始し、その後(ピンク色の枠以降)ラジオの音をサウンドセンサー近づけて測定した。
・ 静かな環境での音量レベルと音量のパーセントが、アナログ値のほぼ中間値を示し、
・ ラジオの音での音量レベルと音量のパーセントが、静かな環境での値より小さくなったりする。
・ 静かな環境での音量レベルと音量のパーセントが、アナログ値のほぼ中間値を示し、
・ ラジオの音での音量レベルと音量のパーセントが、静かな環境での値より小さくなったりする。
②.データをスケーリングして変化を強調してみる
# データのスケーリング
def scale_data(raw_value, min_value=0, max_value=1023, new_min=0, new_max=100):
"""データを指定された範囲にスケーリング"""
return (raw_value - min_value) * (new_max - new_min) / (max_value - min_value) + new_min
# 測定ループ内
raw_sound_level = read_adc(0)
scaled_sound_level = scale_data(raw_sound_level, 0, 1023, 0, 100) # 0~100 の範囲にスケーリング
print(f"スケーリング後の音量レベル: {scaled_sound_level:.2f}")
③.音声信号のピークを検出して、最大値と最小値を抽出してみる
# ピーク検出
def detect_peak(values):
"""値のリストから最大値と最小値を検出"""
return max(values), min(values)
②にスケーリングと ③のピーク検出を同時に実装した Python プログラム。
import spidev
import time
# SPI インターフェイスの設定
spi = spidev.SpiDev()
spi.open(0, 0) # SPIバスとデバイスを指定
spi.max_speed_hz = 1350000
# MCP3008 からデータを取得
def read_adc(channel):
if channel < 0 or channel > 7:
raise ValueError("チャンネルは 0~7 の間で指定してください")
adc = spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
# データのスケーリング
def scale_data(raw_value, min_value=0, max_value=1023, new_min=0, new_max=100):
"""データを指定された範囲にスケーリング"""
return (raw_value - min_value) * (new_max - new_min) / (max_value - min_value) + new_min
# ピーク検出
def detect_peak(values):
"""値のリストから最大値と最小値を検出"""
return max(values), min(values)
# 音量測定ループ
try:
print("音量測定を開始します。Ctrl+C で終了してください。")
# サンプルバッファを作成
sample_buffer = []
buffer_size = 10 # サンプル数
while True:
# サウンドセンサーのデータを取得
raw_sound_level = read_adc(0)
# スケーリング
scaled_sound_level = scale_data(raw_sound_level, 0, 1023, 0, 100)
# バッファに追加
sample_buffer.append(scaled_sound_level)
if len(sample_buffer) >= buffer_size:
# ピーク検出
max_level, min_level = detect_peak(sample_buffer)
print(f"【ピーク検出】 最大: {max_level:.2f}, 最小: {min_level:.2f}")
# バッファをリセットして再収集を開始
sample_buffer = []
else:
# バッファ収集中の音量を表示
print(f"音量レベル: {scaled_sound_level:.2f} (バッファ収集中)")
# 短い間隔を置く
time.sleep(0.1)
except KeyboardInterrupt:
print("終了します。")
finally:
spi.close()
音声信号の最大値と最小値がスケーリングされて表示されるようになったが、【騒音】が大きいか/小さいかを簡単に判定できるような値にはならない。
④.静かな環境でキャリブレーションを行い「基準値を設定」し、
その後「基準値との差」を測定して音量レベルを表示する。
その後「基準値との差」を測定して音量レベルを表示する。
import spidev
import time
# SPI インターフェイスの設定
spi = spidev.SpiDev()
spi.open(0, 0) # SPIバスとデバイスを指定
spi.max_speed_hz = 1350000
# MCP3008 からデータを取得
def read_adc(channel):
if channel < 0 or channel > 7:
raise ValueError("チャンネルは 0~7 の間で指定してください")
adc = spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
# データのスケーリング
def scale_data(raw_value, min_value=0, max_value=1023, new_min=0, new_max=100):
"""データを指定された範囲にスケーリング"""
return (raw_value - min_value) * (new_max - new_min) / (max_value - min_value) + new_min
# キャリブレーション
def calibrate(channel, duration=5):
"""静かな環境で基準値を計測"""
print(f"キャリブレーションを開始します。{duration}秒間、静かな環境を保ってください...")
start_time = time.time()
samples = []
while time.time() - start_time < duration:
raw_value = read_adc(channel)
samples.append(raw_value)
time.sleep(0.1) # サンプリング間隔
baseline = sum(samples) / len(samples)
print(f"キャリブレーション完了: 基準値 = {baseline:.2f}")
return baseline
# 音量測定ループ
try:
print("音量測定を開始する前に、キャリブレーションを行います。")
input("キャリブレーションを開始するには Enter を押してください...")
# キャリブレーション
channel = 0 # サウンドセンサーが接続されているチャンネル
baseline_value = calibrate(channel)
print("キャリブレーション完了。音量測定を開始します。Ctrl+C で終了してください。")
while True:
# サウンドセンサーのデータを取得
raw_sound_level = read_adc(channel)
# スケーリング
scaled_sound_level = scale_data(raw_sound_level, 0, 1023, 0, 100)
# 基準値との差を計算
relative_sound_level = scaled_sound_level - scale_data(baseline_value, 0, 1023, 0, 100)
# 結果を表示
print(f"基準値との差: {relative_sound_level:.2f}, 音量レベル (スケール): {scaled_sound_level:.2f}")
time.sleep(0.1)
except KeyboardInterrupt:
print("終了します。")
finally:
spi.close()
ラジオの音をサウンドセンサーに近づけて測定してみるも、「基準値との差」がマイナスになったり、【騒音】が大きいと判定できるような値は表示されない。
⑤.差分値を拡大するスケーリング(ゲイン)を適用
gain = 5 # 差分を拡大する倍率
# 差分を拡大
amplified_relative_level = relative_sound_level * gain
# 結果を表示
print(f"基準値との差 (拡大): {amplified_relative_level:.2f}, 音量レベル (スケール): {scaled_sound_level:.2f}")
「基準値との差」がマイナスになるケースがほとんどで、【騒音】が大きいと判定できるような値は一瞬しか表示されない。
7. キャリブレーションによる音量測定
最後に、たどり着いた Python プログラム。
基準値だけでなく、音量測定もキャリブレーション方式にする。
import spidev
import time
# SPI インターフェイスの設定
spi = spidev.SpiDev()
spi.open(0, 0) # SPIバスとデバイスを指定
spi.max_speed_hz = 1350000
# MCP3008 からデータを取得
def read_adc(channel):
if channel < 0 or channel > 7:
raise ValueError("チャンネルは 0~7 の間で指定してください")
adc = spi.xfer2([1, (8 + channel) << 4, 0])
data = ((adc[1] & 3) << 8) + adc[2]
return data
# データのスケーリング
def scale_data(raw_value, min_value=0, max_value=1023, new_min=0, new_max=100):
"""データを指定された範囲にスケーリング"""
return (raw_value - min_value) * (new_max - new_min) / (max_value - min_value) + new_min
# キャリブレーション
def calibrate(channel, duration=5):
print(f"{duration}秒間キャリブレーションを行います。")
start_time = time.time()
samples = []
while time.time() - start_time < duration:
raw_value = read_adc(channel)
samples.append(raw_value)
time.sleep(0.1) # サンプリング間隔
baseline = sum(samples) / len(samples)
print(f"キャリブレーション完了: 測定値 = {baseline:.2f}")
return baseline
# 音量測定ループ
try:
print("音量測定を開始する前に、基準値測定を行います。静かな環境を保ってください...")
input("開始するには Enter を押してください...\n")
# キャリブレーション
channel = 0 # サウンドセンサーが接続されているチャンネル
baseline_value = calibrate(channel)
print("基準値測定の完了。\n")
while True:
print("音量測定を行います。Ctrl+C で終了します。")
input("開始するには Enter を押してください...\n")
# サウンドセンサーのデータを取得
channel = 0 # サウンドセンサーが接続されているチャンネル
raw_sound_level = calibrate(channel)
# スケーリング
scaled_sound_level = scale_data(raw_sound_level, 0, 1023, 0, 100)
# 基準値との差を計算
relative_sound_level = scaled_sound_level - scale_data(baseline_value, 0, 1023, 0, 100)
# 結果を表示
print(f"基準値との差: {relative_sound_level:.2f}, 音量レベル (スケール): {scaled_sound_level:.2f}\n")
except KeyboardInterrupt:
print("終了します。")
finally:
spi.close()
音量測定もキャリブレーション方式にすることで、「測定」という行為が明確になるが、測定値は実用に耐えない。
以上、サウンドセンサー「9534」を使った「騒音計」の作成に挑戦した記録。
以上。
(2025.05.01)
(2025.05.01)
スポンサー リンク