donoのアイコン画像
dono 2021年02月26日作成 (2021年02月26日更新)
製作品 製作品 閲覧数 3281
dono 2021年02月26日作成 (2021年02月26日更新) 製作品 製作品 閲覧数 3281

まっすぐ音が届く指向性スピーカー

まっすぐ音が届く指向性スピーカー

超音波を利用して、正面のみ音が聞こえるスピーカーを作りました。実際は音が反射するため壁にスピーカーを向けると壁から音が出ているように聞こえたりします。

  1. 原理
    音は空気の振動です。振動には1.周波数(音の高さ)、2.振幅(音の大きさ)、3.位相(波の山の位置)の3つの要素があります。
  • 正面のみ聞こえる理由
    音波の位相が揃っている(青線)とき、互いに強め合い振幅が大きくなります。
    音波の位相が180度ずれている(緑線)とき、互いに弱めあい振幅が小さくなります。
    キャプションを入力できます
    二つのスピーカーから音を出したとき、正面に向かって飛ぶ音は強め合い、横に飛ぶ音は弱めあいます。
    実際はスピーカーが大量に並んでいるため正面以外は打ち消されて聞こえなくなります。また、この現象は周波数が高い程表れやすいので今回は40kHzの超音波を使っています。
    キャプションを入力できます

  • 超音波で可聴音を運ぶことが出来る理由
    音は空気の密度が高い部分と低い部分が波となって移動することで伝わります。しかし、空気は圧縮される(密度が高まる)時よりも圧縮から戻る(密度が下がる)時の方が少し時間がかかります。
    超音波のように周波数が高い場合、次の波が来るまでの間に密度が戻らないため、超音波の振幅を変化させると赤線のように低い周波数の波を発生させることができます。
    キャプションを入力できます
    これによって超音波で可聴音を運ぶことが可能になります。

  1. 主な材料
  • 超音波スピーカー:UT1007-Z325R × 37個
    スピーカーの面積(個数)が大きいほど指向性が強まります。

  • マイコン:PIC16F1827 × 1個
    マイクやオーディオ入力からの信号を超音波周波数のPWMに変換するために使います。
    実際はアナログ回路で組むほうが分解能などの点で良いのですが、手軽なのでマイコンを使用しました。

  • ゲートドライバ:IR2104STRPBF × 2個
    超音波スピーカーを駆動するためのHブリッジ回路を構成するために使用します。
    スピーカーに加える電圧が大きいほど音が大きく遠くまで届くので、Hブリッジで電源電圧の2倍の振幅を作ります。

  1. ハードウェア
  • 回路構成
    キャプションを入力できます
    マイクやライン入力の信号をOPアンプで増幅し、マイコンのAD変換器に入れます。変換結果を元にPWMのデューティー比を変化させ超音波を出力します。

  • スピーカーの配置
    キャプションを入力できます
    人が移動するときは基本的に横方向に動くため、スピーカーを正円ではなく楕円状に配置し、横方向の指向性を強化しました。

  1. 完成品外観
    回路はkicadで設計したものをCNCで加工しました。外装はアクリルや100均の下敷きを使って製作しています。
    キャプションを入力できます
    キャプションを入力できます
    キャプションを入力できます
    キャプションを入力できます

  2. 結果
    動作の様子を動画で示します。

    ここに動画が表示されます

    正面に来た時に音が大きくなっていることがわかると思います。部屋が狭いため音が反射し正面以外でも聞こえていますが、開けた場所では聞こえなくなります。
    マイコンの性能の関係で入力信号の分解能が400段階しかない上に、超音波に可聴音を乗せるという無理をしているため音質は残念なことになってしまいました...。

  3. 付録
    作品の回路図です。接続は正しいですが、部品の定数は組み立て時に手元にある数値に変更したので正確ではないです。
    キャプションを入力できます

使ったプログラムです。

// PIC16F1827 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1
#pragma config FOSC = HS        // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = HI        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), high trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#include <xc.h>
#define _XTAL_FREQ	32000000
#define BATT_LOW	100	//140:15V, 102:11V
#define soundTH	15
#define MIC_IN		LATAbits.LATA3
#define LED_R		LATBbits.LATB2
#define LED_G		LATBbits.LATB1
#define PUSH_SW	PORTBbits.RB0
#define BATT_PIN	8
#define SOUND_PIN	4
#define ADRES9		((ADRESH<<7)|(ADRESL>>1))
#define ADSTART(ch)	ADCON0bits.CHS=(ch);\
					__delay_us(10);\
					ADCON0bits.GO_nDONE=1;\
					while( ADCON0bits.GO_nDONE )
#define	PWM(pwm)	CCPR1L			=pwm>>2;\
					CCP1CONbits.DC1B=pwm

volatile unsigned short	sound=0;
volatile unsigned short	countStop=0,countOver=0,soundUnder=0,dcountOver;
volatile unsigned char		battflg=0;

