108浏览
查看: 108|回复: 0

[ESP8266/ESP32] esp32S3AI模块做方言识别控制用电器项目的历程

[复制链接]
本帖最后由 dlzxlsx 于 2025-4-11 22:42 编辑

  有人说“千不怕,万不怕,就怕福建人讲土话",《明史》记载:“闽人入阁,自杨荣、陈山后,以语言难晓,垂二百年无人。”确实如此。我生活闽北一个小县城,同栋楼的邻居操向不同方言;有建瓯方言、有顺昌方言(据说与将乐方言一样)、有闽南方言、有客家方言、有福州方言、有畲族方言、有古田方言、有屏南言。不同方言的人在一天聊天,对于我而言,他们的方言比英语还难懂。在农村,有相当一部分上岁数的老者不会讲普通话,根本用不了现代的语音控制的智能设备,因为当前的语音智能设备听不懂福建土话。esp32S3AI模块做方言识别控制用电器项目的历程图8

   基于上述实际情况,该项目的目的就是尝试应用Edge impulse训练一个福建土话关键词识别的模型,实现用福建土话控制LED。

DAY 1


1.测试esp32S3AI模块麦克风功能
用下面代码实现捕获声音信号,板载麦克风引脚分配图
esp32S3AI模块做方言识别控制用电器项目的历程图1

