前回、DACを使ってスピーカを500Hzの矩形波で鳴らそうとしました。しかし、計測してスペクトル表示をしてみても、ピークは別の周波数でした。その原因を探ります。
調査
まず、アールティ山口工作室で開発しているので、周囲のエアコン、工作設備(3DプリンタやNC)の音にかき消されているのではないかと予想して、比較してみます。
マイクは、常時パソコンに付けているバッファロー製WebカメラBSW500MBK、解析ソフトはオープンソースのAudacityを使います。
鳴らしていないときの工作室音の解析グラフです。そもそも500Hz付近と9000Hz付近のdBが大きいようです。
ということで、inukaiさんの提案により静かな環境で計測するために、nomuraさんのアイディアで社内倉庫にあったマイクロニクス製電波暗箱MY1510に放り込んで計測しました。
静かで落ち着いています。これなら綺麗に計測できそうです。
そして、もう一度500Hzの矩形波を流してみた結果がこちらです。ギザギザした面白い感じのグラフになりました。1250Hz、1750Hz、2250Hz、2750Hz、3250Hzという感じに500Hzずつ増えた波が計測されています。肝心の500Hzは音が小さすぎるのか埋もれていますし、そもそも出ているかどうかも怪しいです。
ということで、矩形波だと??な感じがするので、もうちょっと綺麗な音を出すために、DAC&DMAの機能を使った正弦波を出して再計測してみようと思います。
STM32CubeMX
前回と同じようにDACはOUT1を有効化し、TriggerにTimer 7 Trigger Out eventを指定。
DMA SettingsでDAC1のDMAを追加し、Circularモードに設定。
TIM7はTrigger Event SelectionをUpdate Eventに設定。
クロックはいつものように最大になるように設定して、APB1 Timer Clocksが90MHzであることを確認します。
三角関数演算
STM32で正弦波を生成する方法として色々あります。
- math.hを使ったsinf関数のソフトウェア演算
- 前回も紹介した加藤さん作コンパクト三角関数
- DSP&FPUを使ったarm_sin_f32関数
STM32F446にはDSP機能を持ったFPUが搭載されています。せっかくなのでArm社が定義して利用できるCMSIS-DSP LibraryでFPUを使ってみます。
DSP(Digital Signal Processing)とは、マイコンの中にCPUとは別にデジタル信号を処理するために積和演算に特化したプロセッサで、それを実現するためのパプライン処理とハーバードアーキテクチャと呼ばれるデータと命令の両方への同時アクセスが可能な機能も持っています。DSPは固定小数点演算に特化していますが、さらにFPU(Floating Point Unit)は浮動小数点数を高速に処理してくれる浮動小数点演算器が搭載されています。CMSIS(Cortex Microcontroller Software Interface Standard)準拠のDSPライブラリを使ってそれらをプログラムで利用することができます。
ファイルコピー
CMSIS-DSP Library等をプロジェクトファイルにコピーしてきます。私のWinパソコンだと以下にある2つのファイルを、作成したプロジェクトSTEP4-2フォルダの直下にコピーします
C:\Users\nnaka\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.1\Drivers\CMSIS\Lib\ARM\arm_cortexM4lf_math.lib
C:\Users\nnaka\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.1\Drivers\CMSIS\Lib\GCC\libarm_cortexM4lf_math.a
他、必要な関連ヘッダーファイルもコピーして、プロジェクトフォルダ内のIncフォルダにペーストします。
C:\Users\nnaka\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.1\Drivers\CMSIS\DSP\Include\arm_common_tables.h
C:\Users\nnaka\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.1\Drivers\CMSIS\DSP\Include\arm_const_structs.h
C:\Users\nnaka\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.1\Drivers\CMSIS\DSP\Include\arm_math.h
プロパティ設定
次、ライブラリをプロジェクトで使えるようプロパティで設定していきます。
まずはプロパティを開きます。
ライブラリを追加します。
プロジェクトで使えるようパスを通します。
それぞれ、以下の画像のように追加できていたら、適応ボタンを押します。
プログラム
ARM_MATH_CM4の定義はarm_math.hをインクルードする前に記述が必要となります。順番を入れ替えてエラーになってしまいました。
malloc関数を使うので、stdlib.hを追加。プログラム自体は参考にさせてもらったサイトからそのままコピーしてFPUが使えるよう改変しています。
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #define ARM_MATH_CM4 #include "arm_math.h" #include <stdlib.h> /* USER CODE END Includes */
timer_clockで90MHzを指定、sin_frequency_Hzに出したい正弦波を記入します。低周波の場合はメモリを消費するので、timer_PSC=10-1にすると良いみたいです。
/* USER CODE BEGIN 2 */ const double timer_clock = 90e6; const uint16_t timer_PSC = 0; const uint16_t timer_ARR = 90 - 1; const double sin_frequency_Hz = 500; const double sin_offset = 2048; const double sin_volume = 2048; htim7.Instance->PSC = timer_PSC; htim7.Instance->ARR = timer_ARR; HAL_TIM_GenerateEvent(&htim7, TIM_EVENTSOURCE_UPDATE); double sampling_rate = timer_clock / (htim7.Instance->ARR + 1) / (htim7.Instance->PSC + 1); int32_t length = (int32_t)round(sampling_rate / sin_frequency_Hz); int16_t *DAC_buff = malloc(sizeof(int16_t) * length); for (int16_t i = 0; i < length; i++) { double a = arm_sin_f32(i / (double)length * PI * 2) * sin_volume + sin_offset; if (a < 0) { a = 0; } if (a > 4095) { a = 4095; } DAC_buff[i] = (int16_t)a; } HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC_buff, length, DAC_ALIGN_12B_R); HAL_TIM_Base_Start(&htim7); /* USER CODE END 2 */
実行
正弦波500Hz、1000Hz、1500Hzのスペクトルグラフです。音もまったく聞こえないし、波形も出てきません。
正弦波2000Hzです。やっと小さく音が出始めて-54dBくらいの波形が計測できました。
正弦波2500Hzです。音も少し大きくなって波形が出ています。倍数である5000Hz以降も計測できています。
正弦波3000Hzです。かなり大きな音になりました。賑やかな会場でも十分聞こえる音量です。倍数波形も綺麗にグラフになっています。
動画です。
正弦波3500Hzです。大きな音ですが、先程より小さい気がします。倍数波形は7000Hzのみになりました。
正弦波4000Hzです。先程より更に小さく感じます。ここから先は、同じように指定波形と倍数波形が1つだけというのが続いて、音量は-30dB付近ピークで安定します。
Facebookでブログのシェアをしているのですが、ロボット仲間のZakさんからのコメントで、鉄鼠に採用したダイナミックスピーカUGCT7525AN4は共振周波数2700Hzなので500Hzの音は出ないのでは?とのこと。
調べてみると、スピーカのデータシート等に書いてある共振周波数は最低共振周波数f0を表しており、オーディオなどにおけるスピーカが再生できる低域周波数の限界値だとのこと。
よく調べてから採用すればよかったと後の祭りですが、2000~4000Hzくらいで十分使えそうなので、低音が出せないのは残念ですが、表示インターフェースとしては良しとします。
次、モータのPWMの確認をします。
参考サイト