void PICinit(void){
	OSCCON	=0b10000000;
	while(!OSCSTATbits.PLLR);
	while(!OSCSTATbits.OSTS);
	INTCON	=0b01010000;
	PIE1bits.TMR2IE  =1;
	//IO
	OPTION_REG=0b00010010;
	LATA	=0b00000000;
	TRISA	=0b00110000;
	ANSELA	=0b00010000;
	LATB	=0b00000000;
	TRISB	=0b00010001;
	ANSELB	=0b00010000;
	WPUB	=0b00000001;
	//PWM
	T2CON	=0b00000000;
	CCPTMRS	=0b00000000;
	CCP1CON	=0b10000000;
	PWM1CON	=0b10000000;
	PR2		=200-1;
	TMR2	=0b00000000;
	CCPR1L	=0b00000000;
	//ADC 
	ADCON0	=0b00110000;
	ADCON1	=0b10100000;
	return;
}

void interrupt isr(void){
	if( INTCONbits.INTF ){
		PWM(0);
		LED_R=0;
		LED_G=0;
		__delay_ms(10);
		if( !PUSH_SW ){
			CCP1CONbits.CCP1M=0;
			MIC_IN=!MIC_IN;
			while( !PUSH_SW );
			__delay_ms(10);
			CCP1CONbits.CCP1M=0xF;
		}
		INTCONbits.INTF=0;
	}
	if( PIR1bits.TMR2IF ){
		ADSTART(SOUND_PIN);
		sound = ADRES9-soundUnder;
		if( sound >= 400 ){
			countOver++;
			dcountOver=0x2000;
			CCP1CONbits.CCP1M=0xF;
			LED_R=1;
			LED_G=0;
			if( sound >= 512 ){
				PWM(0);
			}else{
				PWM(400);
			}
			ADSTART(BATT_PIN);
			if( BATT_LOW >= ADRES9 ) battflg=1;
		}else{
			countOver = 0;
			if(dcountOver)	dcountOver--;
			if(sound<(200-soundTH)||sound>(200+soundTH))	countStop=0;
			else											countStop++;
			if( countStop >= 0x2000 ){
				countStop=0x2000;
				CCP1CONbits.CCP1M=0;
				LED_R=1;
				LED_G=1;
				PWM(0);
				ADSTART(BATT_PIN);
				if( BATT_LOW >= ADRES9 ) battflg=1;
			}else{
				CCP1CONbits.CCP1M=0xF;
				if(dcountOver){
					LED_R=1;
					LED_G=0;
				}else{
					LED_R=0;
					LED_G=1;
				}
				PWM(sound);
			}
		}
		PIR1bits.TMR2IF=0;
	}
}

void main(void){
	PICinit();
	LED_R	=1;
	LED_G	=1;
	__delay_ms(10);
	LED_R	=0;
	LED_G	=0;
	__delay_ms(700);
	ADCON0bits.ADON	=1;
	ADSTART(BATT_PIN);
	if( BATT_LOW >= ADRES9 )	goto ERR;
	sound		=256;
	soundUnder	=sound-200;
	CCP1CONbits.CCP1M=0xF;
	countStop		=0;
	countOver		=0;
	PIR1bits.TMR2IF	=0;
	INTCONbits.INTF	=0;
	CCP1CONbits.CCP1M=0xF;
	LED_R	=0;
	LED_G	=0;
	MIC_IN	=0;
	INTCONbits.GIE	=1;
	T2CONbits.TMR2ON=1;
	while( 1 ){
		if( countOver > 0x1000 )	goto ERR;
		if( battflg )				goto ERR;
	}
	
	ERR:
	INTCONbits.GIE	=0;
	T2CONbits.TMR2ON=0;
	CCP1ASbits.CCP1ASE=1;
	ADCON0bits.ADON	=0;
	CCP1CONbits.CCP1M=0;
	OPTION_REG=0b00010010;
	LATA	=0b00000000;
	TRISA	=0b00110000;
	ANSELA	=0b00010000;
	LATB	=0b00000000;
	TRISB	=0b00010001;
	ANSELB	=0b00010000;
	WPUB	=0b00000001;
	OSCCONbits.SCS1	=1;
	LED_R=1;
	LED_G=0;
	INTCONbits.TMR0IF=1;
	while(1){
		if( INTCONbits.TMR0IF ){
			LED_R=!LED_R;
			INTCONbits.TMR0IF=0;
		}
	}
	return;
}
3
  • dono さんが 2021/02/26 に 編集 をしました。 (メッセージ: 初版)
  • dono さんが 2021/02/26 に 編集 をしました。
  • dono さんが 2021/02/26 に 編集 をしました。
  • dono さんが 2021/02/26 に 編集 をしました。 (メッセージ: 図のサイズを変更しました)
  • dono さんが 2021/02/26 に 編集 をしました。 (メッセージ: プログラムを追加しました)
ログインしてコメントを投稿する

投稿者の人気記事