确保电脑安装了esP32开发板后,上传下面的代码,实现显示环境声音波形。
  1. <font size="4">#include <ESP_I2S.h>
  2. I2SClass I2S;
  3. void setup() {
  4.   Serial.begin(115200);
  5.   while (!Serial) {
  6. }
  7.   // setup 38 PDM clock and 39 PDM data pins
  8.   I2S.setPinsPdmRx(38, 39);
  9.   // start I2S at 16 kHz with 16-bits per sample
  10.   if (!I2S.begin(I2S_MODE_PDM_RX, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
  11.     Serial.println("Failed to initialize I2S!");
  12.     while (1); // do nothing
  13.   }
  14. }
  15. void loop() {
  16.   // read a sample
  17.   int sample = I2S.read();
  18.   if (sample && sample != -1 && sample != 1) {
  19.     Serial.println(sample);
  20.   }
  21. }</font>
复制代码
esp32S3AI模块做方言识别控制用电器项目的历程图2
板子配置如上图
烧录代码后,在串口绘图可观察到声音变化图形
esp32S3AI模块做方言识别控制用电器项目的历程图3
表明代码与开发板麦克风工作正常。


2.实现将录制的声音保存到 microSD 卡
  1. <font size="4">#include "ESP_I2S.h"
  2. #include "FS.h"
  3. #include "SD.h"
  4. #include "SPI.h"
  5. void setup() {
  6.   I2SClass i2s;
  7.   uint8_t *wav_buffer;
  8.   size_t wav_size;
  9.   Serial.begin(115200);
  10.   while (!Serial) {
  11.     delay(10);
  12.   }
  13.   Serial.println("Initializing I2S bus...");
  14.   i2s.setPinsPdmRx(38,39);
  15.   // start I2S at 16 kHz with 16-bits per sample
  16.   if (!i2s.begin(I2S_MODE_PDM_RX, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
  17.     Serial.println("Failed to initialize I2S!");
  18.     while (1); // do nothing
  19.   }
  20.   Serial.println("I2S bus initialized.");
  21.   Serial.println("Initializing SD card...");
  22. #ifdef REASSIGN_PINS
  23.   SPI.begin(sck, miso, mosi, cs);
  24.   if (!SD.begin(cs)) {
  25. #else
  26.   if (!SD.begin()) {
  27. #endif
  28.     Serial.println("Card Mount Failed");
  29.     return;
  30.   }
  31.   uint8_t cardType = SD.cardType();
  32.   if (cardType == CARD_NONE) {
  33.     Serial.println("No SD card attached");
  34.     return;
  35.   }
  36.   Serial.println("SD card initialized.");
  37.   Serial.println("Recording 20 seconds of audio data...");
  38.   // Record 20 seconds of audio data
  39.   wav_buffer = i2s.recordWAV(20, &wav_size);
  40.   // Create a file on the SD card
  41.   File file = SD.open("/Arduinor_rec.wav", FILE_WRITE);
  42.   if (!file) {
  43.     Serial.println("Failed to open file for writing!");
  44.     return;
  45.   }
  46.   Serial.println("Writing audio data to file...");
  47.   // Write the audio data to the file
  48.   if (file.write(wav_buffer, wav_size) != wav_size) {
  49.     Serial.println("Failed to write audio data to file!");
  50.     return;
  51.   }
  52.   // Close the file
  53.   file.close();
  54.   Serial.println("Application complete.");
  55. }
  56. void loop() {
  57.   delay(1000);
  58.   Serial.printf(".");
  59. }</font>
复制代码
打开串口监视器,当串口输出信息”Recording 20 seconds of audio data...“时,模块开始录音,当串口显示”Writing audio data to file...“录音结束。随后出现............时,断电取下SD卡,用电脑查看音频文件arduinor_rec.wav,播放该文件,音量较小。
esp32S3AI模块做方言识别控制用电器项目的历程图4esp32S3AI模块做方言识别控制用电器项目的历程图5

采集声音到SD卡,可增加音量,代码如下:
  1. <font size="4">#include "ESP_I2S.h"
  2. #include "FS.h"
  3. #include "SD.h"
  4. #include "SPI.h"
  5. // make changes as needed
  6. #define RECORD_TIME   10  // seconds, The maximum value is 240
  7. #define WAV_FILE_NAME "data"
  8. #define I2S_READ_CHUNK_SIZE 1920  // 添加到文件头部或全局作用域‌:ml-citation{ref="1,6" data="citationList"}
  9. // do not change for best
  10. #define SAMPLE_RATE 16000U
  11. #define SAMPLE_BITS 16
  12. #define WAV_HEADER_SIZE 44
  13. #define VOLUME_GAIN 4 //取4音量较大,3应该更合适
  14. I2SClass I2S;
  15. String baseFileName;
  16. int fileNumber = 1;
  17. bool isRecording = false;
  18. void setup() {
  19.   
  20.   Serial.begin(115200);
  21.   while (!Serial) ;
  22.   
  23.   // setup 38 PDM clock and 39 PDM data pins
  24.   I2S.setPinsPdmRx(38,39);
  25.   if (!I2S.begin(I2S_MODE_PDM_RX, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
  26.     Serial.println("Failed to initialize I2S!");
  27.     while (1) ;
  28.   }
  29. #ifdef REASSIGN_PINS
  30.   SPI.begin(sck, miso, mosi, cs);
  31.   if (!SD.begin(cs)) {
  32. #else
  33.   if (!SD.begin()) {
  34. #endif
  35.     Serial.println("Card Mount Failed");
  36.     return;
  37.   }
  38.   uint8_t cardType = SD.cardType();
  39.   if (cardType == CARD_NONE) {
  40.     Serial.println("No SD card attached");
  41.     return;
  42.   }
  43.   Serial.println("SD card initialized.");
  44.   Serial.printf("Enter with the label name\n");
  45.   //record_wav();
  46. }
  47. void loop() {
  48.   if (Serial.available() > 0) {
  49.     String command = Serial.readStringUntil('\n');
  50.     command.trim();
  51.     if (command == "rec") {
  52.       isRecording = true;
  53.     } else {
  54.       baseFileName = command;
  55.       fileNumber = 1; // reset file number each time a new base file name is set
  56.       Serial.printf("Send rec for starting recording label \n");
  57.     }
  58.   }
  59.   if (isRecording && baseFileName != "") {
  60.     String fileName = "/" + baseFileName + "." + String(fileNumber) + ".wav";
  61.     fileNumber++;
  62.     record_wav(fileName);
  63.     delay(1000); // delay to avoid recording multiple files at once
  64.     isRecording = false;
  65.   }
  66. }
  67. void record_wav(String fileName)
  68. {
  69.   uint32_t sample_size = 0;
  70.   uint32_t record_size = (SAMPLE_RATE * SAMPLE_BITS / 8) * RECORD_TIME;
  71.   uint8_t *rec_buffer = NULL;
  72.   Serial.printf("Start recording ...\n");
  73.    
  74.   File file = SD.open(fileName.c_str(), FILE_WRITE);
  75.   // Write the header to the WAV file
  76.   uint8_t wav_header[WAV_HEADER_SIZE];
  77.   generate_wav_header(wav_header, record_size, SAMPLE_RATE);
  78.   file.write(wav_header, WAV_HEADER_SIZE);
  79.   // PSRAM malloc for recording
  80.   rec_buffer = (uint8_t *)ps_malloc(record_size);
  81.   if (rec_buffer == NULL) {
  82.     Serial.printf("malloc failed!\n");
  83.     while(1) ;
  84.   }
  85.   Serial.printf("Buffer: %d bytes\n", ESP.getPsramSize() - ESP.getFreePsram());
  86.   // 开始录音
  87.   sample_size = 0;
  88.   sample_size = I2S.readBytes((char*)rec_buffer, record_size);
  89.   if (sample_size == 0) {
  90.     Serial.println("Record Failed!");
  91.   } else {
  92.     Serial.printf("Record %d bytes\n", sample_size);
  93.   }
  94.   // Increase volume
  95.   for (uint32_t i = 0; i < sample_size; i += SAMPLE_BITS/8) {
  96.     (*(uint16_t *)(rec_buffer+i)) <<= VOLUME_GAIN;
  97.   }
  98.   // Write data to the WAV file
  99.   Serial.printf("Writing to the file ...\n");
  100.   if (file.write(rec_buffer, record_size) != record_size)
  101.     Serial.printf("Write file Failed!\n");
  102.   free(rec_buffer);
  103.   file.close();
  104.   Serial.printf("Recording complete: \n");
  105.   Serial.printf("Send rec for a new sample or enter a new label\n\n");
  106. }
  107. void generate_wav_header(uint8_t *wav_header, uint32_t wav_size, uint32_t sample_rate)
  108. {
  109.   // See this for reference: http://soundfile.sapp.org/doc/WaveFormat/
  110.   uint32_t file_size = wav_size + WAV_HEADER_SIZE - 8;
  111.   uint32_t byte_rate = SAMPLE_RATE * SAMPLE_BITS / 8;
  112.   const uint8_t set_wav_header[] = {
  113.     'R', 'I', 'F', 'F', // ChunkID
  114.     file_size, file_size >> 8, file_size >> 16, file_size >> 24, // ChunkSize
  115.     'W', 'A', 'V', 'E', // Format
  116.     'f', 'm', 't', ' ', // Subchunk1ID
  117.     0x10, 0x00, 0x00, 0x00, // Subchunk1Size (16 for PCM)
  118.     0x01, 0x00, // AudioFormat (1 for PCM)
  119.     0x01, 0x00, // NumChannels (1 channel)
  120.     sample_rate, sample_rate >> 8, sample_rate >> 16, sample_rate >> 24, // SampleRate
  121.     byte_rate, byte_rate >> 8, byte_rate >> 16, byte_rate >> 24, // ByteRate
  122.     0x02, 0x00, // BlockAlign
  123.     0x10, 0x00, // BitsPerSample (16 bits)
  124.     'd', 'a', 't', 'a', // Subchunk2ID
  125.     wav_size, wav_size >> 8, wav_size >> 16, wav_size >> 24, // Subchunk2Size
  126.   };
  127.   memcpy(wav_header, set_wav_header, sizeof(set_wav_header));
  128. }</font>
复制代码
上传后,在串口输入“hello",该字串将是声音文件的名称前缀,根据串口信息提示,输入”rec",开始录音,如此循环。
esp32S3AI模块做方言识别控制用电器项目的历程图6esp32S3AI模块做方言识别控制用电器项目的历程图7


DAY2


1.准备声音数据集
利用昨天最后一个程序实现声音收集。首先收集用建瓯方言(而且是乡村口音)说“开灯”关键词,方法是先格式化SD卡,插入ESP32S3AI模块SD卡槽,上电。打开Arduino IDE串口,等串口提示:“Send rec for a new sample or enter a new label”时,输入关键词的标签。由于每次录音只有10秒,我就多次采集该关键词,输入“on”,表示采集“开灯”语音录音文件。esp32S3AI模块做方言识别控制用电器项目的历程图12
此时,串口提示:esp32S3AI模块做方言识别控制用电器项目的历程图9
在串口中输入“rec”,开始采集该段录音。

esp32S3AI模块做方言识别控制用电器项目的历程图10

对着esp32s3用方言重复说“开灯”
esp32S3AI模块做方言识别控制用电器项目的历程图11
10秒后结束本次录音。

用上述方法分别录制10次噪音、10次“关灯”,10次“开灯”。
esp32S3AI模块做方言识别控制用电器项目的历程图33


2.用edge Impulse训练与生成模型
在edge impulse上创建一个名为“fj_dialect_detector"的工程,并把SD卡上的录音文件上传到平台数据集中。
esp32S3AI模块做方言识别控制用电器项目的历程图14用”split sample"把时长为10秒的文件分割成1秒的数据,方法如下图。

esp32S3AI模块做方言识别控制用电器项目的历程图13



如果数据集数量太少,少于50个,可用平台上的收集数据功能,通过电脑或手机采集声音数据。esp32S3AI模块做方言识别控制用电器项目的历程图42
esp32S3AI模块做方言识别控制用电器项目的历程图15esp32S3AI模块做方言识别控制用电器项目的历程图16


通过电脑麦克风采集的声音文件时,可以先标注收集数据的标签,如下图是将要采集的数据标签为off(关灯)
esp32S3AI模块做方言识别控制用电器项目的历程图17


当三类声音的样本量都有60个时,观察每个声音数据的波形,删除一些不合格的文件,如下图
esp32S3AI模块做方言识别控制用电器项目的历程图18


开关灯声音的正常的波形应该是下面这样的。
esp32S3AI模块做方言识别控制用电器项目的历程图19esp32S3AI模块做方言识别控制用电器项目的历程图20


我的数据集分三个分类:开灯、关灯、背景音,每类51个样本。
esp32S3AI模块做方言识别控制用电器项目的历程图21


3.准备好数据集,就可以进行设置Impulse

首先,impulse处理的音频文件为1秒窗口的数据点,每 500 毫秒滑动一次该窗口。 必须用小于 1 秒的零样本填充。另外,我们将每个 1 秒的音频样本经过预处理并转换为图像(例如,13 x 49 x 1)。因此,我使用 MFCC,它从音频信号中提取特征,这对分析人类的声音效果很好。模型各类是Classifier,使用卷积神经网络进行图像分类构建分类模型。

esp32S3AI模块做方言识别控制用电器项目的历程图22


点击下面的按键后保存参数,此时左侧多出了MFCC 和 Classifier两个条目
esp32S3AI模块做方言识别控制用电器项目的历程图23                                                   esp32S3AI模块做方言识别控制用电器项目的历程图24


点击MFCC,显示MFCC是把声音变图像的功能.
esp32S3AI模块做方言识别控制用电器项目的历程图25


点击”autotun parameters"(自动调节参数)
esp32S3AI模块做方言识别控制用电器项目的历程图26   


点击“save parameters”保存参数按键
esp32S3AI模块做方言识别控制用电器项目的历程图27

点击“generate feature"生成特征按键,可观察三个分类声音文件分布图
esp32S3AI模块做方言识别控制用电器项目的历程图28


esp32S3AI模块做方言识别控制用电器项目的历程图29



现在要设置训练模型的超参数。
esp32S3AI模块做方言识别控制用电器项目的历程图31
esp32S3AI模块做方言识别控制用电器项目的历程图30
我的数据量小,训练速度很快就完成。

esp32S3AI模块做方言识别控制用电器项目的历程图32

4.部署模型,首先要先生成Arduino 库文件
esp32S3AI模块做方言识别控制用电器项目的历程图34
点击 build,右侧显示生成模型的过程
esp32S3AI模块做方言识别控制用电器项目的历程图35

解压下载的模型文件
esp32S3AI模块做方言识别控制用电器项目的历程图36
     把该文件安装到Arduino libraries中,打开“esp32_microphone”文件,并做适合的修改,修改后的文件如下:

  1. <font size="4">#include <fj_dialect_detector_inferencing.h>
  2. #include "ESP_I2S.h"
  3. #define SAMPLE_RATE 16000U
  4. #define SAMPLE_BITS 16
  5. /** Audio buffers, pointers and selectors */
  6. typedef struct {
  7.     int16_t *buffer;
  8.     uint8_t buf_ready;
  9.     uint32_t buf_count;
  10.     uint32_t n_samples;
  11. } inference_t;
  12. static inference_t inference;
  13. static const uint32_t sample_buffer_size = 2048;
  14. static signed short sampleBuffer[sample_buffer_size];
  15. static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
  16. static bool record_status = true;
  17. I2SClass I2S;
  18. /**
  19. * @brief      Arduino setup function
  20. */
  21. void setup()
  22. {
  23.     // put your setup code here, to run once:
  24.     Serial.begin(115200);
  25.     // comment out the below line to cancel the wait for USB connection (needed for native USB)
  26.     while (!Serial);
  27.     Serial.println("Edge Impulse Inferencing Demo");
  28.     pinMode(3, OUTPUT); // Set the pin as output
  29.     digitalWrite(3, LOW); //Turn off
  30.    
  31.     // setup 38 PDM clock and 39 PDM data pins
  32.     I2S.setPinsPdmRx(38, 39);
  33.     if (!I2S.begin(I2S_MODE_PDM_RX, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO)) {
  34.       Serial.println("Failed to initialize I2S!");
  35.     while (1) ;
  36.     }
  37.     // summary of inferencing settings (from model_metadata.h)
  38.     ei_printf("Inferencing settings:\n");
  39.     ei_printf("\tInterval: ");
  40.     ei_printf_float((float)EI_CLASSIFIER_INTERVAL_MS);
  41.     ei_printf(" ms.\n");
  42.     ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
  43.     ei_printf("\tSample length: %d ms.\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16);
  44.     ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0]));
  45.     ei_printf("\nStarting continious inference in 2 seconds...\n");
  46.     ei_sleep(2000);
  47.     if (microphone_inference_start(EI_CLASSIFIER_RAW_SAMPLE_COUNT) == false) {
  48.         ei_printf("ERR: Could not allocate audio buffer (size %d), this could be due to the window length of your model\r\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT);
  49.         return;
  50.     }
  51.     ei_printf("Recording...\n");
  52. }
  53. /**
  54. * @brief      Arduino main function. Runs the inferencing loop.
  55. */
  56. void loop()
  57. {
  58.     bool m = microphone_inference_record();
  59.     if (!m) {
  60.         ei_printf("ERR: Failed to record audio...\n");
  61.         return;
  62.     }
  63.     signal_t signal;
  64.     signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
  65.     signal.get_data = µphone_audio_signal_get_data;
  66.     ei_impulse_result_t result = { 0 };
  67.     EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
  68.     if (r != EI_IMPULSE_OK) {
  69.         ei_printf("ERR: Failed to run classifier (%d)\n", r);
  70.         return;
  71.     }
  72.     int pred_index = 0;     // Initialize pred_index
  73.     float pred_value = 0;   // Initialize pred_value
  74.     // print the predictions
  75.     ei_printf("Predictions ");
  76.     //ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
  77.      //   result.timing.dsp, result.timing.classification, result.timing.anomaly);
  78.    // ei_printf(": \n");
  79.     for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
  80.         ei_printf("    %s: ", result.classification[ix].label);
  81.         ei_printf_float(result.classification[ix].value);
  82.         ei_printf("\n");
  83.     if (result.classification[ix].value > pred_value){
  84.            pred_index = ix;
  85.            pred_value = result.classification[ix].value;
  86.     }
  87.   }
  88.     ei_printf("%d: ",pred_index);
  89.     ei_printf("\n");
  90.     if (pred_index == 1){
  91.       digitalWrite(3, LOW); //Turn on
  92.     }
  93.     else if (pred_index == 2){
  94.       digitalWrite(3, HIGH); //Turn off
  95.     }
  96. #if EI_CLASSIFIER_HAS_ANOMALY == 1
  97.     ei_printf("    anomaly score: ");
  98.     ei_printf_float(result.anomaly);
  99.     ei_printf("\n");
  100. #endif
  101. }
  102. static void audio_inference_callback(uint32_t n_bytes)
  103. {
  104.     for(int i = 0; i < n_bytes>>1; i++) {
  105.         inference.buffer[inference.buf_count++] = sampleBuffer[i];
  106.         if(inference.buf_count >= inference.n_samples) {
  107.           inference.buf_count = 0;
  108.           inference.buf_ready = 1;
  109.         }
  110.     }
  111. }
  112. static void capture_samples(void* arg) {
  113.   const int32_t i2s_bytes_to_read = (uint32_t)arg;
  114.   size_t bytes_read = i2s_bytes_to_read;
  115.   while (record_status) {
  116.     /* read data at once from i2s */
  117.     //i2s_read((i2s_port_t)1, (void*)sampleBuffer, i2s_bytes_to_read, &bytes_read, 100);
  118.    
  119.     //I2S.i2s_read(esp_i2s::I2S_NUM_0, (void*)sampleBuffer, i2s_bytes_to_read, &bytes_read, 100);
  120.     //从 I2S 接口中读取 i2s_bytes_to_read 字节到 sampleBuffer 中,读取结果保存在 bytes_read 中。
  121.     bytes_read = I2S.readBytes((char*)sampleBuffer, i2s_bytes_to_read);
  122.     if (bytes_read <= 0) {
  123.       ei_printf("Error in I2S read : %d", bytes_read);
  124.     }
  125.     else {
  126.         if (bytes_read < i2s_bytes_to_read) {
  127.         ei_printf("Partial I2S read");
  128.         }
  129.         // scale the data (otherwise the sound is too quiet)
  130.         for (int x = 0; x < i2s_bytes_to_read/2; x++) {
  131.             sampleBuffer[x] = (int16_t)(sampleBuffer[x]) * 8;
  132.         }
  133.         if (record_status) {
  134.             audio_inference_callback(i2s_bytes_to_read);
  135.         }
  136.         else {
  137.             break;
  138.         }
  139.     }
  140.   }
  141.   vTaskDelete(NULL);
  142. }
  143. /**
  144. * @brief      Init inferencing struct and setup/start PDM
  145. *
  146. * @param[in]  n_samples  The n samples
  147. *
  148. * @return     { description_of_the_return_value }
  149. */
  150. static bool microphone_inference_start(uint32_t n_samples)
  151. {
  152.     inference.buffer = (int16_t *)malloc(n_samples * sizeof(int16_t));
  153.     if(inference.buffer == NULL) {
  154.         return false;
  155.     }
  156.     inference.buf_count  = 0;
  157.     inference.n_samples  = n_samples;
  158.     inference.buf_ready  = 0;
  159.     // if (i2s_init(EI_CLASSIFIER_FREQUENCY)) {
  160.     //     ei_printf("Failed to start I2S!");
  161.     // }
  162.     ei_sleep(100);
  163.     record_status = true;
  164.     xTaskCreate(capture_samples, "CaptureSamples", 1024 * 32, (void*)sample_buffer_size, 10, NULL);
  165.     return true;
  166. }
  167. /**
  168. * @brief      Wait on new data
  169. *
  170. * @return     True when finished
  171. */
  172. static bool microphone_inference_record(void)
  173. {
  174.     bool ret = true;
  175.     while (inference.buf_ready == 0) {
  176.         delay(10);
  177.     }
  178.     inference.buf_ready = 0;
  179.     return ret;
  180. }
  181. /**
  182. * Get raw audio signal data
  183. */
  184. static int microphone_audio_signal_get_data(size_t offset, size_t length, float *out_ptr)
  185. {
  186.     numpy::int16_to_float(&inference.buffer[offset], out_ptr, length);
  187.     return 0;
  188. }
  189. /**
  190. * @brief      Stop PDM and release buffers
  191. */
  192. static void microphone_inference_end(void)
  193. {
  194.     free(sampleBuffer);
  195.     ei_free(inference.buffer);
  196. }
  197. // static int i2s_init(uint32_t sampling_rate) {
  198. //   // Start listening for audio: MONO @ 8/16KHz
  199. //   i2s_config_t i2s_config = {
  200. //       .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX),
  201. //       .sample_rate = sampling_rate,
  202. //       .bits_per_sample = (i2s_bits_per_sample_t)16,
  203. //       .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
  204. //       .communication_format = I2S_COMM_FORMAT_I2S,
  205. //       .intr_alloc_flags = 0,
  206. //       .dma_buf_count = 8,
  207. //       .dma_buf_len = 512,
  208. //       .use_apll = false,
  209. //       .tx_desc_auto_clear = false,
  210. //       .fixed_mclk = -1,
  211. //   };
  212. //   i2s_pin_config_t pin_config = {
  213. //       .bck_io_num = 26,    // IIS_SCLK
  214. //       .ws_io_num = 32,     // IIS_LCLK
  215. //       .data_out_num = -1,  // IIS_DSIN
  216. //       .data_in_num = 33,   // IIS_DOUT
  217. //   };
  218. //   esp_err_t ret = 0;
  219. //   ret = i2s_driver_install((i2s_port_t)1, &i2s_config, 0, NULL);
  220. //   if (ret != ESP_OK) {
  221. //     ei_printf("Error in i2s_driver_install");
  222. //   }
  223. //   ret = i2s_set_pin((i2s_port_t)1, &pin_config);
  224. //   if (ret != ESP_OK) {
  225. //     ei_printf("Error in i2s_set_pin");
  226. //   }
  227. //   ret = i2s_zero_dma_buffer((i2s_port_t)1);
  228. //   if (ret != ESP_OK) {
  229. //     ei_printf("Error in initializing dma buffer with 0");
  230. //   }
  231. //   return int(ret);
  232. // }
  233. // static int i2s_deinit(void) {
  234. //     i2s_driver_uninstall((i2s_port_t)1); //stop & destroy i2s driver
  235. //     return 0;
  236. // }
  237. #if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_MICROPHONE
  238. #error "Invalid model for current sensor."
  239. #endif
  240. </font>
复制代码
文件上传后,打开串口,输出的信息如下:
esp32S3AI模块做方言识别控制用电器项目的历程图37


输出该信息对应的代码部分为
esp32S3AI模块做方言识别控制用电器项目的历程图38
对该段代码的变量说明:
result.classification[ix].label是标签名(noise,off,on);
result.classification[ix].value是当前声音为三个标签的可能性;
pred_index是最大可能标签的序号,noise--0,off--1,on--2.


esp32S3AI模块做方言识别控制用电器项目的历程图39                    esp32S3AI模块做方言识别控制用电器项目的历程图40
上两个截图是表示当时麦克风听到“关灯”“开灯”的方言词。


esp32S3AI模块做方言识别控制用电器项目的历程图41
上面的代码是根据听到的命令(标签值)控制板载LED的亮与灭。

全文完

感谢:Solomon Githu的文章“Environment audio monitoring wearable with XIAO ESP32S3 - Hackster.io”对本项目的顺利完成帮助巨大
代码的移植也借助于ChatGPT.
向他们致敬!






esp32_microphone.rar

3.08 KB, 下载次数: 0

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail