feat: add unity ci for multinet

This commit is contained in:
xysun 2023-07-11 19:08:59 +08:00
parent 686ee06302
commit f4d7793d68
327 changed files with 62193 additions and 0 deletions

10
test_apps/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
# Include the components directory of the main application:
#
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../esp-sr")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_sr_test)

6230
test_apps/da_kai_kong_tiao.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
dependencies:
espressif/esp-dsp:
component_hash: 59a67ce3be799201752ebde99890b0ab947054eff6463d83e944f2d4165d6905
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.4.4
idf:
component_hash: null
source:
type: idf
version: 5.0.2
manifest_hash: 47ee996a7c9b6dd8cb942a47ad68d70a24d315c7af8e456eeb0945d3e9575eff
target: esp32s3
version: 1.0.0

View File

@ -0,0 +1,17 @@
if(IDF_TARGET STREQUAL "esp32s3")
set(srcs
"test_app_main.c"
"test_wakenet.c"
"test_multinet.c"
"test_afe.c"
"test_chinese_tts.c"
)
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "."
REQUIRES unity esp-sr
WHOLE_ARCHIVE)
endif()

4025
test_apps/main/alexa.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

7554
test_apps/main/hilexin.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

78
test_apps/main/test_afe.c Normal file
View File

@ -0,0 +1,78 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_wn_iface.h"
#include "esp_wn_models.h"
#include "esp_afe_sr_models.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("audio_front_end create/destroy API & memory leak", "[afe]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_afe_sr_iface_t *afe_handle = (esp_afe_sr_iface_t *)&ESP_AFE_SR_HANDLE;
afe_config_t afe_config = AFE_CONFIG_DEFAULT();
afe_config.memory_alloc_mode = AFE_MEMORY_ALLOC_MORE_PSRAM;
afe_config.wakenet_init = true;
afe_config.wakenet_model_name = model_name;
afe_config.voice_communication_init = false;
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
esp_afe_sr_data_t *afe_data = afe_handle->create_from_config(&afe_config);
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size - create_internal_size);
afe_handle->destroy(afe_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i = 0; i < 6; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
printf("create ...\n");
afe_data = afe_handle->create_from_config(&afe_config);
printf("destroy ...\n");
afe_handle->destroy(afe_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i + 2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}

View File

@ -0,0 +1,55 @@
/* Example test application for testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
static void print_banner(const char* text);
void app_main(void)
{
/* These are the different ways of running registered tests.
* In practice, only one of them is usually needed.
*
* UNITY_BEGIN() and UNITY_END() calls tell Unity to print a summary
* (number of tests executed/failed/ignored) of tests executed between these calls.
*/
// print_banner("Executing one test by its name");
// UNITY_BEGIN();
// unity_run_test_by_name("Mean of an empty array is zero");
// UNITY_END();
// print_banner("Running tests with [mean] tag");
// UNITY_BEGIN();
// unity_run_tests_by_tag("[mean]", false);
// UNITY_END();
// print_banner("Running tests without [fails] tag");
// UNITY_BEGIN();
// unity_run_tests_by_tag("[fails]", true);
// UNITY_END();
// print_banner("Running all the registered tests");
// UNITY_BEGIN();
// unity_run_all_tests();
// UNITY_END();
// print_banner("Starting interactive test menu");
/* This function will not return, and will be busy waiting for UART input.
* Make sure that task watchdog is disabled if you use this function.
*/
unity_run_menu();
// unity_run_all_tests();
}
static void print_banner(const char* text)
{
printf("\n#### %s #####\n\n", text);
}

View File

@ -0,0 +1,96 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include <limits.h>
#include "unity.h"
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_tts.h"
#include "esp_tts_voice_xiaole.h"
#include "esp_tts_voice_template.h"
#include "esp_tts_player.h"
#include "esp_partition.h"
#include "esp_idf_version.h"
TEST_CASE("chinese tts create/destroy API & memory leak", "[tts]")
{
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
/*** 1. create esp tts handle ***/
void* voicedata;
const esp_partition_t* partition=esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");
assert(partition != NULL);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_partition_mmap_handle_t mmap_handle;
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &voicedata, &mmap_handle));
#else
spi_flash_mmap_handle_t mmap_handle;
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, SPI_FLASH_MMAP_DATA, &voicedata, &mmap_handle));
#endif
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
esp_tts_voice_t *voice=esp_tts_voice_set_init(&esp_tts_voice_template, (int16_t*)voicedata);
esp_tts_handle_t *tts_handle=esp_tts_create(voice);
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size - create_internal_size);
// test memory leak
esp_tts_voice_set_free(voice);
esp_tts_destroy(tts_handle);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_partition_munmap(mmap_handle); // support esp-idf v5
#else
spi_flash_munmap(mmap_handle); // support esp-idf v4
#endif
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i = 0; i < 6; i++) {
printf("init partition ...\n");
partition=esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");
assert(partition != NULL);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &voicedata, &mmap_handle));
#else
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, SPI_FLASH_MMAP_DATA, &voicedata, &mmap_handle));
#endif
printf("create ...\n");
voice=esp_tts_voice_set_init(&esp_tts_voice_template, (int16_t*)voicedata);
tts_handle=esp_tts_create(voice);
printf("destroy ...\n");
esp_tts_voice_set_free(voice);
esp_tts_destroy(tts_handle);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_partition_munmap(mmap_handle); // support esp-idf v5
#else
spi_flash_munmap(mmap_handle); // support esp-idf v4
#endif
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i + 2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}

View File

@ -0,0 +1,416 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRAMTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_mn_iface.h"
#include "esp_mn_models.h"
#include "da_kai_kong_tiao.h"
#include "tell_me_a_joke.h"
#include "alexa.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
#include "esp_mn_speech_commands.h"
#include "esp_process_sdkconfig.h"
TEST_CASE("multinet create/destroy API & memory leak", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size-create_internal_size);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
multinet->destroy(model_data);
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i=0; i<3; i++) {
printf("create ...\n");
model_data = multinet->create(model_name, 6000);
printf("destroy ...\n");
multinet->destroy(model_data);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i+2, mem_leak);
}
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("multinet cpu loading", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int frequency = multinet->get_samp_rate(model_data);
int audio_chunksize = multinet->get_samp_chunksize(model_data) * sizeof(int16_t);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
unsigned char* data = NULL;
int data_size = 0;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
data = tell_me_a_joke;
data_size = sizeof(tell_me_a_joke);
printf("commands: tell me a joke, size:%d\n", data_size);
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
data = da_kai_kong_tiao;
data_size = sizeof(da_kai_kong_tiao);
printf("commands: da kai kong tiao, size:%d\n", data_size);
}
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
esp_mn_state_t mn_state;
while (1) {
if ((chunks + 1)*audio_chunksize <= data_size) {
memcpy(buffer, data + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
mn_state = multinet->detect(model_data, buffer);
if (mn_state == ESP_MN_STATE_DETECTED) {
esp_mn_results_t *mn_result = multinet->get_results(model_data);
if (mn_result > 0)
printf("detected: command id:%d, string:%s\n",mn_result->command_id[0], mn_result->string);
else
printf("timeout\n");
break;
}
chunks++;
if (chunks > 600)
break;
}
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
chunks -= 7;
int run_ms = (chunks)*audio_chunksize/sizeof(int16_t)*1000/frequency;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, tv_ms*100.0/run_ms);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, mn_state == ESP_MN_STATE_DETECTED);
}
TEST_CASE("multinet set commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
printf("MODEL NAME %s\n", model_name);
esp_err_t state = ESP_OK;
// first
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
TEST_ESP_OK(esp_mn_commands_add(1, "TfL Mm c qbK"));
TEST_ESP_OK(esp_mn_commands_add(2, "hicST qbK"));
} else {
TEST_ESP_OK(esp_mn_commands_add(1, "TURN ON THE LIGHT"));
TEST_ESP_OK(esp_mn_commands_add(2, "TURN OFF THE KITCHEN LIGHT"));
}
error_phrases = esp_mn_commands_update();
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
TEST_ESP_OK(esp_mn_commands_add(1, "da kai dian deng"));
TEST_ESP_OK(esp_mn_commands_add(2, "guan bi chu fang dian deng"));
error_phrases = esp_mn_commands_update();
} else {
printf("Invalid language\n");
}
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
// second
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
TEST_ESP_OK(esp_mn_commands_add(3, "TkN nN eL jc LiTS"));
TEST_ESP_OK(esp_mn_commands_add(4, "TkN eF eL jc LiTS"));
} else {
TEST_ESP_OK(esp_mn_commands_add(3, "TURN OFF THE LIGHT"));
TEST_ESP_OK(esp_mn_commands_add(4, "TURN OM THE KITCHEN LIGHT"));
}
error_phrases = esp_mn_commands_update();
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(3, "guan bi dian deng");
esp_mn_commands_add(4, "da kai chu fang dian deng");
error_phrases = esp_mn_commands_update();
} else {
printf("Invalid language\n");
}
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
}
TEST_CASE("multinet add incorrect commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_err_t state = ESP_OK;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
state = esp_mn_commands_add(1, "TURN ON THE LIGHT 123");
assert(state == ESP_ERR_INVALID_STATE);
state = esp_mn_commands_add(2, "TURN. OFF THE LIGHT?");
assert(state == ESP_ERR_INVALID_STATE);
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
if (strcmp(model_name, "mn6_cn_ac") == 0 || strcmp(model_name, "mn6_cn") == 0) {
state = esp_mn_commands_add(1, "dakai dian deng");
assert(state == ESP_ERR_INVALID_STATE);
state = esp_mn_commands_add(2, "关闭电灯");
assert(state == ESP_ERR_INVALID_STATE);
} else {
state = esp_mn_commands_add(1, "k");
assert(state == ESP_ERR_INVALID_STATE);
}
} else {
printf("Invalid language\n");
}
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
}
TEST_CASE("multinet add duplicated commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(1, "TfL Mm c qbK");
esp_mn_commands_add(1, "TfL Mm c qbK");
} else {
esp_mn_commands_add(1, "TURN ON THE LIGHT");
esp_mn_commands_add(1, "TURN ON THE LIGHT");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "da kai dian deng");
esp_mn_commands_add(1, "da kai dian deng");
} else {
printf("Invalid language\n");
}
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
}
TEST_CASE("multinet print active commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(1, "TfL Mm qbK");
} else {
esp_mn_commands_add(1, "THIS SHOULD NOT APPEAR IN ACTIVE COMMANDS");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "bu ying gai chu xian zai biao zhong");
} else {
printf("Invalid language\n");
}
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}
TEST_CASE("multinet remove commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_remove("TfL Mm c qbK");
} else {
esp_mn_commands_remove("TURN ON THE LIGHT");;
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_remove("da kai dian deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}
TEST_CASE("multinet clear and add commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
esp_mn_commands_clear();
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(1, "TfL Mm c qbK");
} else {
esp_mn_commands_add(1, "TURN ON THE LIGHT");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "da kai dian deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
esp_mn_commands_print();
multinet->print_active_speech_commands(model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(2, "Sgl c Sel");
} else {
esp_mn_commands_add(2, "SING A SONG");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "guan bi dian deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
esp_mn_commands_print();
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}
TEST_CASE("multinet modify commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_modify("TfL Mm c qbK", "TfL TfL Mm c qbK");
} else {
esp_mn_commands_modify("TURN ON THE LIGHT", "TURN ON THE KITCHEN LIGHT");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_modify("da kai dian deng", "da kai chu fang deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}

View File

@ -0,0 +1,121 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_wn_iface.h"
#include "esp_wn_models.h"
#include "hilexin.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_3CH_95);
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size - create_internal_size);
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i = 0; i < 6; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
wakenet = esp_wn_handle_from_name(model_name);
printf("create ...\n");
// typedef enum {
// DET_MODE_90 = 0, // Normal
// DET_MODE_95 = 1, // Aggressive
// DET_MODE_2CH_90 = 2,
// DET_MODE_2CH_95 = 3,
// DET_MODE_3CH_90 = 4,
// DET_MODE_3CH_95 = 5,
// } det_mode_t;
model_data = wakenet->create(model_name, i);
printf("destroy ...\n");
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i + 2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("wakenet detect API & cpu loading", "[wn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_95);
int frequency = wakenet->get_samp_rate(model_data);
int audio_chunksize = wakenet->get_samp_chunksize(model_data) * sizeof(int16_t);
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
int detected = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
while (1) {
if ((chunks + 1)*audio_chunksize <= sizeof(hilexin)) {
memcpy(buffer, hilexin + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
int res = wakenet->detect(model_data, buffer);
if (res > 0) {
detected = 1;
}
chunks++;
if (detected == 1) {
break;
}
}
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
int run_ms = (chunks) * audio_chunksize / sizeof(int16_t) * 1000 / frequency;
float cpu_loading = tv_ms * 100.0 / run_ms;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, cpu_loading);
wakenet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (cpu_loading < 75 && detected == 1));
}

View File

@ -0,0 +1 @@
59a67ce3be799201752ebde99890b0ab947054eff6463d83e944f2d4165d6905

View File

@ -0,0 +1,56 @@
.config
*.o
*.pyc
# gtags
GTAGS
GRTAGS
GPATH
# emacs
.dir-locals.el
# emacs temp file suffixes
*~
.#*
\#*#
# eclipse setting
.settings
# MacOS directory files
.DS_Store
# Example project files
examples/**/sdkconfig
examples/**/sdkconfig.old
examples/**/build
examples/**/dependencies.lock
exmaples/**/managed_components
# Test app files
test_app/build
test_app/sdkconfig
test_app/sdkconfig.old
# Doc build artifacts
docs/_build/
docs/doxygen-warning-log.txt
docs/sphinx-warning-log.txt
docs/sphinx-warning-log-sanitized.txt
docs/xml/
docs/xml_in/
docs/man/
docs/doxygen_sqlite3.db
TEST_LOGS
# gcov coverage reports
*.gcda
*.gcno
coverage.info
coverage_report/
# VS Code Settings
.vscode/

View File

@ -0,0 +1,64 @@
# Esp-dsp Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Target tests
### Fixed
- Add Bi-Quad for esp32s3 into common CMakeLists.txt
### Changed
- Update documentation build
### Removed
## [1.4.0] 2023-05-29
### Added
- Complex signal generator dsps_cplx_gen()
- FIR f32 filter optimized for esp32s3
- Memcpy and Memset optimized for esp32s3
### Fixed
- Fix in tests to pass
- Minimum coeffcient length for fird_s16
- Include malloc.h into dsps_fft4r_fc32_ansi.c
- Fix for calculation length for dsps_corr_f32_axxx
### Changed
### Removed
## [1.3.0] 2023-03-10
### Added
- Fixed point FIR filter with decimation
- Update tag to 1.2.1 for component manager
- Extend dsp_power_of_two() to 32-bit value
### Fixed
- add various links to idf_component.yml, exclude unnecessary files
- cmake: update component CMakeLists.txt file syntax to IDF v4.x+
- docs: move instructions for contributors into CONTRIBUTING.md
- docs: update README.md to use IDF component manager for installation
- drop IDF v4.0 and v4.1 support, add a CI build with IDF release/v5.0
- examples: remove GNU Make instructions from README files
- examples: allow examples to be installed from the component manager
- Fix for fft_cplx2reC_f32 function
- Wno-format-fix related errors
- Wrong path for extra component directory
### Changed
### Removed
## [1.2.0] 2022-09-22

View File

@ -0,0 +1,160 @@
set(srcs "modules/common/misc/dsps_pwroftwo.cpp"
"modules/common/misc/aes3_tie_log.c"
"modules/dotprod/float/dsps_dotprod_f32_ae32.S"
"modules/dotprod/float/dsps_dotprod_f32_m_ae32.S"
"modules/dotprod/float/dsps_dotprode_f32_ae32.S"
"modules/dotprod/float/dsps_dotprode_f32_m_ae32.S"
"modules/dotprod/float/dsps_dotprod_f32_ansi.c"
"modules/dotprod/float/dsps_dotprode_f32_ansi.c"
"modules/dotprod/float/dsps_dotprod_f32_aes3.S"
"modules/dotprod/fixed/dsps_dotprod_s16_ae32.S"
"modules/dotprod/fixed/dsps_dotprod_s16_m_ae32.S"
"modules/dotprod/fixed/dsps_dotprod_s16_ansi.c"
"modules/dotprod/float/dspi_dotprod_f32_ansi.c"
"modules/dotprod/float/dspi_dotprod_off_f32_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_s16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_u16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_s8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_u8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_s16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_u16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_s8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_u8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_s16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_u16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_s16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_u16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_s8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_u8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_u8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_s8_aes3.S"
"modules/matrix/float/dspm_mult_3x3x1_f32_ae32.S"
"modules/matrix/float/dspm_mult_3x3x3_f32_ae32.S"
"modules/matrix/float/dspm_mult_4x4x1_f32_ae32.S"
"modules/matrix/float/dspm_mult_4x4x4_f32_ae32.S"
"modules/matrix/float/dspm_mult_f32_ae32.S"
"modules/matrix/float/dspm_mult_f32_aes3.S"
"modules/matrix/float/dspm_mult_f32_ansi.c"
"modules/matrix/fixed/dspm_mult_s16_ae32.S"
"modules/matrix/fixed/dspm_mult_s16_m_ae32_vector.S"
"modules/matrix/fixed/dspm_mult_s16_m_ae32.S"
"modules/matrix/fixed/dspm_mult_s16_ansi.c"
"modules/matrix/fixed/dspm_mult_s16_aes3.S"
"modules/matrix/mat/mat.cpp"
"modules/math/mulc/float/dsps_mulc_f32_ansi.c"
"modules/math/addc/float/dsps_addc_f32_ansi.c"
"modules/math/mulc/fixed/dsps_mulc_s16_ansi.c"
"modules/math/mulc/fixed/dsps_mulc_s16_ae32.S"
"modules/math/add/float/dsps_add_f32_ansi.c"
"modules/math/add/fixed/dsps_add_s16_ansi.c"
"modules/math/add/fixed/dsps_add_s16_ae32.S"
"modules/math/sub/float/dsps_sub_f32_ansi.c"
"modules/math/mul/float/dsps_mul_f32_ansi.c"
"modules/math/mul/fixed/dsps_mul_s16_ansi.c"
"modules/math/mulc/float/dsps_mulc_f32_ae32.S"
"modules/math/addc/float/dsps_addc_f32_ae32.S"
"modules/math/add/float/dsps_add_f32_ae32.S"
"modules/math/sub/float/dsps_sub_f32_ae32.S"
"modules/math/mul/float/dsps_mul_f32_ae32.S"
"modules/math/sqrt/float/dsps_sqrt_f32_ansi.c"
"modules/fft/float/dsps_fft2r_fc32_ae32_.S"
"modules/fft/float/dsps_fft2r_fc32_aes3_.S"
"modules/fft/float/dsps_fft2r_fc32_ansi.c"
"modules/fft/float/dsps_fft2r_fc32_ae32.c"
"modules/fft/float/dsps_bit_rev_lookup_fc32_aes3.S"
"modules/fft/float/dsps_fft4r_fc32_ansi.c"
"modules/fft/float/dsps_fft4r_fc32_ae32.c"
"modules/fft/float/dsps_fft2r_bitrev_tables_fc32.c"
"modules/fft/float/dsps_fft4r_bitrev_tables_fc32.c"
"modules/fft/fixed/dsps_fft2r_sc16_ae32.S"
"modules/fft/fixed/dsps_fft2r_sc16_ansi.c"
"modules/fft/fixed/dsps_fft2r_sc16_aes3.S"
"modules/dct/float/dsps_dct_f32.c"
"modules/support/snr/float/dsps_snr_f32.cpp"
"modules/support/sfdr/float/dsps_sfdr_f32.cpp"
"modules/support/misc/dsps_d_gen.c"
"modules/support/misc/dsps_h_gen.c"
"modules/support/misc/dsps_tone_gen.c"
"modules/support/cplx_gen/dsps_cplx_gen.c"
"modules/support/cplx_gen/dsps_cplx_gen.S"
"modules/support/cplx_gen/dsps_cplx_gen_init.c"
"modules/support/mem/esp32s3/dsps_memset_aes3.S"
"modules/support/mem/esp32s3/dsps_memcpy_aes3.S"
"modules/support/view/dsps_view.cpp"
"modules/windows/hann/float/dsps_wind_hann_f32.c"
"modules/windows/blackman/float/dsps_wind_blackman_f32.c"
"modules/windows/blackman_harris/float/dsps_wind_blackman_harris_f32.c"
"modules/windows/blackman_nuttall/float/dsps_wind_blackman_nuttall_f32.c"
"modules/windows/nuttall/float/dsps_wind_nuttall_f32.c"
"modules/windows/flat_top/float/dsps_wind_flat_top_f32.c"
"modules/conv/float/dsps_conv_f32_ansi.c"
"modules/conv/float/dsps_conv_f32_ae32.S"
"modules/conv/float/dsps_corr_f32_ansi.c"
"modules/conv/float/dsps_corr_f32_ae32.S"
"modules/conv/float/dsps_ccorr_f32_ansi.c"
"modules/conv/float/dsps_ccorr_f32_ae32.S"
"modules/iir/biquad/dsps_biquad_f32_ae32.S"
"modules/iir/biquad/dsps_biquad_f32_aes3.S"
"modules/iir/biquad/dsps_biquad_f32_ansi.c"
"modules/iir/biquad/dsps_biquad_gen_f32.c"
"modules/fir/float/dsps_fir_f32_ae32.S"
"modules/fir/float/dsps_fir_f32_aes3.S"
"modules/fir/float/dsps_fird_f32_ae32.S"
"modules/fir/float/dsps_fir_f32_ansi.c"
"modules/fir/float/dsps_fir_init_f32.c"
"modules/fir/float/dsps_fird_f32_ansi.c"
"modules/fir/float/dsps_fird_init_f32.c"
"modules/fir/fixed/dsps_fird_init_s16.c"
"modules/fir/fixed/dsps_fird_s16_ansi.c"
"modules/fir/fixed/dsps_fird_s16_ae32.S"
"modules/fir/fixed/dsps_fir_s16_m_ae32.S"
"modules/fir/fixed/dsps_fird_s16_aes3.S"
# EKF files
"modules/kalman/ekf/common/ekf.cpp"
"modules/kalman/ekf_imu13states/ekf_imu13states.cpp"
)
set(include_dirs "modules/dotprod/include"
"modules/support/include"
"modules/support/mem/include"
"modules/windows/include"
"modules/windows/hann/include"
"modules/windows/blackman/include"
"modules/windows/blackman_harris/include"
"modules/windows/blackman_nuttall/include"
"modules/windows/nuttall/include"
"modules/windows/flat_top/include"
"modules/iir/include"
"modules/fir/include"
"modules/math/include"
"modules/math/add/include"
"modules/math/sub/include"
"modules/math/mul/include"
"modules/math/addc/include"
"modules/math/mulc/include"
"modules/math/sqrt/include"
"modules/matrix/include"
"modules/fft/include"
"modules/dct/include"
"modules/conv/include"
"modules/common/include"
# EKF files
"modules/kalman/ekf/include"
"modules/kalman/ekf_imu13states/include"
)
set(priv_include_dirs "modules/dotprod/float"
"modules/dotprod/fixed")
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include_dirs}
PRIV_INCLUDE_DIRS ${priv_include_dirs})

View File

@ -0,0 +1,64 @@
# Contributing
Contributions to ESP-DSP project in the form of pull requests, bug reports, and feature requests are welcome!
This document covers various topics related to contributions to the ESP-DSP projects. Please read it if you plan to submit a PR!
## CLA
We require accepting the contributor's license agreement for all pull requests. When opening a pull request the first time you will be prompted to sign the CLA by the [CLA Assistant](https://cla-assistant.io/) service.
## Large-scale Changes
If you'd like to propose a change to the existing APIs or a large-scale refactoring of the implementation, we recommend opening an issue first to discuss this.
## Updating the Benchmarks Table
The benchmarks table [esp-dsp-benchmarks.rst](docs/esp-dsp-benchmarks.rst) contains benchmarks for ESP32 and ESP32-S3 CPUs. The benchmarks are collected with compiler optimizations for speed (-Os) and for size (-O2). This table may need to be updated if you have changed the implementations of some of the functions.
To build this table:
- Build the test application in the `test_app` directory.
- Run "DSP Benchmarks data" test and copy the output into the CSV file [docs/esp_bm_results.csv](docs/esp_bm_results.csv).
- Run the [docs/build_bm_table.py](docs/build_bm_table.py) script to update the benchmarks table [esp-dsp-benchmarks.rst](docs/esp-dsp-benchmarks.rst).
If you have added new functions, modify the [benchmarks test](test/test_dsp.c) to call these new functions.
## Supported IDF Versions
The component is expected to be usable with multiple supported IDF versions. You can find the list in the [CI workflow file](.gitlab-ci.yml).
Note that for compatibility reasons, the component has to support the legacy GNU Make build system which was present up until ESP-IDF v5.0. Remember to add or update `component.mk` and `Makefile` files when adding or changing examples. GNU Make support can be removed from ESP-DSP when IDF v4.4 maintenance period expires.
## Releasing a new version
Maintainers should follow the steps below to release a new version of ESP-DSP component. Assuming the new version is `vX.Y.Z`:
1. Ensure you are on the latest `master` branch, then create a new branch:
```bash
git checkout master
git pull --ff-only origin master
git checkout -b update_version_vX.Y.Z
```
1. Update the version in [idf_component.yml](idf_component.yml):
```yml
version: "X.Y.Z"
```
1. Commit the changes:
```bash
git add idf_component.yml
git commit -s -m "version: update to vX.Y.Z"
```
1. Create the new tag:
```bash
git tag -s -a -m "vX.Y.Z" vX.Y.Z
```
1. Push the tag and the branch to the internal repository:
```bash
git push origin update_version_vX.Y.Z
git push origin vX.Y.Z
```
1. Create the merge request, get it reviewed and merged.
1. CI will automatically push the tag to Github and will upload the new version to the IDF Component Registry.
1. Go to https://github.com/espressif/esp-dsp/releases and create a release from the tag vX.Y.Z.
1. Write the release notes and publish the release.

View File

@ -0,0 +1,61 @@
menu "DSP Library"
config DSP_OPTIMIZATIONS_SUPPORTED
bool
default y
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
choice DSP_OPTIMIZATION
bool "DSP Optimization"
default DSP_OPTIMIZED if DSP_OPTIMIZATIONS_SUPPORTED
default DSP_ANSI
help
An ANSI C version could be used for verification and debug purpose,
or for chips where an optimized version is not available.
config DSP_ANSI
bool "ANSI C"
config DSP_OPTIMIZED
bool "Optimized"
depends on DSP_OPTIMIZATIONS_SUPPORTED
endchoice
config DSP_OPTIMIZATION
int
default 0 if DSP_ANSI
default 1 if DSP_OPTIMIZED
choice DSP_MAX_FFT_SIZE
bool "Maximum FFT length"
default DSP_MAX_FFT_SIZE_4096
help
This is default FFT size for internal usage.
config DSP_MAX_FFT_SIZE_512
bool "512"
config DSP_MAX_FFT_SIZE_1024
bool "1024"
config DSP_MAX_FFT_SIZE_2048
bool "2048"
config DSP_MAX_FFT_SIZE_4096
bool "4096"
config DSP_MAX_FFT_SIZE_8192
bool "8192"
config DSP_MAX_FFT_SIZE_16384
bool "16384"
config DSP_MAX_FFT_SIZE_32768
bool "32768"
endchoice
config DSP_MAX_FFT_SIZE
int
default 512 if DSP_MAX_FFT_SIZE_512
default 1024 if DSP_MAX_FFT_SIZE_1024
default 2048 if DSP_MAX_FFT_SIZE_2048
default 4096 if DSP_MAX_FFT_SIZE_4096
default 8192 if DSP_MAX_FFT_SIZE_8192
default 16384 if DSP_MAX_FFT_SIZE_16384
default 32768 if DSP_MAX_FFT_SIZE_32768
endmenu

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,82 @@
[![Component Registry](https://components.espressif.com/components/espressif/esp-dsp/badge.svg)](https://components.espressif.com/components/espressif/esp-dsp)
# Espressif DSP Library
ESP-DSP is the official DSP library for [ESP32](https://espressif.com/en/products/hardware/esp32/overview) and [ESP32-S3](https://espressif.com/en/products/hardware/esp32s3/overview) chips.
## Overview
ESP-DSP is intended to be used as an [ESP-IDF](https://github.com/espressif/esp-idf) component. For the introduction to ESP-IDF, refer to the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/).
The ESP-DSP library includes implementations of the following functions:
- Matrix multiplication: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#matrix-operations-apis)
- Dot product: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#dot-product), [example](https://github.com/espressif/esp-dsp/tree/master/examples/dotprod)
- FFT: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#fft), [example](https://github.com/espressif/esp-dsp/tree/master/examples/fft)
- IIR: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#iir), [example](https://github.com/espressif/esp-dsp/tree/master/examples/iir)
- FIR: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#fir)
- Vector math operations: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#math)
- Kalman filter: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#kalman)
Many of the library functions are written in assembly and are optimized for the CPU configuration used in the ESP32. In addition to the optimized implementations, reference implementations written in ANSI C are provided.
Function implementations are provided for single precision floating point (32-bit float), and 16-bit signed integers.
## Documentation
- [ESP-DSP Overview](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-library.html)
- [ESP-DSP API Reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html)
- [ESP-DSP Benchmarks](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-benchmarks.html)
Documentation found in the above links is automatically generated from the contents of this repository. If you find that some information is missing or incomplete, please report an issue.
## Installation and Usage
The ESP-DSP library is a component for the [ESP-IDF build system](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html).
The recommended way to use the component is to install it from the [IDF Component Registry](https://components.espressif.com/components/espressif/esp-dsp).
### Adding ESP-DSP component to an existing project
In the project directory, run:
```bash
idf.py add-dependency "espressif/esp-dsp"
```
This will add the esp-dsp component as a dependency to the `main` component of your project. You can also add it by editing the `idf_component.yml` file manually.
### Downloading ESP-DSP examples
You can download the example projects from the IDF Component Registry website or use the `idf.py create-project-from-example` command. For example:
```bash
idf.py create-project-from-example "espressif/esp-dsp:basic_math"
```
Please refer to the [IDF Component Registry](https://components.espressif.com/components/espressif/esp-dsp) for the download links and the instructions.
You can also use Git to clone this repository and find all the examples in the `examples/` subdirectory. For the list of the examples, please see [README.md](examples/README.md) in the examples directory.
### Building and running ESP-DSP examples
Build, flash and monitor as this is usually done for ESP-IDF projects:
```bash
idf.py -p PORT flash monitor
```
where `PORT` is the UART port name of your development board, such as `/dev/ttyUSB0` or `COM1`.
Note that you need to set up ESP-IDF before building the project. Refer to the [ESP-IDF Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) if you don't have the environment set up yet.
## Reporting Issues
If you have found an issue in ESP-DSP, or wish to submit an enhancement request, please use the [Issues](https://github.com/espressif/esp-dsp/issues) section on Github.
For general questions related to this library, please use the [esp32.com forum](https://esp32.com/).
## Contributing to ESP-DSP
Please check [CONTRIBUTING.md](CONTRIBUTING.md) if you'd like to contribute to ESP-DSP.
## Copyrights and License
All original source code in this repository is Copyright (C) 2018-2023 Espressif Systems. This source code is licensed under the Apache License 2.0 as described in the file LICENSE.

View File

@ -0,0 +1,84 @@
#!/bin/bash
#
# Build the test app and all examples from the examples directory.
# Expects EXAMPLE_TARGETS and TEST_TARGETS environment variables to be set.
# Each variable is the list of IDF_TARGET values to build the examples and
# the test app for, respectively.
#
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ -n "${DEBUG_SHELL}" ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
if [[ -z "${EXAMPLE_TARGETS}" || -z "${TEST_TARGETS}" ]]
then
echo "EXAMPLE_TARGETS and TEST_TARGETS environment variables must be set before calling this script"
exit 1
fi
if [[ -z "${SKIP_GNU_MAKE_BUILD}" ]]
then
echo "SKIP_GNU_MAKE_BUILD not set, will build with GNU Make based build system as well."
export SKIP_GNU_MAKE_BUILD=0
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
set -o nounset # Exit if variable not set.
STARS='***************************************************'
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
# build_for_targets <target list>
# call this in the project directory
function build_for_targets
{
target_list="$1"
for IDF_TARGET in ${target_list}
do
export IDF_TARGET
if [[ "${IDF_TARGET}" = "esp32" ]] && [[ "${SKIP_GNU_MAKE_BUILD}" = "0" ]]
then
echo "${STARS}"
echo "Building in $PWD with Make"
# -j option will be set via MAKEFLAGS in .gitlab-ci.yml
# shellcheck disable=SC2015
make defconfig && make || die "Make build in ${PWD} has failed"
rm -rf build
fi
echo "${STARS}"
echo "Building in $PWD with CMake for ${IDF_TARGET}"
rm -f sdkconfig
idf.py set-target "${IDF_TARGET}"
idf.py build || die "CMake build in ${PWD} has failed for ${IDF_TARGET}"
idf.py fullclean || true
done
}
# Build the test app
echo "${STARS}"
pushd test_app
build_for_targets "${TEST_TARGETS}"
popd
# Build the examples
pushd examples
EXAMPLES=$(find . -maxdepth 1 -mindepth 1 -type d | cut -d '/' -f 2)
for NAME in ${EXAMPLES}
do
pushd "${NAME}"
build_for_targets "${EXAMPLE_TARGETS}"
popd
done
popd

View File

@ -0,0 +1,20 @@
# ESP-DSP Examples
This directory contains a range of examples for ESP-DSP library.
These examples are intended to demonstrate part of ESP-DSP functionality (e.g. initialization, execution) and to provide code that you can copy and adapt into your own projects.
See the [README.md](../README.md) file in the upper level directory for more information about ESP-DSP.
# Example Layout
The examples are grouped into subdirectories by category. Each category directory contains one or more example projects:
* [Dot Product Calculation](./dotprod/README.md) Example
* [Basic Math Operations](./basic_math/README.md) Example
* [FFT](./fft/README.md) Example
* [Matrix](./matrix/README.md) Example
* [FFT Window](./fft_window/README.md) Example
* [IIR Filter](./iir/README.md) Example
* [Kalman Filter](./kalman/README.md) Example
* [FIR Filter](.fir/README.md) Example

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(basic_math)

View File

@ -0,0 +1,75 @@
# Basic Math Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use basic math functions from esp-dsp library. Example does the following steps:
1. Initialize the library
2. Initialize input signals with 1024 samples
3. Apply window to input signal by standard C loop.
4. Calculate FFT for 1024 complex samples and show the result
5. Show results on the plots
6. Apply window to input signal by basic math functions dsps_mul_f32 and dsps_mulc_f32.
7. Calculate FFT for 1024 complex samples
8. Show results on the plots
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```bash
I (132) main: *** Start Example. ***
I (132) main: *** Multiply tone signal with Hann window by standard C loop. ***
I (152) view: Data min[432] = -173.749878, Data max[205] = 23.849705
________________________________________________________________
0 | |
1 | |
2 | |
3 || |
4 | | |
5 || | |
6 ||| || |
7 ||||| |||| |
8||||||||||||||| |||||| |
9 |||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (162) view: Plot: Length=512, min=-120.000000, max=40.000000
I (162) main: *** Multiply tone signal with Hann window by esp-dsp basic math functions. ***
I (162) view: Data min[432] = -173.749878, Data max[205] = 23.849705
________________________________________________________________
0 | |
1 | |
2 | |
3 || |
4 | | |
5 || | |
6 ||| || |
7 ||||| |||| |
8||||||||||||||| |||||| |
9 |||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (172) view: Plot: Length=512, min=-120.000000, max=40.000000
I (172) main: *** End Example. ***
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_math_main.c")

View File

@ -0,0 +1,96 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include <math.h>
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use FFT from esp-dsp library
#define N_SAMPLES 1024
int N = N_SAMPLES;
// Input test array
__attribute__((aligned(16)))
float x1[N_SAMPLES];
// Window coefficients
__attribute__((aligned(16)))
float wind[N_SAMPLES];
// working complex array
__attribute__((aligned(16)))
float y_cf[N_SAMPLES*2];
// Pointers to result arrays
float* y1_cf = &y_cf[0];
static void process_and_show(float* data, int length)
{
dsps_fft2r_fc32(data, length);
// Bit reverse
dsps_bit_rev_fc32(data, length);
// Convert one complex vector to two complex vectors
dsps_cplx2reC_fc32(data, length);
for (int i = 0 ; i < length/2 ; i++) {
data[i] = 10 * log10f((data[i * 2 + 0] * data[i * 2 + 0] + data[i * 2 + 1] * data[i * 2 + 1])/N);
}
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
dsps_view(data, length/2, 64, 10, -120, 40, '|');
}
void app_main()
{
esp_err_t ret;
ESP_LOGI(TAG, "*** Start Example. ***");
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
// Generate Hann window
dsps_wind_hann_f32(wind, N);
ESP_LOGI(TAG, "*** Multiply tone signal with Hann window by standard C loop. ***");
// Generate input signal
dsps_tone_gen_f32(x1, N, 1., 0.2, 0);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = x1[i]*wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGI(TAG, "*** Multiply tone signal with Hann window by esp-dsp basic math functions. ***");
// Convert two input vectors to one complex vector with basic functions
dsps_mul_f32(x1, wind, y_cf, N, 1, 1, 2); // Multiply input array with window and store as real part
dsps_mulc_f32(&y_cf[1], &y_cf[1], N, 0, 2, 2); // Clear imaginary part of the complex signal
process_and_show(y_cf, N);
ESP_LOGI(TAG, "*** End Example. ***");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(dotprod)

View File

@ -0,0 +1,42 @@
# Dot Product Calculation Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use dotprod dsps_dotprod_f32 from esp-dsp library. Example does the following steps:
1. Initialize the input arrays
2. Calculate dot product of two arrays
3. Compare results and calculate execution time in cycles.
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```
I (55) main: Start Example.
I (55) main: The sum of 101 elements from 0..100 = 5050.000000
I (55) main: Operation for 101 samples took 1381 cycles
I (65) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_dotproduct_main.c")

View File

@ -0,0 +1,65 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use dsps_dotprod_f32 and dsps_dotprode_f32 functions
#define N_SAMPLES 256
int N = N_SAMPLES;
__attribute__((aligned(16)))
float input1[N_SAMPLES];
__attribute__((aligned(16)))
float input2[N_SAMPLES];
void app_main()
{
esp_err_t ret;
ESP_LOGI(TAG, "Start Example.");
// The example will calculate n!
//Initialize an input arrays
for (int i=0 ; i< N ; i++)
{
input1[i] = 1;
input2[i] = i;
}
float result1 = 0;
unsigned int start_b = dsp_get_cpu_cycle_count();
ret = dsps_dotprod_f32(input1, input2, &result1, 101);
unsigned int end_b = dsp_get_cpu_cycle_count();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Operation error = %i", ret);
}
ESP_LOGI(TAG, "The sum of 101 elements from 0..100 = %f", result1);
ESP_LOGI(TAG, "Operation for 101 samples take %i cycles", end_b - start_b);
ESP_LOGI(TAG, "End Example.");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(fft2r)

View File

@ -0,0 +1,91 @@
# FFT Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use FFT functionality from esp-dsp library. Example does the following steps:
1. Initialize the library
2. Initialize input signals with 1024 samples: one 0 dB, second with -20 dB
3. Combine two signals as one complex input signal and apply window to input signals paar.
4. Calculate FFT for 1024 complex samples
5. Apply bit reverse operation for output complex vector
6. Split one complex FFT output spectrum to two real signal spectrums
7. Show results on the plots
8. Show execution time of FFT
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```
I (59) main: Start Example.
W (89) main: Signal x1
I (89) view: Data min[495] = -162.760925, Data max[164] = 23.938747
________________________________________________________________
0 |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | | |
7 | | |
8 || || |
9|||||||||||||||||| ||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (159) view: Plot: Length=512, min=-60.000000, max=40.000000
W (169) main: Signal x2
I (169) view: Data min[502] = -164.545135, Data max[205] = 3.857752
________________________________________________________________
0 |
1 |
2 |
3 | |
4 | |
5 | |
6 | |
7 || |
8 | | |
9|||||||||||||||||||||||| ||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (249) view: Plot: Length=512, min=-60.000000, max=40.000000
W (249) main: Signals x1 and x2 on one plot
I (259) view: Data min[505] = -159.215271, Data max[164] = 23.938747
________________________________________________________________
0 |
1 | |
2 | |
3 | | |
4 | | |
5 | | |
6 | | | |
7 | | || |
8 || || | | |
9|||||||||||||||||| | ||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (339) view: Plot: Length=512, min=-60.000000, max=40.000000
I (339) main: FFT for 1024 complex points take 140472 cycles
I (349) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_fft_main.c")

View File

@ -0,0 +1,106 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include <math.h>
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use FFT from esp-dsp library
#define N_SAMPLES 1024
int N = N_SAMPLES;
// Input test array
__attribute__((aligned(16)))
float x1[N_SAMPLES];
__attribute__((aligned(16)))
float x2[N_SAMPLES];
// Window coefficients
__attribute__((aligned(16)))
float wind[N_SAMPLES];
// working complex array
__attribute__((aligned(16)))
float y_cf[N_SAMPLES*2];
// Pointers to result arrays
float* y1_cf = &y_cf[0];
float* y2_cf = &y_cf[N_SAMPLES];
// Sum of y1 and y2
__attribute__((aligned(16)))
float sum_y[N_SAMPLES/2];
void app_main()
{
esp_err_t ret;
ESP_LOGI(TAG, "Start Example.");
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
// Generate hann window
dsps_wind_hann_f32(wind, N);
// Generate input signal for x1 A=1 , F=0.1
dsps_tone_gen_f32(x1, N, 1.0, 0.16, 0);
// Generate input signal for x2 A=0.1,F=0.2
dsps_tone_gen_f32(x2, N, 0.1, 0.2, 0);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = x1[i] * wind[i];
y_cf[i*2 + 1] = x2[i] * wind[i];
}
// FFT
unsigned int start_b = dsp_get_cpu_cycle_count();
dsps_fft2r_fc32(y_cf, N);
unsigned int end_b = dsp_get_cpu_cycle_count();
// Bit reverse
dsps_bit_rev_fc32(y_cf, N);
// Convert one complex vector to two complex vectors
dsps_cplx2reC_fc32(y_cf, N);
for (int i = 0 ; i < N/2 ; i++) {
y1_cf[i] = 10 * log10f((y1_cf[i * 2 + 0] * y1_cf[i * 2 + 0] + y1_cf[i * 2 + 1] * y1_cf[i * 2 + 1])/N);
y2_cf[i] = 10 * log10f((y2_cf[i * 2 + 0] * y2_cf[i * 2 + 0] + y2_cf[i * 2 + 1] * y2_cf[i * 2 + 1])/N);
// Simple way to show two power spectrums as one plot
sum_y[i] = fmax(y1_cf[i], y2_cf[i]);
}
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
ESP_LOGW(TAG, "Signal x1");
dsps_view(y1_cf, N/2, 64, 10, -60, 40, '|');
ESP_LOGW(TAG, "Signal x2");
dsps_view(y2_cf, N/2, 64, 10, -60, 40, '|');
ESP_LOGW(TAG, "Signals x1 and x2 on one plot");
dsps_view(sum_y, N/2, 64, 10, -60, 40, '|');
ESP_LOGI(TAG, "FFT for %i complex points take %i cycles", N, end_b - start_b);
ESP_LOGI(TAG, "End Example.");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(fft4real)

View File

@ -0,0 +1,91 @@
# FFT 4 Real Input Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use FFT functionality from esp-dsp library. Example does the following steps:
1. Initialize the library
2. Initialize input signals with 1024 samples: one 0 dB, second with -20 dB
3. Calculate FFT Radix-2 for 1024 complex samples
4. Calculate FFT Radix-4 for 1024 complex samples
5. Apply bit reverse operation for output complex vectors
6. Show results on the plots
7. Show execution time of FFTs
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```
I (344) main: Start Example.
W (424) main: Signal x1
I (424) view: Data min[673] = -103.113297, Data max[328] = 20.490950
________________________________________________________________
0 |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | | |
8 | | |
9||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (494) view: Plot: Length=1024, min=-60.000000, max=40.000000
W (504) main: Signal x2
I (504) view: Data min[582] = -103.113297, Data max[328] = 20.490950
________________________________________________________________
0 |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | | |
8 | | |
9||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (584) view: Plot: Length=1024, min=-60.000000, max=40.000000
W (593) main: Difference between signals x1 and x2 on one plot
I (594) view: Data min[0] = 0.000000, Data max[392] = 0.313019
________________________________________________________________
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8----------------------------------------------------------------|
9 |
0123456789012345678901234567890123456789012345678901234567890123
I (674) view: Plot: Length=1024, min=0.000000, max=40.000000
I (674) main: FFT Radix 2 for 1024 complex points take 168652 cycles
I (684) main: FFT Radix 4 for 1024 complex points take 104665 cycles
I (694) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_fft4real_main.c")

View File

@ -0,0 +1,118 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include <math.h>
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use FFT from esp-dsp library
#define N_SAMPLES 2048 // Amount of real input samples
int N = N_SAMPLES;
// Input test array
__attribute__((aligned(16)))
float x1[N_SAMPLES];
__attribute__((aligned(16)))
float x2[N_SAMPLES];
// Window coefficients
__attribute__((aligned(16)))
float wind[N_SAMPLES];
// Pointers to result arrays
float* y1_cf = &x1[0];
float* y2_cf = &x2[0];
// diff of y1 and y2
__attribute__((aligned(16)))
float diff_y[N_SAMPLES/2];
void app_main()
{
esp_err_t ret;
ESP_LOGI(TAG, "Start Example.");
ret = dsps_fft2r_init_fc32(NULL, N>>1);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT2R. Error = %i", ret);
return;
}
ret = dsps_fft4r_init_fc32(NULL, N >> 1);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT4R. Error = %i", ret);
return;
}
// Generate hann window
dsps_wind_hann_f32(wind, N);
// Generate input signal for x1 A=1 , F=0.1
dsps_tone_gen_f32(x1, N, 1.0, 0.16, 0);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
x1[i] = x1[i] * wind[i];
x2[i] = x1[i];
}
// FFT Radix-2
unsigned int start_r2 = dsp_get_cpu_cycle_count();
dsps_fft2r_fc32(x1, N>>1);
// Bit reverse
dsps_bit_rev2r_fc32(x1, N>>1);
// Convert one complex vector with length N/2 to one real spectrum vector with length N/2
dsps_cplx2real_fc32(x1, N>>1);
unsigned int end_r2 = dsp_get_cpu_cycle_count();
// FFT Radix-4
unsigned int start_r4 = dsp_get_cpu_cycle_count();
dsps_fft4r_fc32(x2, N>>1);
// Bit reverse
dsps_bit_rev4r_fc32(x2, N>>1);
// Convert one complex vector with length N/2 to one real spectrum vector with length N/2
dsps_cplx2real_fc32(x2, N>>1);
unsigned int end_r4 = dsp_get_cpu_cycle_count();
for (int i = 0 ; i < N/2 ; i++) {
x1[i] = 10 * log10f((x1[i * 2 + 0] * x1[i * 2 + 0] + x1[i * 2 + 1] * x1[i * 2 + 1] + 0.0000001)/N);
x2[i] = 10 * log10f((x2[i * 2 + 0] * x2[i * 2 + 0] + x2[i * 2 + 1] * x2[i * 2 + 1] + 0.0000001)/N);
// Simple way to show two power spectrums as one plot
diff_y[i] = fabs(x1[i] - x2[i]);
}
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
ESP_LOGW(TAG, "Signal x1");
dsps_view(x1, N/2, 64, 10, -60, 40, '|');
ESP_LOGW(TAG, "Signal x2");
dsps_view(x2, N/2, 64, 10, -60, 40, '|');
ESP_LOGW(TAG, "Difference between signals x1 and x2 on one plot");
dsps_view(diff_y, N/2, 64, 10, 0, 40, '-');
ESP_LOGI(TAG, "FFT Radix 2 for %i complex points take %i cycles", N/2, end_r2 - start_r2);
ESP_LOGI(TAG, "FFT Radix 4 for %i complex points take %i cycles", N/2, end_r4 - start_r4);
ESP_LOGI(TAG, "End Example.");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,9 @@
[mapping:dsp]
archive: libdsp.a
entries:
* (noflash)
[mapping:esp-dsp]
archive: libesp-dsp.a
entries:
* (noflash)

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(fft_window)

View File

@ -0,0 +1,134 @@
# FFT Window Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use Window and FFT functionality from esp-dsp library. Example does the following steps:
1. Initialize the library
2. Initialize input signals with 1024 samples
3. Apply window to input signal.
4. Calculate FFT for 1024 complex samples
5. Apply bit reverse operation for output complex vector
6. Split one complex FFT output spectrum to two real signal spectrums
7. Show results on the plots
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```
I (128) main: Start Example.
W (128) main: Hann Window
I (128) view: Data min[256] = -inf, Data max[1] = 24.086628
________________________________________________________________
0| |
1| |
2| |
3| |
4| |
5 | |
6 | |
7 ||||| |
8 ||||||||||||||| |
9 ||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (138) view: Plot: Length=512, min=-120.000000, max=40.000000
W (138) main: Blackman Window
I (148) view: Data min[355] = -165.295654, Data max[1] = 24.083012
________________________________________________________________
0| |
1| |
2| |
3| |
4| |
5| |
6 | |
7 ||| |
8 ||||||||| |
9 |||||||||||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (158) view: Plot: Length=512, min=-120.000000, max=40.000000
W (158) main: Blackman-Harris Window
I (168) view: Data min[128] = -inf, Data max[1] = 23.874702
________________________________________________________________
0| |
1| |
2| |
3| |
4| |
5| |
6| |
7|| |
8| |||| |
9 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (178) view: Plot: Length=512, min=-120.000000, max=40.000000
W (178) main: Blackman-Nuttall Window
I (188) view: Data min[128] = -inf, Data max[1] = 23.890663
________________________________________________________________
0| |
1| |
2| |
3| |
4| |
5| |
6| |
7 || |
8 |||| | |
9 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (198) view: Plot: Length=512, min=-120.000000, max=40.000000
W (198) main: Nuttall Window
I (208) view: Data min[203] = -175.147400, Data max[1] = 23.858671
________________________________________________________________
0| |
1| |
2| |
3| |
4| |
5| |
6| |
7|| |
8 ||| |
9 ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (218) view: Plot: Length=512, min=-120.000000, max=40.000000
W (218) main: Flat-Top Window
I (228) view: Data min[256] = -inf, Data max[1] = 22.490753
________________________________________________________________
0| |
1| |
2| |
3| |
4| |
5| |
6| |
7 || |
8 ||||| |
9 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0123456789012345678901234567890123456789012345678901234567890123
I (238) view: Plot: Length=512, min=-120.000000, max=40.000000
I (238) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_window_main.c")

View File

@ -0,0 +1,145 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include <math.h>
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use FFT from esp-dsp library
#define N_SAMPLES 1024
int N = N_SAMPLES;
// Input test array
__attribute__((aligned(16)))
float x1[N_SAMPLES];
// Window coefficients
__attribute__((aligned(16)))
float wind[N_SAMPLES];
// working complex array
__attribute__((aligned(16)))
float y_cf[N_SAMPLES*2];
// Pointers to result arrays
__attribute__((aligned(16)))
float* y1_cf = &y_cf[0];
void process_and_show(float* data, int length)
{
dsps_fft2r_fc32(data, length);
// Bit reverse
dsps_bit_rev_fc32(data, length);
// Convert one complex vector to two complex vectors
dsps_cplx2reC_fc32(data, length);
for (int i = 0 ; i < length/2 ; i++) {
data[i] = 10 * log10f((data[i * 2 + 0] * data[i * 2 + 0] + data[i * 2 + 1] * data[i * 2 + 1])/N);
}
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/4 samples
dsps_view(data, length/2, 64, 10, -120, 40, '|');
}
void app_main()
{
esp_err_t ret;
ESP_LOGI(TAG, "Start Example.");
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
ESP_LOGW(TAG, "Hann Window");
// Generate Hann window
dsps_wind_hann_f32(wind, N);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGW(TAG, "Blackman Window");
// Generate Blackman window
dsps_wind_blackman_f32(wind, N);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGW(TAG, "Blackman-Harris Window");
// Generate Blackman-Harris window
dsps_wind_blackman_harris_f32(wind, N);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGW(TAG, "Blackman-Nuttall Window");
// Generate Blackman-Nuttall window
dsps_wind_blackman_nuttall_f32(wind, N);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGW(TAG, "Nuttall Window");
// Generate Nuttall window
dsps_wind_nuttall_f32(wind, N);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGW(TAG, "Flat-Top Window");
// Generate Flat-Top window
dsps_wind_flat_top_f32(wind, N);
// Convert two input vectors to one complex vector
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = wind[i];
y_cf[i*2 + 1] = 0;
}
process_and_show(y_cf, N);
ESP_LOGI(TAG, "End Example.");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(fir)

View File

@ -0,0 +1,87 @@
# FIR Filter Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use FIR filter functionality from esp-dsp library. Example does the following steps:
1. Initialize the FFT library
2. Initialize input signal
* 1st Sine wave (f = 0.2Fs)
* 2nd Sine wave (f = 0.4Fs)
* Combine the waves
3. Show input signal
* Calculate windows coefficients
* Apply the windowing to the input signal
* Do the FFT
* Show the frequency response on a plot
* Calculate execution performance
4. Show filtered signal
* Initialize the FIR filter library
* Calculate Windowed-Sinc coefficients of FIR filter
* Apply the FIR filter to the input signal
* Do the FFT
* Show the frequency response on a plot
* Calculate execution performance
## How to use the example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is a typical example of console output.
```
I (340) main: Start Example.
I (400) view: Data min[388] = -108.419342, Data max[205] = 30.267143
________________________________________________________________
0 | | |
1 | || |
2 || || |
3 || || |
4 || || |
5 || ||| |
6 || || | | |
7|||||||||||||||||||||||| |||||||||||||||||||||| ||||||||||||
8 |
9 |
0123456789012345678901234567890123456789012345678901234567890123
I (470) view: Plot: Length=512, min=-120.000000, max=40.000000
I (490) view: Data min[254] = -114.853371, Data max[205] = 27.247583
________________________________________________________________
0 | |
1 | |
2 | |
3 | | |
4 | | |
5 | | |
6 | ||| ||| |
7||||||||||||||||||||||||||||||||||||||||||||||| | ||||| |
8 |||||
9 |
0123456789012345678901234567890123456789012345678901234567890123
I (560) view: Plot: Length=256, min=-120.000000, max=40.000000
I (560) main: FIR for 1024 samples and decimation 2 takes 763647 cycles
I (570) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_fir_main.c")

View File

@ -0,0 +1,167 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include <math.h>
#include <malloc.h>
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use FIR filters from esp-dsp library
#define FIR_COEFFS_LEN 64 // Number of FIR filter coefficients
#define DECIMATION 2 // Decimation ratio of the FIR filter
#define N_SAMPLES 1024 // Input samples
#define FIR_DELAY (FIR_COEFFS_LEN / DECIMATION) // Amount of samples not being considered for the FFT
#define FIR_BUFF_OUT_LEN (N_SAMPLES + FIR_DELAY) // Total length of samples
// Function shows the result of the FIR filter
void show_FFT(float *input_signal, const unsigned int fft_len){
dsps_fft2r_fc32(input_signal, fft_len>>1);
dsps_bit_rev2r_fc32(input_signal, fft_len>>1);
dsps_cplx2real_fc32(input_signal, fft_len>>1);
// Correction factor for the FFT spectrum
const float correction_factor = fft_len * 3;
// Calculating power of spectrum in dB
for (int i = 0 ; i < fft_len / 2 ; i++) {
input_signal[i] = 10 * log10f((input_signal[i * 2 + 0] * input_signal[i * 2 + 0] + input_signal[i * 2 + 1] * input_signal[i * 2 + 1] + 0.0000001)/correction_factor);
}
// Display power spectrum
dsps_view(input_signal, fft_len / 2, 64, 10, -120, 40, '|');
}
// Generate Windowed-Sinc filter coefficients
void generate_FIR_coefficients(float *fir_coeffs, const unsigned int fir_len, const float ft){
// Even or odd length of the FIR filter
const bool is_odd = (fir_len % 2) ? (true) : (false);
const float fir_order = (float)(fir_len - 1);
// Window coefficients
float *fir_window = (float*)malloc(fir_len * sizeof(float));
dsps_wind_blackman_f32(fir_window, fir_len);
for(int i = 0; i < fir_len; i++){
if((i == fir_order / 2) && (is_odd))
fir_coeffs[i] = 2 * ft;
else
fir_coeffs[i] = sinf((2 * M_PI * ft * (i - fir_order / 2))) / (M_PI * (i - fir_order / 2));
fir_coeffs[i] *= fir_window[i];
}
free(fir_window);
}
void app_main()
{
const int16_t fir_len = FIR_COEFFS_LEN;
const float fir_ft = 0.5 / DECIMATION; // Transition frequency of the FIR filter
const int32_t N = N_SAMPLES; // Number of input samples
const int16_t fir_decim = DECIMATION; // FIR filter decimation
const int32_t N_buff = FIR_BUFF_OUT_LEN; // Total length of samples with ignored
__attribute__((aligned(16))) float tone_combined[N_buff];
__attribute__((aligned(16))) float fir_coeffs[fir_len];
__attribute__((aligned(16))) float delay_line[fir_len];
fir_f32_t fir1;
esp_err_t ret;
// Ignoring the first set of samples, due to the delay line of the FIR filter
const int fir_out_offset = ((FIR_DELAY / 2) - 1);
ESP_LOGI(TAG, "Start Example.");
// If a user doesn't care about buffer allocation, the default
// initialization could be used as shown here:
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
ret = dsps_fft4r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
// Generate input signal as 2 sine waves
float *tone_1 = (float*)malloc(N_buff * sizeof(float));
float *tone_2 = (float*)malloc(N_buff * sizeof(float));
dsps_tone_gen_f32(tone_1, N_buff, 5, 0.2, 0);
dsps_tone_gen_f32(tone_2, N_buff, 5, 0.4, 0);
// Generate windowing coefficients
float *window = (float*)malloc(N * sizeof(float));
dsps_wind_blackman_harris_f32(window, N);
// Add the two waves together
for (int i = 0 ; i < N_buff ; i++){
tone_combined[i] = tone_1[i] + tone_2[i];
}
free(tone_1);
free(tone_2);
// Apply the windowing
for (int i = 0 ; i < N ; i++){
window[i] *= tone_combined[i];
}
// Show FFT spectrum
show_FFT(window, N);
// Calculate coefficients for the FIR filter
generate_FIR_coefficients(fir_coeffs, fir_len, fir_ft);
ESP_LOGI(TAG, "\n");
// Filter the input signal with FIR filter
float *fir_out = (float*)malloc( N_buff * sizeof(float));
dsps_fird_init_f32(&fir1, fir_coeffs, delay_line, fir_len, fir_decim, 0);
unsigned int start_b = dsp_get_cpu_cycle_count();
dsps_fird_f32_ansi(&fir1, tone_combined, fir_out, N_buff);
unsigned int end_b = dsp_get_cpu_cycle_count();
// Generate windowing coefficients and apply the windowing
dsps_wind_blackman_harris_f32(window, (N / fir_decim));
for (int i = 0 ; i < N / fir_decim ; i++){
window[i] *= fir_out[fir_out_offset + i];
}
// Show FFT spectrum, ignoring first samples from the delay line
show_FFT(window, N / fir_decim);
ESP_LOGI(TAG, "FIR for %"PRId32" samples and decimation %"PRId16" takes %"PRId16" cycles", N, fir_decim, (int16_t)(end_b - start_b));
ESP_LOGI(TAG, "End Example.");
free(fir_out);
free(window);
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(iir)

View File

@ -0,0 +1,107 @@
# IIR Filter Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use IIR filters functionality from esp-dsp library. Example does the following steps:
1. Initialize the library
2. Initialize input signal
3. Show LPF filter with Q factor 1
* Calculate iir filter coefficients
* Filter the input test signal (delta function)
* Shows impulse response on the plot
* Shows frequency response on the plot
* Calculate execution performance
4. The same for LPF filter with Q factor 10
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```
I (58) main: Start Example.
I (58) main: Impulse response of IIR filter with F=0.100000, qFactor=1.000000
I (68) view: Data min[8] = -0.060052, Data max[2] = 0.333517
________________________________________________________________
0 |
1 |
2 - |
3- - |
4 -------------------------------------------------------------|
5 |
6 |
7 |
8 |
9 |
0123456789012345678901234567890123456789012345678901234567890123
I (138) view: Plot: Length=128, min=-1.000000, max=1.000000
I (148) view: Data min[511] = -149.983795, Data max[0] = 0.000000
________________________________________________________________
0 |
1 |
2----------------- |
3 ---------- |
4 ------------- |
5 ---------- |
6 ------- |
7 --- |
8 -- |
9 --|
0123456789012345678901234567890123456789012345678901234567890123
I (228) view: Plot: Length=512, min=-100.000000, max=0.000000
I (228) main: IIR for 1024 samples take 20276 cycles
I (238) main: Impulse response of IIR filter with F=0.100000, qFactor=10.000000
I (248) view: Data min[7] = -0.453739, Data max[2] = 0.526114
________________________________________________________________
0 |
1 |
2 - - |
3- - - - --- --- - - |
4- - - - - ---- -------------------------------------|
5 -- -- -- -- |
6 |
7 |
8 |
9 |
0123456789012345678901234567890123456789012345678901234567890123
I (318) view: Plot: Length=128, min=-1.000000, max=1.000000
I (328) view: Data min[511] = -149.480377, Data max[0] = 0.000000
________________________________________________________________
0 -- |
1 -- - |
2---------- ----- |
3 -------- |
4 ------------ |
5 ---------- |
6 ------- |
7 --- |
8 -- |
9 --|
0123456789012345678901234567890123456789012345678901234567890123
I (408) view: Plot: Length=512, min=-100.000000, max=0.000000
I (408) main: IIR for 1024 samples take 17456 cycles
I (418) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dsps_iir_main.c")

View File

@ -0,0 +1,115 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "soc/uart_struct.h"
#include <math.h>
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use iir filters from esp-dsp library
#define N_SAMPLES 1024
int N = N_SAMPLES;
// Input test array
__attribute__((aligned(16)))
float d[N_SAMPLES];
// output array
__attribute__((aligned(16)))
float y[N_SAMPLES];
__attribute__((aligned(16)))
float y_cf[N_SAMPLES*2];
// Function shows result of IIR filter
void ShowIIRfilter(float freq, float qFactor)
{
esp_err_t ret = ESP_OK;
float coeffs_lpf[5];
float w_lpf[5] = {0,0};
// Calculate iir filter coefficients
ret = dsps_biquad_gen_lpf_f32(coeffs_lpf, freq, qFactor);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Operation error = %i", ret);
return;
}
// Process input signal
unsigned int start_b = dsp_get_cpu_cycle_count();
ret = dsps_biquad_f32(d, y, N, coeffs_lpf, w_lpf);
unsigned int end_b = dsp_get_cpu_cycle_count();
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Operation error = %i", ret);
return;
}
// Show result as a plot
ESP_LOGI(TAG, "Impulse response of IIR filter with F=%f, qFactor=%f", freq, qFactor);
dsps_view(y, 128, 64, 10, -1, 1, '-');
// Show result as frequency responce on the plot
for (int i=0 ; i< N ; i++)
{
y_cf[i*2 + 0] = y[i];
y_cf[i*2 + 1] = 0;
}
// We making FFT transform
dsps_fft2r_fc32_ansi(y_cf, N);
// Bit reverse
dsps_bit_rev_fc32_ansi(y_cf, N);
// Calculating power of spectrum in dB
for (int i = 0 ; i < N/2 ; i++) {
y_cf[i] = 10 * log10f((y_cf[i * 2 + 0] * y_cf[i * 2 + 0] + y_cf[i * 2 + 1] * y_cf[i * 2 + 1])/N);
}
// Show power spectrum in 64x10 window from -100 to 0 dB from 0..N/2 samples
dsps_view(y_cf, N/2, 64, 10, -100, 0, '-');
ESP_LOGI(TAG, "IIR for %i samples take %i cycles", N, end_b - start_b);
}
void app_main()
{
esp_err_t ret;
ESP_LOGI(TAG, "Start Example.");
// If user don't care about buffer allocation, the defalt
// initialization could be used as shown here:
ret = dsps_fft2r_init_fc32(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Not possible to initialize FFT. Error = %i", ret);
return;
}
// Initialize input signal
// Generate d function as input signal
dsps_d_gen_f32(d, N, 0);
// Show filter with Q factor 1
ShowIIRfilter(0.1, 1);
// Show filter with Q factor 10
ShowIIRfilter(0.1, 10);
ESP_LOGI(TAG, "End Example.");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ekf13states)

View File

@ -0,0 +1,149 @@
# Extended Kalman Filter
This example emulate system with IMU sensors and show how to use Extended Kalman Filter (EKF), with 13 values states vector,
to estimate gyroscope errors and calculate system attitude.
Also, this example show how to use esp-dsp library to operate with matrices and vectors.
In real system, the emulated sensors values should be replace by the real sensors values.
Then, in real system, a calibration phase should be implemented and after the calibration
phase the state vector X and covariance matrix P should be saved and restored next time, when
filter called. It will save time for initial phase.
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (380) spi_flash: detected chip: gd
I (383) spi_flash: flash io: dio
W (387) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (404) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (413) main: Start Example.
Gyro error: 0.1 0.2 0.3
Calibration phase started:
Loop 1000 from 48000, State data : 0.998361 0.0152476 0.0211183 0.0509682 0.00463435 0.00919946 0.01352 0.998156 0.00619182 -0.000683098 -0.00117112 0.0063196 -0.000952147
Loop 2000 from 48000, State data : 0.941757 0.0877462 0.170681 0.276156 0.016951 0.0334337 0.0498731 0.998804 0.0162317 -0.00225174 0.00389746 0.0110905 -0.000489083
Loop 3000 from 48000, State data : 0.372216 0.24247 0.488788 0.750832 0.0323164 0.0642265 0.0962768 0.997295 0.0269348 -0.00481966 0.00605674 0.00779719 0.00494921
Loop 4000 from 48000, State data : 0.944725 0.0951798 0.165878 0.266308 0.0470155 0.0946294 0.141251 0.998213 0.0337875 -0.00704064 0.00422252 0.0124181 0.00485692
Loop 5000 from 48000, State data : 0.944287 0.102183 0.168344 0.263706 0.0597481 0.12037 0.179946 0.997498 0.0378795 -0.00841348 0.0053515 0.0104612 0.00666854
Loop 6000 from 48000, State data : 0.379137 0.258284 0.476853 0.74977 0.0697741 0.140876 0.210702 0.995523 0.0410914 -0.00911293 0.00510267 0.00764586 0.00913832
Loop 7000 from 48000, State data : 0.947048 0.112494 0.165382 0.251187 0.0773002 0.156661 0.233985 0.996358 0.0425222 -0.00994576 0.00353348 0.00969652 0.00849919
Loop 8000 from 48000, State data : 0.945556 0.120624 0.169212 0.250481 0.082995 0.16838 0.251493 0.995914 0.0433827 -0.0102827 0.0039165 0.00846988 0.00913964
Loop 9000 from 48000, State data : 0.381034 0.276875 0.4647 0.749805 0.0871785 0.177046 0.264439 0.995073 0.0441243 -0.0103565 0.00391002 0.0071649 0.00997719
Loop 10000 from 48000, State data : 0.946592 0.132375 0.168307 0.241068 0.0902326 0.183443 0.273873 0.995445 0.0443655 -0.0106197 0.00326065 0.00799655 0.00960479
Loop 11000 from 48000, State data : 0.944297 0.140946 0.172816 0.242015 0.0924658 0.188118 0.280807 0.995187 0.0445766 -0.0106806 0.00346742 0.00749049 0.00979064
Loop 12000 from 48000, State data : 0.378334 0.295555 0.452859 0.751285 0.0941005 0.191525 0.285886 0.994796 0.0447763 -0.0106511 0.0034986 0.00695604 0.0100697
Loop 13000 from 48000, State data : 0.944329 0.1532 0.172826 0.234315 0.0953075 0.194011 0.289567 0.994899 0.0448155 -0.0107384 0.00323858 0.00728781 0.00989103
Loop 14000 from 48000, State data : 0.941572 0.16194 0.177533 0.236008 0.0961574 0.195842 0.292257 0.994735 0.0448801 -0.0107422 0.00334282 0.0070798 0.00993131
Loop 15000 from 48000, State data : 0.373427 0.314041 0.441061 0.753256 0.0967899 0.197167 0.294234 0.994523 0.0449438 -0.0107112 0.00335898 0.00685221 0.0100213
Loop 16000 from 48000, State data : 0.941028 0.174338 0.177916 0.228952 0.0972752 0.198121 0.295664 0.994518 0.0449512 -0.0107403 0.0032445 0.00697761 0.00993463
Loop 17000 from 48000, State data : 0.937959 0.183145 0.18262 0.230959 0.0975883 0.198844 0.296697 0.994396 0.0449757 -0.0107339 0.0032963 0.00688409 0.00992845
Loop 18000 from 48000, State data : 0.3675 0.33233 0.429142 0.755207 0.0978324 0.199358 0.297465 0.994256 0.0450002 -0.0107104 0.00330113 0.00677742 0.00995297
Loop 19000 from 48000, State data : 0.937014 0.195546 0.183166 0.224089 0.0980371 0.199716 0.298023 0.994211 0.0450036 -0.0107164 0.00324275 0.00681997 0.00990755
Loop 20000 from 48000, State data : 0.933698 0.204372 0.187784 0.226223 0.0981422 0.200008 0.29842 0.994114 0.0450155 -0.0107065 0.00327025 0.00677405 0.00988484
Loop 21000 from 48000, State data : 0.361055 0.350426 0.417036 0.756916 0.0982358 0.200208 0.29872 0.99401 0.0450272 -0.0106858 0.00326787 0.00671759 0.0098834
Loop 22000 from 48000, State data : 0.932425 0.216717 0.188413 0.219358 0.0983318 0.200334 0.298938 0.993947 0.0450303 -0.0106798 0.00323017 0.00672916 0.00985372
Loop 23000 from 48000, State data : 0.928888 0.225543 0.19291 0.221546 0.0983561 0.200458 0.299082 0.993866 0.0450371 -0.0106664 0.00324701 0.00670354 0.00982584
Loop 24000 from 48000, State data : 0.354297 0.36833 0.404722 0.758292 0.0983915 0.200535 0.299203 0.993773 0.045044 -0.0106443 0.00324109 0.00666712 0.00981608
Loop 25000 from 48000, State data : 0.927316 0.237803 0.19359 0.214612 0.0984453 0.200572 0.299291 0.993709 0.0450468 -0.0106303 0.00321085 0.00666748 0.00979369
Loop 26000 from 48000, State data : 0.92357 0.246618 0.197954 0.216824 0.0984385 0.200632 0.299342 0.993629 0.0450514 -0.0106123 0.00322403 0.00665109 0.00976504
Loop 27000 from 48000, State data : 0.347305 0.386034 0.392194 0.759303 0.0984521 0.200663 0.299393 0.993546 0.0450564 -0.0105864 0.00321847 0.00662376 0.00975319
Loop 28000 from 48000, State data : 0.92171 0.258777 0.198672 0.209796 0.0984898 0.200666 0.299433 0.993475 0.045059 -0.0105663 0.00319366 0.00662077 0.00973562
Loop 29000 from 48000, State data : 0.917761 0.267574 0.202895 0.212019 0.0984714 0.2007 0.299446 0.9934 0.0450631 -0.0105437 0.00320563 0.0066091 0.00970881
Loop 30000 from 48000, State data : 0.340113 0.403531 0.379459 0.759933 0.0984762 0.200711 0.299466 0.993322 0.0450673 -0.0105132 0.00320031 0.00658594 0.00969804
Loop 31000 from 48000, State data : 0.915619 0.279623 0.203648 0.204891 0.0985076 0.2007 0.299484 0.993253 0.0450696 -0.0104878 0.00317637 0.00658294 0.00968329
Loop 32000 from 48000, State data : 0.91147 0.288396 0.207727 0.207121 0.0984838 0.200725 0.299481 0.99318 0.0450732 -0.0104599 0.00318786 0.00657435 0.00965871
Loop 33000 from 48000, State data : 0.332734 0.420812 0.366519 0.760177 0.0984844 0.20073 0.299492 0.993105 0.045077 -0.0104242 0.00318322 0.00655352 0.00964965
Loop 34000 from 48000, State data : 0.909049 0.300327 0.208511 0.199891 0.0985129 0.200714 0.299506 0.993034 0.0450794 -0.0103941 0.0031609 0.00655179 0.00963774
Loop 35000 from 48000, State data : 0.904704 0.309072 0.212442 0.202124 0.0984875 0.200736 0.299498 0.992959 0.0450829 -0.0103612 0.0031732 0.00654506 0.00961709
Loop 36000 from 48000, State data : 0.325179 0.437867 0.353384 0.760034 0.098487 0.200738 0.299504 0.992885 0.0450865 -0.0103208 0.00317079 0.00652607 0.00961171
Loop 37000 from 48000, State data : 0.325177 0.437848 0.353377 0.760049 0.0989011 0.200534 0.299617 0.992838 0.0450912 -0.0103039 0.00319877 0.00652725 0.00959415
Loop 38000 from 48000, State data : 0.325194 0.437821 0.353363 0.760064 0.099202 0.200388 0.299726 0.992838 0.0450926 -0.0102998 0.00320422 0.00652895 0.00959084
Loop 39000 from 48000, State data : 0.325211 0.437798 0.353354 0.760074 0.0994169 0.200278 0.299826 0.992816 0.045093 -0.0102979 0.00320263 0.0065278 0.00959847
Loop 40000 from 48000, State data : 0.325222 0.437784 0.353346 0.760081 0.0995754 0.200199 0.299886 0.992816 0.0450925 -0.0102967 0.00320118 0.00652683 0.00960376
Loop 41000 from 48000, State data : 0.325231 0.437773 0.353342 0.760085 0.0996929 0.200142 0.299945 0.992816 0.0450925 -0.0102966 0.00320043 0.00652627 0.00960631
Loop 42000 from 48000, State data : 0.325238 0.437769 0.353336 0.760087 0.0997802 0.200119 0.299978 0.992816 0.0450913 -0.0102965 0.00320007 0.0065261 0.00960773
Loop 43000 from 48000, State data : 0.32524 0.437762 0.353331 0.760093 0.099842 0.200089 0.299979 0.992816 0.0450913 -0.0102961 0.00320001 0.00652608 0.00960857
Loop 44000 from 48000, State data : 0.325241 0.43776 0.353327 0.760095 0.099883 0.200059 0.299979 0.992816 0.045089 -0.0102953 0.00319975 0.00652622 0.00960868
Loop 45000 from 48000, State data : 0.325243 0.437759 0.353325 0.760096 0.0999138 0.200045 0.299979 0.992816 0.0450878 -0.0102956 0.0031996 0.00652593 0.00960985
Loop 46000 from 48000, State data : 0.325245 0.437756 0.353324 0.760097 0.0999355 0.200042 0.299979 0.992816 0.0450878 -0.0102959 0.00319972 0.0065261 0.00960944
Loop 47000 from 48000, State data : 0.325246 0.437757 0.353322 0.760098 0.0999504 0.200039 0.299979 0.992816 0.0450878 -0.0102959 0.00319952 0.00652634 0.00960984
Calibration phase finished.
Regular calculation started:
Loop 1000 from 48000, State data : 0.9996 6.68374e-06 -7.71055e-05 0.028269 0.0999599 0.199742 0.298758 0.992397 0.0506049 -0.00981295 0.00516875 0.00517689 0.0102406
Loop 2000 from 48000, State data : 0.95186 0.0747648 0.154942 0.253704 0.0997667 0.199899 0.298983 0.992397 0.0504132 -0.0098162 0.00510809 0.00522702 0.0102249
Loop 3000 from 48000, State data : 0.395338 0.237819 0.486861 0.741698 0.0994409 0.200091 0.299095 0.992397 0.0502891 -0.00981838 0.00506923 0.00525921 0.0102147
Loop 4000 from 48000, State data : 0.952465 0.0877289 0.155254 0.247002 0.0992076 0.200299 0.299271 0.992397 0.0502054 -0.00981973 0.00504271 0.00528111 0.0102076
Loop 5000 from 48000, State data : 0.950016 0.096521 0.160702 0.249654 0.0990023 0.200426 0.299306 0.992397 0.05013 -0.00982108 0.00501929 0.00530046 0.0102013
Loop 6000 from 48000, State data : 0.389808 0.256786 0.476033 0.745321 0.0988748 0.200476 0.299331 0.992397 0.050078 -0.00982208 0.0050032 0.00531378 0.0101971
Loop 7000 from 48000, State data : 0.950306 0.109383 0.161046 0.242937 0.0987883 0.200581 0.299444 0.992397 0.0500379 -0.00982289 0.0049906 0.00532416 0.0101938
Loop 8000 from 48000, State data : 0.947646 0.118155 0.166392 0.2456 0.0986931 0.200633 0.299434 0.992397 0.0499987 -0.00982366 0.00497852 0.00533416 0.0101903
Loop 9000 from 48000, State data : 0.383995 0.275557 0.464951 0.748623 0.0986473 0.200627 0.299425 0.992397 0.0499702 -0.00982415 0.00496994 0.00534126 0.0101879
Loop 10000 from 48000, State data : 0.94764 0.130939 0.166769 0.238794 0.0986203 0.200694 0.299509 0.992397 0.0499475 -0.00982454 0.004963 0.00534698 0.0101861
Loop 11000 from 48000, State data : 0.944771 0.139703 0.171999 0.241471 0.0985699 0.200714 0.299481 0.992397 0.0499252 -0.00982467 0.00495605 0.00535274 0.0101844
Loop 12000 from 48000, State data : 0.377949 0.294161 0.453622 0.751566 0.0985571 0.200685 0.299459 0.992397 0.0499092 -0.00982467 0.00495124 0.0053567 0.0101832
Loop 13000 from 48000, State data : 0.944475 0.152413 0.172408 0.234549 0.0985539 0.200736 0.299532 0.992397 0.0498962 -0.00982467 0.00494735 0.0053599 0.0101823
Loop 14000 from 48000, State data : 0.941398 0.16117 0.177516 0.237239 0.0985215 0.200743 0.299498 0.992397 0.0498826 -0.00982467 0.0049434 0.00536316 0.0101813
Loop 15000 from 48000, State data : 0.371694 0.312599 0.442052 0.754132 0.0985222 0.200704 0.299474 0.992397 0.049874 -0.00982467 0.00494084 0.0053653 0.0101808
Loop 16000 from 48000, State data : 0.940819 0.173801 0.177954 0.230187 0.0985277 0.20075 0.299544 0.992397 0.0498671 -0.00982467 0.00493887 0.00536698 0.0101804
Loop 17000 from 48000, State data : 0.937532 0.182552 0.182939 0.232897 0.0985023 0.200752 0.299507 0.992397 0.0498602 -0.00982467 0.0049367 0.0053688 0.0101799
Loop 18000 from 48000, State data : 0.365235 0.33087 0.43025 0.756316 0.0985084 0.200708 0.299482 0.992397 0.0498562 -0.00982467 0.00493555 0.0053698 0.0101796
Loop 19000 from 48000, State data : 0.936669 0.195102 0.183407 0.225717 0.0985175 0.200754 0.299549 0.992397 0.0498532 -0.00982467 0.00493474 0.00537051 0.0101794
Loop 20000 from 48000, State data : 0.933178 0.203841 0.188264 0.22844 0.0984953 0.200754 0.299511 0.992397 0.0498502 -0.00982467 0.00493366 0.00537141 0.010179
Loop 21000 from 48000, State data : 0.35858 0.348967 0.41822 0.758113 0.0985034 0.200709 0.299484 0.992397 0.0498495 -0.00982467 0.00493334 0.00537172 0.0101788
Loop 22000 from 48000, State data : 0.93203 0.216304 0.188763 0.221136 0.0985129 0.200755 0.299549 0.992397 0.0498497 -0.00982467 0.00493327 0.00537182 0.0101787
Loop 23000 from 48000, State data : 0.928336 0.225027 0.193488 0.22387 0.0984918 0.200754 0.29951 0.992397 0.0498497 -0.00982467 0.00493298 0.00537209 0.0101787
Loop 24000 from 48000, State data : 0.351735 0.366882 0.405969 0.759519 0.0985006 0.200707 0.299482 0.992397 0.0498508 -0.00982467 0.00493324 0.00537189 0.0101787
Loop 25000 from 48000, State data : 0.926905 0.237397 0.194017 0.216443 0.0985107 0.200755 0.299545 0.992397 0.0498526 -0.00982467 0.00493366 0.00537159 0.0101787
Loop 26000 from 48000, State data : 0.92301 0.246099 0.198608 0.219185 0.0984902 0.200753 0.299511 0.992397 0.0498537 -0.00982467 0.00493391 0.00537146 0.0101787
Loop 27000 from 48000, State data : 0.344708 0.384605 0.393502 0.760534 0.0984992 0.200706 0.299488 0.992397 0.0498556 -0.00982467 0.00493459 0.00537092 0.0101787
Loop 28000 from 48000, State data : 0.921297 0.258369 0.199166 0.211636 0.0985091 0.200757 0.299555 0.992397 0.0498579 -0.00982467 0.00493535 0.00537033 0.0101787
Loop 29000 from 48000, State data : 0.917204 0.267048 0.203621 0.214385 0.0984891 0.200754 0.29952 0.992397 0.0498601 -0.00982467 0.00493597 0.0053698 0.0101787
Loop 30000 from 48000, State data : 0.337501 0.402129 0.380825 0.761156 0.0984981 0.200706 0.299491 0.992397 0.0498626 -0.00982467 0.00493691 0.00536903 0.0101787
Loop 31000 from 48000, State data : 0.915208 0.279212 0.204208 0.206723 0.0985072 0.200758 0.299553 0.992397 0.0498654 -0.00982467 0.00493789 0.00536824 0.0101787
Loop 32000 from 48000, State data : 0.910918 0.287861 0.208526 0.209479 0.0984873 0.200754 0.299515 0.992397 0.0498676 -0.00982467 0.00493879 0.00536752 0.0101787
Loop 33000 from 48000, State data : 0.330116 0.419445 0.367945 0.761385 0.0984966 0.200704 0.299489 0.992397 0.0498701 -0.00982467 0.00493986 0.00536667 0.0101787
Loop 34000 from 48000, State data : 0.908641 0.299912 0.209141 0.201703 0.0985056 0.200757 0.299551 0.992397 0.0498728 -0.00982467 0.00494093 0.00536582 0.0101787
Loop 35000 from 48000, State data : 0.904158 0.308528 0.213318 0.204462 0.0984862 0.200752 0.299518 0.992397 0.0498751 -0.00982467 0.00494188 0.00536507 0.0101787
Loop 36000 from 48000, State data : 0.322561 0.436541 0.354869 0.761219 0.0984953 0.200702 0.299495 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 37000 from 48000, State data : 0.322549 0.436508 0.354868 0.761243 0.0989076 0.200506 0.299634 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 38000 from 48000, State data : 0.322568 0.436485 0.354851 0.761257 0.099208 0.200371 0.299726 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 39000 from 48000, State data : 0.322581 0.436466 0.354841 0.761267 0.0994207 0.200267 0.299799 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 40000 from 48000, State data : 0.322592 0.436454 0.354831 0.761274 0.099581 0.200208 0.299849 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 41000 from 48000, State data : 0.322601 0.436443 0.354826 0.761278 0.099701 0.20015 0.299901 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 42000 from 48000, State data : 0.322606 0.436435 0.35482 0.761283 0.0997844 0.200101 0.299931 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 43000 from 48000, State data : 0.322611 0.436429 0.35482 0.761285 0.0998457 0.200072 0.299961 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 44000 from 48000, State data : 0.322615 0.436425 0.354818 0.761286 0.0998883 0.200057 0.29999 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 45000 from 48000, State data : 0.322617 0.436423 0.354816 0.761287 0.099912 0.200042 0.300002 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 46000 from 48000, State data : 0.322617 0.436421 0.354815 0.761289 0.0999343 0.20003 0.300002 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Loop 47000 from 48000, State data : 0.322618 0.436421 0.354814 0.761289 0.0999444 0.20003 0.300002 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Final State data : 0.322618 0.436421 0.354814 0.761289 0.0999518 0.20003 0.300002 0.992397 0.0498778 -0.00982467 0.00494296 0.00536423 0.0101787
Estimated error : 0.0999518 0.20003 0.300002
Difference between real and estimated errors : 4.81904e-05 -2.99811e-05 -2.17557e-06
Expected Euler angels (degree) : -29.8215 64.9692 150.241
Calculated Euler angels (degree) : -35.1525 63.3067 156.167
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "ekf_imu13states_main.cpp")

View File

@ -0,0 +1,196 @@
// Copyright 2020-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dsp_platform.h"
#include "esp_log.h"
#include "esp_dsp.h"
#include "ekf_imu13states.h"
static const char *TAG = "main";
extern "C" void app_main();
// This example reproduce system with gyroscope, accelerometer, and magnetometer
// True gyroscope values will be transformed and applied to the rotation and reference measurements.
void app_main()
{
ekf_imu13states *ekf13 = new ekf_imu13states();
ekf13->Init();
ESP_LOGI(TAG, "Start Example.");
// Set up some initial values to emulate and calculate system values
int total_N = 3000;
// Pi value
float pi = std::atan(1) * 4;
// gyroscope bias error
float gyro_err_data[] = {0.1, 0.2, 0.3}; // static constatnt error
dspm::Mat gyro_err(gyro_err_data, 3, 1);
// Measurement noise covariance values for diagonal covariance matrix.
// For the real system these values could be adjusted!
// These calues depends on how noisy the measurement.
//
float R[10];
for (size_t i = 0; i < 10; i++) {
R[i] = 0.01;
}
// Reference vectors
float accel0_data[] = {0, 0, 1};
// In real system magnetometer vector will have different value and direction
// The EKF will calculate them. This value is used as initial state.
float magn0_data[] = {1, 0, 0};
dspm::Mat accel0(accel0_data, 3, 1);
dspm::Mat magn0(magn0_data, 3, 1);
float dt = 0.01;
dspm::Mat gyro_data(3, 1);
int count = 0;
// Initial rotation matrix
dspm::Mat Rm = dspm::Mat::eye(3);
dspm::Mat Re = dspm::Mat::eye(3);
gyro_err *= 1;
std::cout << "Gyro error: " << gyro_err.t() << std::endl;
std::cout << "Calibration phase started: " << std::endl;
for (size_t n = 1; n < total_N * 16; n++) {
if ((n % 1000) == 0) {
std::cout << "Loop " << n << " from " << total_N * 16;
std::cout << ", State data : " << ekf13->X.t();
}
//
// This part of the loop related to the system emulation
//
// Generate gyro values for system emulation
gyro_data *= 0; // reset gyro value
if ((n >= (total_N / 2)) && (n < total_N * 12)) {
gyro_data(0, 0) = 1 / pi * std::cos(-pi / 2 + pi / 2 * count * 2 / (total_N / 10));
gyro_data(1, 0) = 2 / pi * std::cos(-pi / 2 + pi / 2 * count * 2 / (total_N / 10));
gyro_data(2, 0) = 3 / pi * std::cos(-pi / 2 + pi / 2 * count * 2 / (total_N / 10));
count++;
}
dspm::Mat gyro_sample = gyro_data + gyro_err;
gyro_data *= dt;
// Calculate rotation for the last time interval
Re = ekf::eul2rotm(gyro_data.data);
// Ally rotation to the system rotation matrix
Rm = Rm * Re;
// Convert rotation matrix to the system attitude quaternion
dspm::Mat attitude = ekf::rotm2quat(Rm);
// We have to rotate accel and magn to the opposite direction
dspm::Mat accel_data = Rm.t() * accel0;
dspm::Mat magn_data = Rm.t() * magn0;
dspm::Mat accel_norm = accel_data / accel_data.norm();
dspm::Mat magn_norm = magn_data / magn_data.norm();
//
// This part of the loop related to the real system
// Here gyro_sample values must be replaced by measured gyroscope values
// and accel_norm and magn_norm should be real measured accel and magn values
// The dt in this case should be real time difference in seconds between samples
// Fill the input control values with measured gyro values
float input_u[] = {gyro_sample(0, 0), gyro_sample(1, 0), gyro_sample(2, 0)};
// Process input values to new state
ekf13->Process(input_u, dt);
dspm::Mat q_norm(ekf13->X.data, 4, 1);
q_norm /= q_norm.norm();
// Correct state and calculate gyro and magnetometer values.
// Here accel_norm and magn_norm should be real measured accel and magn values
ekf13->UpdateRefMeasurementMagn(accel_norm.data, magn_norm.data, R);
}
std::cout << "Calibration phase finished." << std::endl << std::endl;
std::cout << "Regular calculation started:" << std::endl;
// Reset rotation nmatrix
Rm = dspm::Mat::eye(3);
Re = dspm::Mat::eye(3);
count = 0;
// Set initial state
ekf13->X(0,0) = 1;
ekf13->X(0,1) = 0;
ekf13->X(0,2) = 0;
ekf13->X(0,3) = 0;
for (size_t n = 1; n < total_N * 16; n++) {
if ((n % 1000) == 0) {
std::cout << "Loop " << n << " from " << total_N * 16;
std::cout << ", State data : " << ekf13->X.t();
}
//
// This part of the loop related to the system emulation
//
// Generate gyro values for system emulation
gyro_data *= 0; // reset gyro value
if ((n >= (total_N / 2)) && (n < total_N * 12)) {
gyro_data(0, 0) = 1 / pi * std::cos(-pi / 2 + pi / 2 * count * 2 / (total_N / 10));
gyro_data(1, 0) = 2 / pi * std::cos(-pi / 2 + pi / 2 * count * 2 / (total_N / 10));
gyro_data(2, 0) = 3 / pi * std::cos(-pi / 2 + pi / 2 * count * 2 / (total_N / 10));
count++;
}
dspm::Mat gyro_sample = gyro_data + gyro_err;
gyro_data *= dt;
// Calculate rotation for the last time interval
Re = ekf::eul2rotm(gyro_data.data);
// Ally rotation to the system rotation matrix
Rm = Rm * Re;
// Convert rotation matrix to the system attitude quaternion
dspm::Mat attitude = ekf::rotm2quat(Rm);
// We have to rotate accel and magn to the opposite direction
dspm::Mat accel_data = Rm.t() * accel0;
dspm::Mat magn_data = Rm.t() * magn0;
dspm::Mat accel_norm = accel_data / accel_data.norm();
dspm::Mat magn_norm = magn_data / magn_data.norm();
//
// This part of the loop related to the real system
// Here gyro_sample values must be replaced by measured gyroscope values
// and accel_norm and magn_norm should be real measured accel and magn values
// The dt in this case should be real time difference in seconds between samples
// Fill the input control values with measured gyro values
float input_u[] = {gyro_sample(0, 0), gyro_sample(1, 0), gyro_sample(2, 0)};
// Process input values to new state
ekf13->Process(input_u, dt);
dspm::Mat q_norm(ekf13->X.data, 4, 1);
q_norm /= q_norm.norm();
// Correct state and calculate gyro and magnetometer values.
// Here accel_norm and magn_norm should be real measured accel and magn values
ekf13->UpdateRefMeasurement(accel_norm.data, magn_norm.data, R);
}
std::cout << "Final State data : " << ekf13->X.t();
dspm::Mat estimated_error(&ekf13->X.data[4], 3, 1);
std::cout << "Estimated error : " << estimated_error.t();
std::cout << "Difference between real and estimated errors : " << (gyro_err - estimated_error).t() << std::endl;
std::cout << "Expected Euler angels (degree) : " << (180/pi*ekf::quat2eul(ekf::rotm2quat(Rm).data)).t();
std::cout << "Calculated Euler angels (degree) : " << (180/pi*ekf::quat2eul(ekf13->X.data)).t() << std::endl;
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,21 @@
#
# DSP Library
#
# CONFIG_DSP_ANSI is not set
CONFIG_DSP_OPTIMIZED=y
# CONFIG_DSP_MAX_FFT_SIZE_512 is not set
# CONFIG_DSP_MAX_FFT_SIZE_1024 is not set
# CONFIG_DSP_MAX_FFT_SIZE_2048 is not set
CONFIG_DSP_MAX_FFT_SIZE_4096=y
# CONFIG_DSP_MAX_FFT_SIZE_8192 is not set
# CONFIG_DSP_MAX_FFT_SIZE_16384 is not set
# CONFIG_DSP_MAX_FFT_SIZE_32768 is not set
CONFIG_DSP_MAX_FFT_SIZE=4096
# end of DSP Library
#
# ESP System Settings
#
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT=n
# end of ESP System Settings

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(matrix)

View File

@ -0,0 +1,54 @@
# Matrix Operations Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use Mat class functionality from esp-dsp library. Example does the following steps:
1. Initialize a matrix A and matirx x
2. Calculate matrix b: b = A*x
3. Find roots x1_: A*x1_ = b, with different methods
4. Print result
## How to use example
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is an typical example console output.
```
I (215) main: Start Example.
I (215) main: Original vector x:
0
1
2
I (215) main: Solve result:
0
1
2
I (215) main: Roots result:
0
1
2
I (215) main: End Example.
```

View File

@ -0,0 +1 @@
idf_component_register(SRCS "dspm_matrix_main.cpp")

View File

@ -0,0 +1,62 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dsp_platform.h"
#include "esp_log.h"
#include "esp_dsp.h"
static const char *TAG = "main";
// This example shows how to use Mat class from esp-dsp library.
//
// First we create matix A and x, and then calculating matrix b as result
// A*x = b
// Then we can find x as roots of matrices X and b
//
extern "C" void app_main();
void app_main()
{
ESP_LOGI(TAG, "Start Example.");
int M = 3;
int N = 3;
dspm::Mat A(M, N);
dspm::Mat x(N, 1);
for (int m = 0 ; m < M ; m++) {
for (int n = 0 ; n < N ; n++) {
A(m, n) = N * m + n;
}
x(m, 0) = m;
}
A(0, 0) = 10;
A(0, 1) = 11;
dspm::Mat b = A * x;
// Gaussian method
dspm::Mat x1_ = dspm::Mat::solve(A, b);
// Non Gaussian method
dspm::Mat x2_ = dspm::Mat::roots(A, b);
ESP_LOGI(TAG, "Original vector x:");
std::cout << x;
ESP_LOGI(TAG, "Solve result:");
std::cout << x1_;
ESP_LOGI(TAG, "Roots result:");
std::cout << x2_;
ESP_LOGI(TAG, "End Example.");
}

View File

@ -0,0 +1,4 @@
dependencies:
espressif/esp-dsp:
override_path: "../../../"
version: "*"

View File

@ -0,0 +1,9 @@
dependencies:
idf:
version: '>=4.2'
description: ESP-DSP is the official DSP library for Espressif SoCs.
documentation: https://docs.espressif.com/projects/esp-dsp/en/latest/index.html
issues: https://github.com/espressif/esp-dsp/issues
repository: https://github.com/espressif/esp-dsp.git
url: https://github.com/espressif/esp-dsp
version: 1.4.4

View File

@ -0,0 +1,83 @@
// Copyright 2018-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _dsp_common_H_
#define _dsp_common_H_
#include <stdint.h>
#include <stdbool.h>
#include "dsp_err.h"
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
#include "esp_cpu.h"
#else
#include "soc/cpu.h"
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief check power of two
* The function check if the argument is power of 2.
* The implementation use ANSI C and could be compiled and run on any platform
*
* @return
* - true if x is power of two
* - false if no
*/
bool dsp_is_power_of_two(int x);
/**
* @brief Power of two
* The function return power of 2 for values 2^N.
* The implementation use ANSI C and could be compiled and run on any platform
*
* @return
* - power of two
*/
int dsp_power_of_two(int x);
/**
* @brief Logginng for esp32s3 TIE core
* Registers covered q0 to q7, ACCX and SAR_BYTE
*
* @param n_regs: number of registers to be logged at once
* @param ...: register codes 0, 1, 2, 3, 4, 5, 6, 7, 'a', 's'
*
* @return ESP_OK
*
*/
esp_err_t tie_log(int n_regs, ...);
#ifdef __cplusplus
}
#endif
// esp_cpu_get_ccount function is implemented in IDF 4.1 and later
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#define dsp_get_cpu_cycle_count esp_cpu_get_cycle_count
#else
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0)
#define dsp_get_cpu_cycle_count esp_cpu_get_ccount
#else
#define dsp_get_cpu_cycle_count xthal_get_ccount
#endif
#endif // ESP_IDF_VERSION
#endif // _dsp_common_H_

View File

@ -0,0 +1,23 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DSP_ERR_H_
#define _DSP_ERR_H_
#include "stdint.h"
#include "esp_err.h"
#include "dsp_err_codes.h"
#endif // _DSP_ERR_H_

View File

@ -0,0 +1,28 @@
// Copyright 2018-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _dsp_error_codes_H_
#define _dsp_error_codes_H_
#define DSP_OK 0 // For internal use only. Please use ESP_OK instead
#define ESP_ERR_DSP_BASE 0x70000
#define ESP_ERR_DSP_INVALID_LENGTH (ESP_ERR_DSP_BASE + 1)
#define ESP_ERR_DSP_INVALID_PARAM (ESP_ERR_DSP_BASE + 2)
#define ESP_ERR_DSP_PARAM_OUTOFRANGE (ESP_ERR_DSP_BASE + 3)
#define ESP_ERR_DSP_UNINITIALIZED (ESP_ERR_DSP_BASE + 4)
#define ESP_ERR_DSP_REINITIALIZED (ESP_ERR_DSP_BASE + 5)
#define ESP_ERR_DSP_ARRAY_NOT_ALIGNED (ESP_ERR_DSP_BASE + 6)
#endif // _dsp_error_codes_H_

View File

@ -0,0 +1,30 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef dsp_platform_h_
#define dsp_platform_h_
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
#include "esp_cpu.h"
#else
#include "soc/cpu.h"
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/portable.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#endif // dsp_platform_h_

View File

@ -0,0 +1,37 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DSP_TESTS_H_
#define _DSP_TESTS_H_
#include <stdlib.h>
#include "esp_idf_version.h"
#define TEST_ASSERT_EXEC_IN_RANGE(min_exec, max_exec, actual) \
if (actual >= max_exec) { \
ESP_LOGE("", "Time error. Expected max: %i, reached: %i", (int)max_exec, (int)actual);\
TEST_ASSERT_MESSAGE (false, "Exec time takes more than expected! ");\
}\
if (actual < min_exec) {\
ESP_LOGE("", "Time error. Expected min: %i, reached: %i", (int)min_exec, (int)actual);\
TEST_ASSERT_MESSAGE (false, "Exec time takes less then expected!");\
}
// memalign function is implemented in IDF 4.3 and later
#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 3, 0)
#define memalign(align_, size_) malloc(size_)
#endif
#endif // _DSP_TESTS_H_

View File

@ -0,0 +1,40 @@
#ifndef _dsp_types_H_
#define _dsp_types_H_
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
// union to simplify access to the 16 bit data
typedef union sc16_u
{
struct
{
int16_t re;
int16_t im;
};
uint32_t data;
}sc16_t;
typedef union fc32_u
{
struct
{
float re;
float im;
};
uint64_t data;
}fc32_t;
typedef struct image2d_s
{
void* data; // could be int8_t, unt8_t, int16_t, unt16_t, float
int step_x; // step of elements by X
int step_y; // step of elements by Y, usually is 1
int stride_x; // stride width: size of the elements in X axis * by step_x + padding
int stride_y; // stride height: size of the elements in Y axis * by step_y + padding
// Point[x,y] = data[width*y*step_y + x*step_x];
// Full data size = width*height
} image2d_t;
#endif // _dsp_types_H_

View File

@ -0,0 +1,65 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _esp_dsp_H_
#define _esp_dsp_H_
#ifdef __cplusplus
extern "C"
{
#endif
// Common includes
#include "dsp_common.h"
#include "dsp_types.h"
// Signal processing
#include "dsps_dotprod.h"
#include "dsps_math.h"
#include "dsps_fir.h"
#include "dsps_biquad.h"
#include "dsps_biquad_gen.h"
#include "dsps_wind.h"
#include "dsps_conv.h"
#include "dsps_corr.h"
#include "dsps_d_gen.h"
#include "dsps_h_gen.h"
#include "dsps_tone_gen.h"
#include "dsps_snr.h"
#include "dsps_sfdr.h"
#include "dsps_fft2r.h"
#include "dsps_fft4r.h"
#include "dsps_dct.h"
// Matrix operations
#include "dspm_mult.h"
// Support functions
#include "dsps_view.h"
// Image processing functions:
#include "dspi_dotprod.h"
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
#include "mat.h"
#endif
#endif // _esp_dsp_H_

View File

@ -0,0 +1,21 @@
// Copyright 2018-2020 spressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file include defenitions that are emulate esp-idf error codes
#ifndef _esp_attr_h_
#define _esp_attr_h_
#endif // _esp_attr_h_

View File

@ -0,0 +1,29 @@
// Copyright 2018-2020 spressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file include defenitions that are emulate esp-idf error codes
#ifndef _esp_err_h_
#define _esp_err_h_
#include <stdlib.h>
typedef int esp_err_t;
#define ESP_OK 0
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif // M_PI
#endif // _esp_err_h_

View File

@ -0,0 +1,24 @@
// Copyright 2018-2020 spressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file include defenitions that are emulate esp-idf error codes
#ifndef _esp_log_h_
#define _esp_log_h_
#include <stdlib.h>
#define ESP_LOGD
#endif // _esp_log_h_

View File

@ -0,0 +1,4 @@
#ifndef _sdkconfig_h_
#define _sdkconfig_h_
#endif // _sdkconfig_h_

View File

@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "dsp_common.h"
#include <stdarg.h>
#define TIE_LOG_ENABLED 1
#if (CONFIG_IDF_TARGET_ESP32S3)
esp_err_t tie_log(int n_regs, ...){
#if !TIE_LOG_ENABLED
return ESP_OK;
#else
va_list list;
va_start(list, n_regs);
uint32_t reg_128_bits[4] = {0, 0, 0, 0};
int reg_code;
for(int i = 0; i < n_regs; i++){
reg_code = va_arg(list, int);
// ACCX register
if( reg_code == 'a'){
asm volatile("rur.accx_0 %0" : "=a" (reg_128_bits[0]));
asm volatile("rur.accx_1 %0" : "=a" (reg_128_bits[1]));
printf("ACCX - %02x %08x", (unsigned int)reg_128_bits[1], (unsigned int)reg_128_bits[0]);
printf(" --- %llu\n", (long long unsigned)reg_128_bits[1] << 32 | (unsigned int)reg_128_bits[0]);
}
// SAR:_BYTE register
else if( reg_code == 's'){
asm volatile("rur.sar_byte %0" : "=a" (reg_128_bits[0]));
printf("SAR_BYTE - %d\n", (unsigned int)reg_128_bits[0]);
}
// Q0 - Q7 registers
else if((reg_code >= 0) && (reg_code <= 7)){
switch(reg_code){
case 0 : {
asm volatile("ee.movi.32.a q0, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q0, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q0, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q0, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q0");
break;
}
case 1 : {
asm volatile("ee.movi.32.a q1, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q1, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q1, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q1, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q1");
break;
}
case 2 : {
asm volatile("ee.movi.32.a q2, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q2, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q2, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q2, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q2");
break;
}
case 3 : {
asm volatile("ee.movi.32.a q3, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q3, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q3, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q3, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q3");
break;
}
case 4 : {
asm volatile("ee.movi.32.a q4, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q4, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q4, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q4, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q4");
break;
}
case 5 : {
asm volatile("ee.movi.32.a q5, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q5, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q5, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q5, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q5");
break;
}
case 6 : {
asm volatile("ee.movi.32.a q6, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q6, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q6, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q6, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q6");
break;
}
case 7 : {
asm volatile("ee.movi.32.a q7, %0, 0" : "=a" (reg_128_bits[0]));
asm volatile("ee.movi.32.a q7, %0, 1" : "=a" (reg_128_bits[1]));
asm volatile("ee.movi.32.a q7, %0, 2" : "=a" (reg_128_bits[2]));
asm volatile("ee.movi.32.a q7, %0, 3" : "=a" (reg_128_bits[3]));
printf("Q7");
break;
}
}
printf(" - 0x%08X %08X %08X %08X --- ", (unsigned int)reg_128_bits[3], (unsigned int)reg_128_bits[2], (unsigned int)reg_128_bits[1], (unsigned int)reg_128_bits[0]);
printf("%u %u %u %u %u %u %u %u\n", (unsigned int)reg_128_bits[3] >> 16, (unsigned int)reg_128_bits[3] & 0x0000FFFF,
(unsigned int)reg_128_bits[2] >> 16, (unsigned int)reg_128_bits[2] & 0x0000FFFF,
(unsigned int)reg_128_bits[1] >> 16, (unsigned int)reg_128_bits[1] & 0x0000FFFF,
(unsigned int)reg_128_bits[0] >> 16, (unsigned int)reg_128_bits[0] & 0x0000FFFF);
}
else{
printf("Bad register code");
}
}
printf("------------------------------------------------------------------------------------\n");
return ESP_OK;
#endif //TIE_LOG_ENABLED
}
#endif // CONFIG_IDF_TARGET_ESP32S3

View File

@ -0,0 +1,30 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsp_common.h"
bool dsp_is_power_of_two(int x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
int dsp_power_of_two(int x)
{
for (size_t i = 0; i < 32; i++)
{
x = x >> 1;
if(0 == x) return i;
}
return 0;
}

View File

@ -0,0 +1,144 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsps_conv_platform.h"
#if (dsps_ccorr_f32_ae32_enabled == 1)
#include "dsps_conv_f32_m_ae32.S"
// This is dot product function for ESP32 processor.
.text
.align 4
.global dsps_ccorr_f32_ae32
.type dsps_ccorr_f32_ae32,@function
// The function implements the C code from dsps_ccorr_f32_ansi:
//esp_err_t dsps_ccorr_f32_ansi(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *corrout);
//
dsps_ccorr_f32_ae32:
// Signal - a2
// siglen - a3
// Kernel - a4
// kernlen - a5
// corrout - a6
//
// a11 - loop length
entry a1, 16
// Array increment for floating point data should be 4
sub a10, a3, a5
bgez a10, dsps_ccorr_positive
addi a10, a2, 0
addi a2, a4, 0
addi a4, a10, 0
addi a10, a3, 0
addi a3, a5, 0
addi a5, a10, 0
dsps_ccorr_positive:
movi.n a8, 4
addi a11, a5, 0 // lkern - loop counter
movi.n a14, 0
addi a9, a14, 1
movi.n a7, 4
movi.n a8, -4
mull a13, a5, a7 // a13 - kernlen*4
add a13, a13, a4 // a13 - Kernel[kernlen]
addi a13, a13, -4 // a13 - Kernel[kernlen - 1]
ccorr_loop1:
// Clear initial state of the result register
addi a10, a13, 0 // a10 - Kernel
addi a12, a2, 0 // a12 - Signal
wfr f1, a14 // clear output: convout[n] = 0;
// a12 - sig[0]
// a10 - kern[n];
// a9 - n+1
// a7 - 4,
// a8 - -4,
conv_f32_ae32 a12, a10, a9, a7, a7, loop1
addi a9, a9, 1 // (n+1)++
addi a13, a13, -4 // kern[n] - a4--
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // convout++ - increment output pointer
addi a11, a11, -1
bnez a11, ccorr_loop1
// a11 - loop counter = siglen - kernlen - 1
addi a9, a2, 4 // sig[1] - sig[kmin]
addi a13, a5, 0
// skip loop if 0
sub a11, a3, a5 // a11 - loop counter
beqz a11, skip_ccorr_loop2
ccorr_loop2:
// Clear initial state of the result register
addi a12, a9, 0 // a12 - Signal[kmin]
addi a10, a4, 0 // a10 - Kernel
wfr f1, a14 // clear output: convout[n] = 0;
// a12 - sig[kmin]
// a10 - kern[0];
// a11 - kernlen
// a7 - 4,
conv_f32_ae32 a12, a10, a13, a7, a7, loop2
addi a9, a9, 4 // in1++
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // convout++ - increment output pointer
addi a11, a11, -1
bnez a11, ccorr_loop2
skip_ccorr_loop2:
// a9 - the same
addi a11, a5, -1
addi a13, a5, -1
ccorr_loop3:
// Clear initial state of the result register
addi a12, a9, 0 // a12 - Signal[kmin]
addi a10, a4, 0 // a10 - Kernel
wfr f1, a14 // clear output: convout[n] = 0;
// a12 - sig[kmin]
// a10 - kern[n - kmin];
// a11 - length
// a7 - 4,
// a8 - -4,
conv_f32_ae32 a12, a10, a11, a7, a7, loop3
addi a9, a9, 4 // n++
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // convout++ - increment output pointer
addi a11, a11, -1
bnez a11, ccorr_loop3
skip_ccorr_loop3:
movi.n a2, 0 // return status ESP_OK
retw.n
#endif // dsps_ccorr_f32_ae32_enabled

View File

@ -0,0 +1,81 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsps_conv.h"
#include "esp_log.h"
static const char *TAG = "dsps_conv";
esp_err_t dsps_ccorr_f32_ansi(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *corrvout)
{
if (NULL == Signal) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == Kernel) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == corrvout) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
float *sig = (float *)Signal;
float *kern = (float *)Kernel;
int lsig = siglen;
int lkern = kernlen;
if (siglen < kernlen) {
sig = (float *)Kernel;
kern = (float *)Signal;
lsig = kernlen;
lkern = siglen;
}
for (int n = 0; n < lkern; n++) {
size_t k;
size_t kmin = lkern - 1 - n;
corrvout[n] = 0;
for (k = 0; k <= n; k++) {
corrvout[n] += sig[k] * kern[kmin + k];
}
ESP_LOGV(TAG, "L1 k = %i, n = %i , kmin= %i, kmax= %i", 0, n, kmin, kmin + n);
}
for (int n = lkern; n < lsig; n++) {
size_t kmin, kmax, k;
corrvout[n] = 0;
kmin = n - lkern + 1;
kmax = n;
for (k = kmin; k <= kmax; k++) {
corrvout[n] += sig[k] * kern[k - kmin];
}
ESP_LOGV(TAG, "L2 n=%i, kmin = %i, kmax = %i , k-kmin = %i", n, kmin, kmax, 0);
}
for (int n = lsig; n < lsig + lkern - 1; n++) {
size_t kmin, kmax, k;
corrvout[n] = 0;
kmin = n - lkern + 1;
kmax = lsig - 1;
for (k = kmin; k <= kmax; k++) {
corrvout[n] += sig[k] * kern[k - kmin];
}
ESP_LOGV(TAG, "L3 n=%i, kmin = %i, kmax = %i , k - kmin = %i", n, kmin, kmax, kmax - kmin);
}
return ESP_OK;
}

View File

@ -0,0 +1,147 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsps_conv_platform.h"
#if (dsps_conv_f32_ae32_enabled == 1)
#include "dsps_conv_f32_m_ae32.S"
// This is dot product function for ESP32 processor.
.text
.align 4
.global dsps_conv_f32_ae32
.type dsps_conv_f32_ae32,@function
// The function implements the C code from dsps_conv_f32_ansi:
//esp_err_t dsps_conv_f32_ansi(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *convout);
//
dsps_conv_f32_ae32:
// Signal - a2
// siglen - a3
// Kernel - a4
// kernlen - a5
// convout - a6
//
// a11 - loop length
entry a1, 16
// Array increment for floating point data should be 4
sub a10, a3, a5
bgez a10, dsps_conv_positive
addi a10, a2, 0
addi a2, a4, 0
addi a4, a10, 0
addi a10, a3, 0
addi a3, a5, 0
addi a5, a10, 0
dsps_conv_positive:
movi.n a8, 4
addi a11, a5, 0 // lkern - loop counter
movi.n a14, 0
addi a9, a14, 1
movi.n a7, 4
movi.n a8, -4
conv_loop1:
// Clear initial state of the result register
addi a10, a4, 0 // a10 - Kernel
addi a12, a2, 0 // a12 - Signal
wfr f1, a14 // clear output: convout[n] = 0;
// a12 - sig[0]
// a10 - kern[n];
// a9 - n+1
// a7 - 4,
// a8 - -4,
conv_f32_ae32 a12, a10, a9, a7, a8, loop1
addi a9, a9, 1 // (n+1)++
addi a4, a4, 4 // kern[n] - a4++
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // convout++ - increment output pointer
addi a11, a11, -1
bnez a11, conv_loop1
// a11 - loop counter = siglen - kernlen - 1
addi a9, a2, 0 // sig[1] - sig[kmin]
addi a13, a5, 0
// skip loop if 0
sub a11, a3, a5 // a11 - loop counter
beqz a11, skip_conv_loop2
conv_loop2:
// Clear initial state of the result register
addi a12, a9, 4 // a12 - Signal[kmin]
addi a10, a4, -4 // a10 - Kernel
wfr f1, a14 // clear output: convout[n] = 0;
// a12 - sig[kmin]
// a10 - kern[n - kmin];
// a11 - length
// a7 - 4,
// a8 - -4,
conv_f32_ae32 a12, a10, a13, a7, a8, loop2
addi a9, a9, 4 // (n+1)++
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // convout++ - increment output pointer
addi a11, a11, -1
bnez a11, conv_loop2
skip_conv_loop2:
// sub a11, a3, a5 // a11 - loop counter
// beqz a11, skip_conv_loop3
// a9 - the same
addi a11, a5, -1
addi a13, a5, -1
// beqz a11, skip_conv_loop3
conv_loop3:
// Clear initial state of the result register
addi a12, a9, 4 // a12 - Signal[kmin]
addi a10, a4, -4 // a10 - Kernel
wfr f1, a14 // clear output: convout[n] = 0;
// a12 - sig[kmin]
// a10 - kern[n - kmin];
// a11 - length
// a7 - 4,
// a8 - -4,
conv_f32_ae32 a12, a10, a13, a7, a8, loop3
addi a9, a9, 4 // (n+1)++
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // convout++ - increment output pointer
addi a13, a13, -1
addi a11, a11, -1
bnez a11, conv_loop3
skip_conv_loop3:
movi.n a2, 0 // return status ESP_OK
retw.n
#endif // dsps_conv_f32_ae32_enabled

View File

@ -0,0 +1,81 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsps_conv.h"
#include "esp_log.h"
static const char *TAG = "dsps_conv";
esp_err_t dsps_conv_f32_ansi(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *convout)
{
if (NULL == Signal) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == Kernel) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == convout) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
float *sig = (float *)Signal;
float *kern = (float *)Kernel;
int lsig = siglen;
int lkern = kernlen;
if (siglen < kernlen) {
sig = (float *)Kernel;
kern = (float *)Signal;
lsig = kernlen;
lkern = siglen;
}
for (int n = 0; n < lkern; n++) {
size_t k;
convout[n] = 0;
for (k = 0; k <= n; k++) {
convout[n] += sig[k] * kern[n - k];
}
ESP_LOGV(TAG,"L1 kmin = %i, kmax = %i , n-kmin = %i", 0, n, n);
}
for (int n = lkern; n < lsig; n++) {
size_t kmin, kmax, k;
convout[n] = 0;
kmin = n - lkern + 1;
kmax = n;
ESP_LOGV(TAG,"L2 n=%i, kmin = %i, kmax = %i , n-kmin = %i", n, kmin, kmax, n-kmin);
for (k = kmin; k <= kmax; k++) {
convout[n] += sig[k] * kern[n - k];
}
}
for (int n = lsig; n < lsig + lkern - 1; n++) {
size_t kmin, kmax, k;
convout[n] = 0;
kmin = n - lkern + 1;
kmax = lsig - 1;
for (k = kmin; k <= kmax; k++) {
convout[n] += sig[k] * kern[n - k];
}
ESP_LOGV(TAG,"L3 n=%i, kmin = %i, kmax = %i , n-kmin = %i", n, kmin, kmax, n-kmin);
}
return ESP_OK;
}

View File

@ -0,0 +1,39 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
.macro conv_f32_ae32 x1 x2 count step1 step2 name
// This macro calculates floating point dot product for count float samples
// x1, x2 - input arrays
// count - amount of samples
// step1 - start step
//,step2 - A register for array step increment. (should be divided by 4)
// f1 - contains initial value
//
// result in f1
//
// Macros body:
// f1 += x1[]*x2[]; i: 0..counter-1
// affected: f0, f1, f2
// Example: conv_f32_ae32 a2 a3 a5 a8 a9
// a8 == 4, step is 4 bytes
// a5 == 32, length of array is 32
//
lsxp f0, \x2, \step2
loopnez \count, loop_mac_end_m_ae32\name
lsxp f2, \x1, \step1
madd.s f1, f2, f0
lsxp f0, \x2, \step2
loop_mac_end_m_ae32\name:
.endm

View File

@ -0,0 +1,77 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsps_conv_platform.h"
#if (dsps_corr_f32_ae32_enabled == 1)
#include "dsps_dotprod_f32_m_ae32.S"
// This is dot product function for ESP32 processor.
.text
.align 4
.global dsps_corr_f32_ae32
.type dsps_corr_f32_ae32,@function
// The function implements the following C code:
//esp_err_t dsps_corr_f32_ansi(const float *Signal, const int siglen, const float *Pattern, const int patlen, float *dest)
//{
// for (size_t n = 0; n < (siglen - patlen); n++) {
// float k_corr = 0;
// for (size_t m = 0; m < patlen; m++) {
// k_corr += Signal[n + m] * Pattern[m];
// }
// dest[n] = k_corr;
// }
// return ESP_OK;
//}
dsps_corr_f32_ae32:
// Signal - a2
// siglen - a3
// Pattern - a4
// patlen - a5
// dest - a6
// a11 - loop length
entry a1, 16
// Array increment for floating point data should be 4
movi.n a8, 4
movi.n a13, 4
sub a11, a3, a5 // a11 = loop length
addi a11, a11, 1
addi a12, a2, 0 // move input pointer to the a12
movi.n a9, 0
movi.n a14, 0
corr_loop:
// Clear initial state of the result register
addi a10, a4, 0 // a10 - pattern
movi.n a9, 0 // clear a9
wfr f1, a9 // clrar f1
// a12 - input1
// a10 - input2
// a5 - length
// a8 - 4, step in arrays
// a9 - 0
dotprod_f32_ae32 a12, a10, a5, a9, a8;
ssi f1, a6, 0 // Store result from f1 to memory at a6
addi a6, a6, 4 // y++ - increment output pointer
addi a12, a12, 4 // Signal++
addi a11, a11, -1
bnez a11, corr_loop
movi.n a2, 0 // return status ESP_OK
retw.n
#endif // dsps_corr_f32_ae32_enabled

View File

@ -0,0 +1,40 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dsps_corr.h"
esp_err_t dsps_corr_f32_ansi(const float *Signal, const int siglen, const float *Pattern, const int patlen, float *dest)
{
if (NULL == Signal) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == Pattern) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == dest) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (siglen < patlen) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
for (size_t n = 0; n <= (siglen - patlen); n++) {
float k_corr = 0;
for (size_t m = 0; m < patlen; m++) {
k_corr += Signal[n + m] * Pattern[m];
}
dest[n] = k_corr;
}
return ESP_OK;
}

View File

@ -0,0 +1,63 @@
// Copyright 2018-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _dsps_ccorr_H_
#define _dsps_ccorr_H_
#include "dsp_err.h"
#include "dsps_conv_platform.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**@{*/
/**
* @brief Cross correlation
*
* The function make cross correlate between two ignals.
* The implementation use ANSI C and could be compiled and run on any platform
*
* @param[in] Signal1: input array with input 1 signal values
* @param[in] siglen1: length of the input 1 signal array
* @param[in] Signal2: input array with input 2 signal values
* @param[in] siglen2: length of the input signal array
* @param corrout: output array with result of cross correlation. The size of dest array must be (siglen1 + siglen2 - 1) !!!
*
* @return
* - ESP_OK on success
* - One of the error codes from DSP library (one of the input array are NULL, or if (siglen < patlen))
*/
esp_err_t dsps_ccorr_f32_ansi(const float *Signal, const int siglen, const float *Pattern, const int patlen, float *corrout);
esp_err_t dsps_ccorr_f32_ae32(const float *Signal, const int siglen, const float *Pattern, const int patlen, float *corrout);
/**}@*/
#ifdef __cplusplus
}
#endif
#ifdef CONFIG_DSP_OPTIMIZED
#if (dsps_ccorr_f32_ae32_enabled == 1)
#define dsps_ccorr_f32 dsps_ccorr_f32_ae32
#else
#define dsps_ccorr_f32 dsps_ccorr_f32_ansi
#endif // dsps_ccorr_f32_ae32_enabled
#else
#define dsps_ccorr_f32 dsps_ccorr_f32_ansi
#endif
#endif // _dsps_conv_H_

View File

@ -0,0 +1,65 @@
// Copyright 2018-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _dsps_conv_H_
#define _dsps_conv_H_
#include "dsp_err.h"
#include "dsps_conv_platform.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**@{*/
/**
* @brief Convolution
*
* The function convolve Signal array with Kernel array.
* The implementation use ANSI C and could be compiled and run on any platform
*
* @param[in] Signal: input array with signal
* @param[in] siglen: length of the input signal
* @param[in] Kernel: input array with convolution kernel
* @param[in] kernlen: length of the Kernel array
* @param convout: output array with convolution result length of (siglen + Kernel -1)
*
* @return
* - ESP_OK on success
* - One of the error codes from DSP library
*/
esp_err_t dsps_conv_f32_ae32(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *convout);
esp_err_t dsps_conv_f32_ansi(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *convout);
/**@}*/
#ifdef __cplusplus
}
#endif
#ifdef CONFIG_DSP_OPTIMIZED
#if (dsps_conv_f32_ae32_enabled == 1)
#define dsps_conv_f32 dsps_conv_f32_ae32
#else
#define dsps_conv_f32 dsps_conv_f32_ansi
#endif // dsps_conv_f32_ae32_enabled
#else
#define dsps_conv_f32 dsps_conv_f32_ansi
#endif
#endif // _dsps_conv_H_

View File

@ -0,0 +1,20 @@
#ifndef _dsps_conv_platform_H_
#define _dsps_conv_platform_H_
#include "sdkconfig.h"
#ifdef __XTENSA__
#include <xtensa/config/core-isa.h>
#include <xtensa/config/core-matmap.h>
#if ((XCHAL_HAVE_FP == 1) && (XCHAL_HAVE_LOOPS == 1))
#define dsps_conv_f32_ae32_enabled 1
#define dsps_ccorr_f32_ae32_enabled 1
#define dsps_corr_f32_ae32_enabled 1
#endif
#endif // __XTENSA__
#endif // _dsps_conv_platform_H_

View File

@ -0,0 +1,63 @@
// Copyright 2018-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _dsps_corr_H_
#define _dsps_corr_H_
#include "dsp_err.h"
#include "dsps_conv_platform.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**@{*/
/**
* @brief Correlation with pattern
*
* The function correlate input sigla array with pattern array.
* The implementation use ANSI C and could be compiled and run on any platform
*
* @param[in] Signal: input array with signal values
* @param[in] siglen: length of the signal array
* @param[in] Pattern: input array with pattern values
* @param[in] patlen: length of the pattern array. The siglen must be bigger then patlen!
* @param dest: output array with result of correlation
*
* @return
* - ESP_OK on success
* - One of the error codes from DSP library (one of the input array are NULL, or if (siglen < patlen))
*/
esp_err_t dsps_corr_f32_ansi(const float *Signal, const int siglen, const float *Pattern, const int patlen, float *dest);
esp_err_t dsps_corr_f32_ae32(const float *Signal, const int siglen, const float *Pattern, const int patlen, float *dest);
/**@}*/
#ifdef __cplusplus
}
#endif
#ifdef CONFIG_DSP_OPTIMIZED
#if (dsps_corr_f32_ae32_enabled == 1)
#define dsps_corr_f32 dsps_corr_f32_ae32
#else
#define dsps_corr_f32 dsps_corr_f32_ansi
#endif // dsps_corr_f32_ae32_enabled
#else
#define dsps_corr_f32 dsps_corr_f32_ansi
#endif
#endif // _dsps_corr_H_

View File

@ -0,0 +1,81 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "unity.h"
#include "dsp_platform.h"
#include "esp_log.h"
#include "dsps_ccorr.h"
#include "esp_attr.h"
static const char *TAG = "dsps_ccorr";
#define lenA 8
#define lenB 4
static float inputA[lenA];
static float inputB[lenB];
static float output[lenA + lenB - 1 + 2];
static float output_ref[lenA + lenB - 1 + 2];
TEST_CASE("dsps_ccorr_f32_ae32 functionality", "[dsps]")
{
for (int i = 0 ; i < lenA ; i++) {
inputA[i] = i + 3;
}
for (int i = 0 ; i < lenB ; i++) {
inputB[i] = i + 10;
}
for (int i = 0 ; i < (lenA + lenB + 2 - 1); i++) {
output[i] = -1;
output_ref[i] = -1;
}
dsps_ccorr_f32_ae32(inputA, lenA, inputB, lenB, &output[0]);
dsps_ccorr_f32_ansi(inputA, lenA, inputB, lenB, &output_ref[0]);
for (size_t i = 0; i < (lenA + lenB - 1) + 2; i++) {
ESP_LOGI(TAG, "Data[%i] = %2.2f, expected = %2.2f", i, output[i], output_ref[i]);
}
for (size_t i = 0; i < (lenA + lenB - 1) + 2; i++) {
TEST_ASSERT_EQUAL(output_ref[i], output[i]);
}
}
TEST_CASE("dsps_ccorr_f32_ae32 benchmark", "[dsps]")
{
int max_N = 1024;
int ccorr_size = 64;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc((max_N + ccorr_size - 1) * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
for (int i = 0 ; i < max_N ; i++) {
x[i] = 0;
y[i] = 1000;
}
unsigned int start_b = xthal_get_ccount();
dsps_ccorr_f32_ae32(x, max_N, y, ccorr_size, &z[0]);
unsigned int end_b = xthal_get_ccount();
float cycles = end_b - start_b;
ESP_LOGI(TAG, "dsps_ccorr_f32_ae32 - %f cycles for signal %i and pattern %i", cycles, max_N, ccorr_size);
free(x);
free(y);
free(z);
}

View File

@ -0,0 +1,116 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <math.h>
#include "unity.h"
#include "dsp_platform.h"
#include "esp_log.h"
#include "dsps_ccorr.h"
#include "esp_attr.h"
#include "esp_dsp.h"
static const char *TAG = "dsps_ccorr";
#define lenA 20
#define lenB 20
static float inputA[lenA];
static float inputB[lenB];
static float output_fwd[lenA + lenB - 1 + 2];
static float output_back[lenA + lenB - 1 + 2];
TEST_CASE("dsps_ccorr_f32_ansi functionality", "[dsps]")
{
for (size_t la = 1; la < lenA; la++) {
for (size_t lb = 1; lb < lenB; lb++) {
for (int i = 0 ; i < lenA ; i++) {
inputA[i] = (float)rand() / INT32_MAX;
}
for (int i = 0 ; i < lenB ; i++) {
inputB[i] = (float)rand() / INT32_MAX;
}
for (int i = 0 ; i < (lenA + lenB - 1 + 2); i++) {
output_fwd[i] = -1;
output_back[i] = -1;
}
dsps_ccorr_f32_ansi(inputA, la, inputB, lb, &output_fwd[1]);
dsps_ccorr_f32_ansi(inputB, lb, inputA, la, &output_back[1]);
TEST_ASSERT_EQUAL(output_fwd[0], -1);
TEST_ASSERT_EQUAL(output_fwd[la + lb], -1);
TEST_ASSERT_EQUAL(output_back[0], -1);
TEST_ASSERT_EQUAL(output_back[la + lb], -1);
}
}
}
TEST_CASE("dsps_ccorr_f32_ansi draw", "[dsps]")
{
int max_N = 1024;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc((max_N * 2 + 1) * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
int l1 = 8;
int l2 = 4;
for (int i = 0 ; i < max_N ; i++) {
x[i] = 0;
y[i] = 0;
z[i] = 0;
}
x[0] = 20;
x[7] = 30;
y[0] = 10;
y[3] = 8;
dsps_ccorr_f32_ansi(x, l1, y, l2, &z[0]);
dsps_view(z, l1 + l2, l1 + l2, 10, -1, 400, '+');
for (int i = 0 ; i < (l1 + l2 - 1) ; i++) {
ESP_LOGI(TAG, "Z[%i] = %2.2f", i, z[i]);
}
free(x);
free(y);
free(z);
}
TEST_CASE("dsps_ccorr_f32_ansi benchmark", "[dsps]")
{
int max_N = 1024;
int conv_size = 64;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc((max_N * 2 + 1) * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
for (int i = 0 ; i < max_N ; i++) {
x[i] = 0;
y[i] = 1000;
}
unsigned int start_b = xthal_get_ccount();
dsps_ccorr_f32_ansi(x, max_N, y, conv_size, &z[0]);
unsigned int end_b = xthal_get_ccount();
float cycles = end_b - start_b;
ESP_LOGI(TAG, "dsps_conv_f32_ansi - %f cycles for signal %i and pattern %i", cycles, max_N, conv_size);
free(x);
free(y);
free(z);
}

View File

@ -0,0 +1,123 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <math.h>
#include "unity.h"
#include "dsp_platform.h"
#include "esp_log.h"
#include "dsps_conv.h"
#include "esp_attr.h"
static const char *TAG = "dsps_conv";
#define lenA 30
#define lenB 30
static float inputA[lenA];
static float inputB[lenB];
static float output_ref[lenA + lenB - 1 + 2];
static float output_fwd[lenA + lenB - 1 + 2];
static float output_back[lenA + lenB - 1 + 2];
TEST_CASE("dsps_conv_f32_ae32 test output", "[dsps]")
{
int la = 3;
int lb = 2;
for (int i = 0; i < lenA; i++) {
inputA[i] = 10 + i;
}
for (int i = 0; i < lenB; i++) {
inputB[i] = 20 + i;
}
for (int i = 0; i < (lenA + lenB - 1 + 2); i++) {
output_ref[i] = -1;
output_fwd[i] = -1;
output_back[i] = -1;
}
dsps_conv_f32_ansi(inputA, la, inputB, lb, &output_ref[1]);
dsps_conv_f32_ae32(inputA, la, inputB, lb, &output_fwd[1]);
for (size_t i = 0; i < (la + lb + 1); i++) {
ESP_LOGD(TAG, "la=%i, lb=%i, i=%i, ref=%2.3f, fwd=%2.3f", la, lb, i, output_ref[i], output_fwd[i]);
}
float max_eps = 0.000001;
for (size_t i = 0; i < (la + lb + 1); i++) {
if (fabs(output_ref[i] - output_fwd[i]) > max_eps) {
ESP_LOGE(TAG, "la=%i, lb=%i, i=%i, ref=%2.3f, fwd=%2.3f", la, lb, i, output_ref[i], output_fwd[i]);
}
TEST_ASSERT_EQUAL(output_ref[i], output_fwd[i]);
}
}
TEST_CASE("dsps_conv_f32_ae32 functionality", "[dsps]")
{
for (size_t la = 2; la < lenA; la++) {
for (size_t lb = 2; lb < lenB; lb++) {
for (int i = 0 ; i < lenA ; i++) {
inputA[i] = (float)rand() / INT32_MAX;
}
for (int i = 0 ; i < lenB ; i++) {
inputB[i] = (float)rand() / INT32_MAX;
}
for (int i = 0 ; i < (lenA + lenB - 1 + 2); i++) {
output_ref[i] = -1;
output_fwd[i] = -1;
output_back[i] = -1;
}
dsps_conv_f32_ansi(inputA, la, inputB, lb, &output_ref[1]);
dsps_conv_f32_ae32(inputA, la, inputB, lb, &output_fwd[1]);
dsps_conv_f32_ae32(inputB, lb, inputA, la, &output_back[1]);
float max_eps = 0.000001;
for (size_t i = 0; i < (la + lb + 1); i++) {
if ((fabs(output_ref[i] - output_fwd[i]) > max_eps) || (fabs(output_ref[i] - output_back[i]) > max_eps) || (fabs(output_back[i] - output_fwd[i]) > max_eps)) {
ESP_LOGE(TAG, "la=%i, lb=%i, i=%i, ref=%2.3f, fwd=%2.3f, back=%2.3f", la, lb, i, output_ref[i], output_fwd[i], output_back[i]);
}
TEST_ASSERT_EQUAL(output_ref[i], output_fwd[i]);
TEST_ASSERT_EQUAL(output_ref[i], output_back[i]);
TEST_ASSERT_EQUAL(output_back[i], output_fwd[i]);
}
}
}
}
TEST_CASE("dsps_conv_f32_ae32 benchmark", "[dsps]")
{
int max_N = 1024;
int conv_size = 64;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc((max_N * 2 + 1) * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
for (int i = 0 ; i < max_N ; i++) {
x[i] = 0;
y[i] = 1000;
}
unsigned int start_b = xthal_get_ccount();
dsps_conv_f32_ae32(x, max_N, y, conv_size, &z[0]);
unsigned int end_b = xthal_get_ccount();
float cycles = end_b - start_b;
ESP_LOGI(TAG, "dsps_conv_f32_ae32 - %f cycles for signal %i and pattern %i", cycles, max_N, conv_size);
free(x);
free(y);
free(z);
}

View File

@ -0,0 +1,146 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <math.h>
#include "unity.h"
#include "dsp_platform.h"
#include "esp_log.h"
#include "dsps_conv.h"
#include "esp_attr.h"
#include "esp_dsp.h"
static const char *TAG = "dsps_conv";
#define lenA 20
#define lenB 20
static float inputA[lenA];
static float inputB[lenB];
static float output_ref[lenA + lenB - 1 + 2];
static float output_fwd[lenA + lenB - 1 + 2];
static float output_back[lenA + lenB - 1 + 2];
esp_err_t dsps_conv_f32_ref(const float *Signal, const int siglen, const float *Kernel, const int kernlen, float *convout)
{
if (NULL == Signal) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == Kernel) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
if (NULL == convout) {
return ESP_ERR_DSP_PARAM_OUTOFRANGE;
}
for (int n = 0; n < siglen + kernlen - 1; n++) {
size_t kmin, kmax, k;
convout[n] = 0;
kmin = (n >= kernlen - 1) ? n - (kernlen - 1) : 0;
kmax = (n < siglen - 1) ? n : siglen - 1;
for (k = kmin; k <= kmax; k++) {
convout[n] += Signal[k] * Kernel[n - k];
}
}
return ESP_OK;
}
TEST_CASE("dsps_conv_f32_ansi functionality", "[dsps]")
{
for (size_t la = 1; la < lenA; la++) {
for (size_t lb = 1; lb < lenB; lb++) {
for (int i = 0 ; i < lenA ; i++) {
inputA[i] = (float)rand() / INT32_MAX;
}
for (int i = 0 ; i < lenB ; i++) {
inputB[i] = (float)rand() / INT32_MAX;
}
for (int i = 0 ; i < (lenA + lenB - 1 + 2); i++) {
output_ref[i] = -1;
output_fwd[i] = -1;
output_back[i] = -1;
}
dsps_conv_f32_ref(inputA, la, inputB, lb, &output_ref[1]);
dsps_conv_f32_ansi(inputA, la, inputB, lb, &output_fwd[1]);
dsps_conv_f32_ansi(inputB, lb, inputA, la, &output_back[1]);
float max_eps = 0.000001;
for (size_t i = 0; i < (la + lb + 1); i++) {
if ((fabs(output_ref[i] - output_fwd[i]) > max_eps) || (fabs(output_ref[i] - output_back[i]) > max_eps) || (fabs(output_back[i] - output_fwd[i]) > max_eps)) {
ESP_LOGE(TAG, "la=%i, lb=%i, i=%i, ref=%2.3f, fwd=%2.3f, back=%2.3f", la, lb, i, output_ref[i], output_fwd[i], output_back[i]);
}
TEST_ASSERT_EQUAL(output_ref[i], output_fwd[i]);
TEST_ASSERT_EQUAL(output_ref[i], output_back[i]);
TEST_ASSERT_EQUAL(output_back[i], output_fwd[i]);
}
}
}
}
TEST_CASE("dsps_conv_f32_ansi draw", "[dsps]")
{
int max_N = 1024;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc((max_N * 2 + 1) * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
for (int i = 0 ; i < max_N ; i++) {
x[i] = 10;
y[i] = 20;
z[i] = 0;
}
dsps_conv_f32_ansi(x, 32, y, 16, &z[0]);
dsps_view(z, 32 + 16, 32 + 16, 10, -1, 4000, '+');
free(x);
free(y);
free(z);
}
TEST_CASE("dsps_conv_f32_ansi benchmark", "[dsps]")
{
int max_N = 1024;
int conv_size = 64;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc((max_N * 2 + 1) * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
for (int i = 0 ; i < max_N ; i++) {
x[i] = 0;
y[i] = 1000;
}
unsigned int start_b = xthal_get_ccount();
dsps_conv_f32_ansi(x, max_N, y, conv_size, &z[0]);
unsigned int end_b = xthal_get_ccount();
float cycles = end_b - start_b;
ESP_LOGI(TAG, "dsps_conv_f32_ansi - %f cycles for signal %i and pattern %i", cycles, max_N, conv_size);
free(x);
free(y);
free(z);
}

View File

@ -0,0 +1,82 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "unity.h"
#include "dsp_platform.h"
#include "esp_log.h"
#include "dsps_corr.h"
#include "esp_attr.h"
static const char *TAG = "dsps_corr";
#define lenA 15
#define lenB 10
static float inputA[lenA];
static float inputB[lenB];
static float output[lenA + lenB - 1 + 2];
static float output_ref[lenA + lenB - 1 + 2];
TEST_CASE("dsps_corr_f32_ae32 functionality", "[dsps]")
{
for (int i = 0 ; i < lenA ; i++) {
inputA[i] = i;
}
for (int i = 0 ; i < lenB ; i++) {
inputB[i] = 10 + i;
}
for (int i = 0 ; i < (lenA - lenB + 2); i++) {
output[i] = -1;
output_ref[i] = -1;
}
inputB[0] = 1;
dsps_corr_f32_ae32(inputA, lenA, inputB, lenB, &output[1]);
dsps_corr_f32_ansi(inputA, lenA, inputB, lenB, &output_ref[1]);
for (size_t i = 0; i < (lenA - lenB) + 2; i++) {
ESP_LOGD(TAG, "Data[%i] = %2.2f, expected = %2.2f", i, output[i], output_ref[i]);
}
for (size_t i = 0; i < (lenA - lenB) + 2; i++) {
TEST_ASSERT_EQUAL(output_ref[i], output[i]);
}
}
TEST_CASE("dsps_corr_f32_ae32 benchmark", "[dsps]")
{
int max_N = 1024;
int corr_size = 64;
float *x = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(x);
float *y = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(y);
float *z = (float *)malloc(max_N * sizeof(float));
TEST_ASSERT_NOT_NULL(z);
for (int i = 0 ; i < max_N ; i++) {
x[i] = 0;
y[i] = 1000;
}
unsigned int start_b = xthal_get_ccount();
dsps_corr_f32_ae32(x, max_N, y, corr_size, &z[0]);
unsigned int end_b = xthal_get_ccount();
float cycles = end_b - start_b;
ESP_LOGI(TAG, "dsps_corr_f32_ae32 - %f cycles for signal %i and pattern %i", cycles, max_N, corr_size);
free(x);
free(y);
free(z);
}

Some files were not shown because too many files have changed in this diff Show More