diff --git a/Include/dsp/distance_functions.h b/Include/dsp/distance_functions.h index 3123fc3a..7f930296 100755 --- a/Include/dsp/distance_functions.h +++ b/Include/dsp/distance_functions.h @@ -36,6 +36,7 @@ #include "dsp/statistics_functions.h" #include "dsp/basic_math_functions.h" #include "dsp/fast_math_functions.h" +#include "dsp/matrix_functions.h" #ifdef __cplusplus extern "C" @@ -332,8 +333,53 @@ float32_t arm_sokalsneath_distance(const uint32_t *pA, const uint32_t *pB, uint3 float32_t arm_yule_distance(const uint32_t *pA, const uint32_t *pB, uint32_t numberOfBools); +typedef enum + { + ARM_DTW_SAKOE_CHIBA_WINDOW = 1, + /*ARM_DTW_ITAKURA_WINDOW = 2,*/ + ARM_DTW_SLANTED_BAND_WINDOW = 3 + } arm_dtw_window; +/** + * @brief Window for dynamic time warping computation + * @param[in] windowType Type of window + * @param[in] windowSize Window size + * @param[in,out] pWindow Window + * @return Error if window type not recognized + * + */ +arm_status arm_dtw_init_window_q7(const arm_dtw_window windowType, + const int32_t windowSize, + arm_matrix_instance_q7 *pWindow); + +/** + * @brief Dynamic Time Warping distance + * @param[in] pDistance Distance matrix (Query rows * Template columns) + * @param[in] pWindow Windowing (can be NULL if no windowing used) + * @param[out] pDTW Temporary cost buffer (same size) + * @param[out] distance Distance + * @return Error in case no path can be found with window constraint + * + */ + +arm_status arm_dtw_distance_f32(const arm_matrix_instance_f32 *pDistance, + const arm_matrix_instance_q7 *pWindow, + arm_matrix_instance_f32 *pDTW, + float32_t *distance); + + +/** + * @brief Mapping between query and template + * @param[in] pDTW Cost matrix (Query rows * Template columns) + * @param[out] pPath Warping path in cost matrix 2*nb rows + nb columns) + * @param[out] pathLength Length of path in number of points + * @return none + * + */ +void arm_dtw_path_f32(const arm_matrix_instance_f32 *pDTW, + int16_t *pPath, + uint32_t *pathLength); #ifdef __cplusplus } #endif diff --git a/Include/dsp/utils.h b/Include/dsp/utils.h index 7b1da5ba..b2049a55 100755 --- a/Include/dsp/utils.h +++ b/Include/dsp/utils.h @@ -40,6 +40,9 @@ extern "C" #define INDEX_MASK 0x0000003F +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +#define MAX(x,y) ((x) > (y) ? (x) : (y)) #define SQ(x) ((x) * (x)) diff --git a/Source/DistanceFunctions/Config.cmake b/Source/DistanceFunctions/Config.cmake index 568f1634..f3c8f690 100644 --- a/Source/DistanceFunctions/Config.cmake +++ b/Source/DistanceFunctions/Config.cmake @@ -25,6 +25,9 @@ target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_russellrao_distance.c) target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_sokalmichener_distance.c) target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_sokalsneath_distance.c) target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_yule_distance.c) +target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_dtw_distance_f32.c) +target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_dtw_path_f32.c) +target_sources(CMSISDSP PRIVATE DistanceFunctions/arm_dtw_init_window_q7.c) target_include_directories(CMSISDSP PRIVATE "DistanceFunctions") diff --git a/Source/DistanceFunctions/DistanceFunctions.c b/Source/DistanceFunctions/DistanceFunctions.c index 0abcbc5f..3a32a57a 100644 --- a/Source/DistanceFunctions/DistanceFunctions.c +++ b/Source/DistanceFunctions/DistanceFunctions.c @@ -49,3 +49,6 @@ #include "arm_sokalmichener_distance.c" #include "arm_sokalsneath_distance.c" #include "arm_yule_distance.c" +#include "arm_dtw_distance_f32.c" +#include "arm_dtw_path_f32.c" +#include "arm_dtw_init_window_q7.c" \ No newline at end of file diff --git a/Source/DistanceFunctions/arm_dtw_distance_f32.c b/Source/DistanceFunctions/arm_dtw_distance_f32.c new file mode 100644 index 00000000..6f70cf94 --- /dev/null +++ b/Source/DistanceFunctions/arm_dtw_distance_f32.c @@ -0,0 +1,153 @@ + +/* ---------------------------------------------------------------------- + * Project: CMSIS DSP Library + * Title: arm_braycurtis_distance_f32.c + * Description: Bray-Curtis distance between two vectors + * + * $Date: 23 April 2021 + * $Revision: V1.9.0 + * + * Target Processor: Cortex-M and Cortex-A cores + * -------------------------------------------------------------------- */ +/* + * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + * + * 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/distance_functions.h" +#include +#include + +#define E(MAT,R,C) \ + (*((MAT)->pData + (MAT)->numCols*(R) + (C))) + +#define WIN(R,C) \ + ((pWindow == NULL) ? 1 : \ + ((*((pWindow)->pData + (pWindow)->numCols*(R) + (C)))==1)) + +/** + @ingroup FloatDist + */ + +/** + @defgroup DTW Dynamic Time Warping Distance + + Dynamic Time Warping Distance. + + This is not really a distance since triangular inequality is + not respected. + + The step pattern used is symmetric2. + Future versions of this function will provide more customization options. + + */ + + +/** + @addtogroup DTW + @{ + */ + + +/** + * @brief Dynamic Time Warping distance + * @param[in] pDistance Distance matrix (Query rows * Template columns) + * @param[in] pWindow Windowing matrix (can be NULL if no windowing used) + * @param[out] pDTW Temporary cost buffer (same size) + * @param[out] distance Distance + * @return ARM_MATH_ARGUMENT_ERROR in case no path can be found with window constraint + * + * @par Windowing matrix + * + * The windowing matrix is used to impose some + * constraints on the search for a path. + * The algorithm will run faster (smaller search + * path) but may not be able to find a solution. + * + * The distance matrix must be initialized only + * where the windowing matrix is containing 1. + * Thus, use of a window also decreases the number + * of distances which must be computed. + */ +arm_status arm_dtw_distance_f32(const arm_matrix_instance_f32 *pDistance, + const arm_matrix_instance_q7 *pWindow, + arm_matrix_instance_f32 *pDTW, + float32_t *distance) +{ + const uint32_t queryLength = pDistance -> numRows; + const uint32_t templateLength = pDistance -> numCols; + float32_t result; + + float32_t *temp = pDTW->pData; + for(uint32_t q=0 ; q < queryLength; q++) + { + for(uint32_t t= 0; t < templateLength; t++) + { + *temp++ = F32_MAX; + } + } + + pDTW->pData[0] = E(pDistance,0,0); + for(uint32_t q = 1; q < queryLength; q++) + { + if (!WIN(q,0)) + { + continue; + } + E(pDTW,q,0) = E(pDTW,q-1,0) + E(pDistance,q,0); + } + + for(uint32_t t = 1; t < templateLength; t++) + { + if (!WIN(0,t)) + { + continue; + } + E(pDTW,0,t) = E(pDTW,0,t-1) + E(pDistance,0,t); + } + + + for(uint32_t q = 1; q < queryLength; q++) + { + for(uint32_t t = 1; t < templateLength; t++) + { + if (!WIN(q,t)) + { + continue; + } + E(pDTW,q,t) = + MIN(E(pDTW,q-1,t-1) + 2.0f * E(pDistance,q,t), + MIN(E(pDTW,q,t-1) + E(pDistance,q,t), + E(pDTW,q-1,t) + E(pDistance,q,t))); + } + } + + if (E(pDTW,queryLength-1,templateLength-1) == F32_MAX) + { + return(ARM_MATH_ARGUMENT_ERROR); + } + + result = E(pDTW,queryLength-1,templateLength-1); + result = result / (queryLength + templateLength); + *distance = result; + + return(ARM_MATH_SUCCESS); +} + +/** + * @} end of DTW group + */ + diff --git a/Source/DistanceFunctions/arm_dtw_init_window_q7.c b/Source/DistanceFunctions/arm_dtw_init_window_q7.c new file mode 100644 index 00000000..31c11094 --- /dev/null +++ b/Source/DistanceFunctions/arm_dtw_init_window_q7.c @@ -0,0 +1,120 @@ + +/* ---------------------------------------------------------------------- + * Project: CMSIS DSP Library + * Title: arm_dtw_path_f32.c + * Description: Warping path + * + * $Date: 23 April 2021 + * $Revision: V1.9.0 + * + * Target Processor: Cortex-M and Cortex-A cores + * -------------------------------------------------------------------- */ +/* + * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + * + * 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/distance_functions.h" +#include +#include +#include + + +/** + @addtogroup DTW + @{ + */ + + +/** + * @brief Window for dynamic time warping computation + * @param[in] windowType Type of window + * @param[in] windowSize Window size + * @param[in,out] pWindow Window + * @return Error if window type not recognized + * + * @par Windowing matrix + * The window matrix will contain 1 for the + * position which are accepted and 0 for the + * positions which are rejected. + * + * The input matrix must already contain a buffer + * and the number of rows (query length) and columns + * (template length) must be initialized. + * The function will fill the matrix with 0 and 1. + * + */ +arm_status arm_dtw_init_window_q7(const arm_dtw_window windowType, + const int32_t windowSize, + arm_matrix_instance_q7 *pWindow) +{ + const int32_t queryLength = pWindow -> numRows; + const int32_t templateLength = pWindow -> numCols; + + switch(windowType) + { + case ARM_DTW_SAKOE_CHIBA_WINDOW: + { + for(int32_t q = 0; q < queryLength; q++) + { + for(int32_t t = 0; t < templateLength; t++) + { + pWindow->pData[templateLength*q + t] = (q7_t)(abs(q-t) <= windowSize); + } + } + } + break; +/* + case ARM_DTW_ITAKURA_WINDOW: + { + for(int32_t q = 0; q < queryLength; q++) + { + for(int32_t t = 0; t < templateLength; t++) + { + pWindow->pData[templateLength*q + t] = (q7_t)( + (t < 2 * q) && + (q <= 2 * t) && + (q >= queryLength - 1 - 2 * (templateLength - t)) && + (t > templateLength - 1 - 2 * (queryLength - q))); + } + } + } + break; +*/ + case ARM_DTW_SLANTED_BAND_WINDOW: + { + for(int32_t q = 0; q < queryLength; q++) + { + for(int32_t t = 0; t < templateLength; t++) + { + float32_t diag = (1.0f * q * templateLength / queryLength); + pWindow->pData[templateLength*q + t] = (q7_t)(fabsf((float32_t)t - diag) <= (float32_t)windowSize); + } + } + } + break; + + default: + return(ARM_MATH_ARGUMENT_ERROR); + } + + return(ARM_MATH_SUCCESS); +} + +/** + * @} end of DTW group + */ + diff --git a/Source/DistanceFunctions/arm_dtw_path_f32.c b/Source/DistanceFunctions/arm_dtw_path_f32.c new file mode 100644 index 00000000..b694354a --- /dev/null +++ b/Source/DistanceFunctions/arm_dtw_path_f32.c @@ -0,0 +1,166 @@ + +/* ---------------------------------------------------------------------- + * Project: CMSIS DSP Library + * Title: arm_dtw_path_f32.c + * Description: Warping path + * + * $Date: 23 April 2021 + * $Revision: V1.9.0 + * + * Target Processor: Cortex-M and Cortex-A cores + * -------------------------------------------------------------------- */ +/* + * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + * + * 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/distance_functions.h" +#include +#include + +#define E(MAT,R,C) \ + (*((MAT)->pData + (MAT)->numCols*(R) + (C))) + + + +/** + @addtogroup DTW + @{ + */ + + +/** + * @brief Mapping between query and template + * @param[in] pDTW Cost matrix (Query rows * Template columns) + * @param[out] pPath Warping path in cost matrix 2*(nb rows + nb columns) + * @param[out] pathLength Length of path in number of points + * @return none + * + * @par Warping path + * + * The warping path has length which is at most + * 2*(query length + template length) in float. + * 2 because it is a list of coordinates : + * (query index, template index) coordinate. + * + * The buffer pPath must be big enough to contain + * the warping path. + * + * pathLength is the number of points in + * the returned path. The resturned path + * may be smaller than query + template. + * + */ +void arm_dtw_path_f32(const arm_matrix_instance_f32 *pDTW, + int16_t *pPath, + uint32_t *pathLength) +{ + int q,t; + float32_t temp; + + *pathLength = 0; + q=pDTW->numRows-1; + t=pDTW->numCols-1; + while((q>0) || (t>0)) + { + int p=-1; + float32_t current=F32_MAX; + + if (q>0) + { + temp = E(pDTW,q-1,t); + if (temp0) + { + temp = E(pDTW,q,t-1); + if (temp0) && (t>0)) + { + temp = E(pDTW,q-1,t-1); + if (temp>1; + for(int i = 0; i< halfLength; i++) + { + temp = fh[0]; + fh[0] = sh[0]; + sh[0] = temp; + + temp = fh[1]; + fh[1] = sh[1]; + sh[1] = temp; + + fh += 2; + sh -= 2; + } +} + +/** + * @} end of DTW group + */ + diff --git a/Testing/FrameworkInclude/Error.h b/Testing/FrameworkInclude/Error.h index 08a436b5..43be3875 100644 --- a/Testing/FrameworkInclude/Error.h +++ b/Testing/FrameworkInclude/Error.h @@ -154,6 +154,8 @@ Macros to use to implement tests. */ #define ASSERT_EQ(A,B) Client::assert_equal(__LINE__,A,B) +#define ASSERT_EQ_PARTIAL(NB,A,B) Client::assert_equal_partial(__LINE__,NB,A,B) + #define ASSERT_NEAR_EQ(A,B,THRESH) Client::assert_near_equal(__LINE__,A,B,THRESH) #define ASSERT_REL_ERROR(A,B,THRESH) Client::assert_relative_error(__LINE__,A,B,THRESH) #define ASSERT_CLOSE_ERROR(A,B,ABSTHRESH,RELTHRESH) Client::assert_close_error(__LINE__,A,B,ABSTHRESH,RELTHRESH) @@ -177,6 +179,43 @@ void assert_equal(unsigned long nb,T pa, T pb) }; +template +void assert_equal_partial(unsigned long nb,unsigned long nbSamples,AnyPattern &pa, AnyPattern &pb) +{ + ASSERT_NOT_EMPTY(pa); + ASSERT_NOT_EMPTY(pb); + + if (pa.nbSamples() < nbSamples) + { + throw (Error(EQUAL_ERROR,nb)); + } + + if (pb.nbSamples() < nbSamples) + { + throw (Error(EQUAL_ERROR,nb)); + } + + unsigned long i=0; + char id[40]; + + T *ptrA = pa.ptr(); + T *ptrB = pb.ptr(); + + for(i=0; i < nbSamples; i++) + { + try + { + assert_equal(nb,ptrA[i],ptrB[i]); + } + catch(Error &err) + { + sprintf(id," (nb=%lu)",i); + strcat(err.details,id); + throw(err); + } + } +}; + template void assert_equal(unsigned long nb,AnyPattern &pa, AnyPattern &pb) { diff --git a/Testing/FrameworkSource/Timing.cpp b/Testing/FrameworkSource/Timing.cpp index eb5423ae..c178aac3 100644 --- a/Testing/FrameworkSource/Timing.cpp +++ b/Testing/FrameworkSource/Timing.cpp @@ -2,7 +2,7 @@ #ifdef CORTEXM -#define SYSTICK_INITIAL_VALUE 0xFFFFFF +#define SYSTICK_INITIAL_VALUE 0x0FFFFFF static uint32_t startCycles=0; #if defined ARMCM0 @@ -53,6 +53,8 @@ static uint32_t startCycles=0; #include "ARMCM55.h" #elif defined ARMCM85 #include "ARMCM85.h" +#elif defined SSE300MPS3 + #include "SSE300MPS3.h" #elif defined ARMv7A /* TODO */ #else @@ -144,9 +146,6 @@ void cycleMeasurementStart() SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk; - while(SysTick->VAL == 0); - - startCycles = SysTick->VAL; @@ -189,15 +188,17 @@ return(0); return(0); #else uint32_t v = SysTick->VAL; - Testing::cycles_t result; - if (v < startCycles) - { - result = startCycles - v; - } - else + int32_t result; + + result = (int32_t)startCycles - (int32_t)v; + + if (result < 0) { - result = SYSTICK_INITIAL_VALUE - (v - startCycles); + result += SYSTICK_INITIAL_VALUE; } + + + /* SysTick tested and tuned on IPSS. On other FVP, the value is forced to 0 because measurement is wrong. diff --git a/Testing/Include/Tests/DistanceTestsF32.h b/Testing/Include/Tests/DistanceTestsF32.h index 08a2b6ca..ad9dcfe0 100755 --- a/Testing/Include/Tests/DistanceTestsF32.h +++ b/Testing/Include/Tests/DistanceTestsF32.h @@ -19,12 +19,19 @@ class DistanceTestsF32:public Client::Suite Client::LocalPattern output; Client::LocalPattern tmpA; Client::LocalPattern tmpB; + Client::LocalPattern tmpC; + + Client::LocalPattern outPath; // Reference patterns are not loaded when we are in dump mode Client::RefPattern ref; + Client::RefPattern refPath; int vecDim; int nbPatterns; + int queryLength; + int templateLength; + }; diff --git a/Testing/PatternGeneration/Distance.py b/Testing/PatternGeneration/Distance.py index 42416838..44a707bf 100755 --- a/Testing/PatternGeneration/Distance.py +++ b/Testing/PatternGeneration/Distance.py @@ -9,6 +9,12 @@ NBTESTSAMPLES = 10 VECDIM = [35,14,20] +query=np.array([ 0.08387197, 0.68082274, 1.06756417, 0.88914541, 0.42513398, -0.3259053, + -0.80934885, -0.90979435, -0.64026483, 0.06923695]) + +template=np.array([ 1.00000000e+00, 7.96326711e-04, -9.99998732e-01, -2.38897811e-03, + 9.99994927e-01]) + def euclidean(xa,xb): r = scipy.spatial.distance.euclidean(xa,xb) return(r) @@ -81,6 +87,22 @@ def yule(xa,xb): r = scipy.spatial.distance.yule (xa,xb) return(r) +def writeDTW(config): + config.setOverwrite(True) + config.writeInput(10, query,"Query") + config.writeInput(10, template,"Template") + query_index = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9] + template_index = [0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 4] + path = np.array(list(zip(query_index,template_index))).flatten() + config.writeReferenceS16(10,path ,"PathRef") + # Distance computed with different windows + references=[0.29962325787495825, + 0.41319151913793334, + 0.6170999383691333 + ] + config.writeReference(10, references,"DTWRef") + config.setOverwrite(False) + def writeFTest(config,funcList): dims=[] dimsM=[] @@ -145,6 +167,9 @@ def writeFTest(config,funcList): config.writeReference(8, outputJen,"Ref") config.writeReference(9, outputMin,"Ref") + writeDTW(config) + + def writeBTest(config,funcList): dims=[] inputsA=[] @@ -234,6 +259,7 @@ def generatePatterns(): configf16=Tools.Config(PATTERNDIR,PARAMDIR,"f16") configu32=Tools.Config(PATTERNDIR,PARAMDIR,"u32") + configf64.setOverwrite(False) configf32.setOverwrite(False) configf16.setOverwrite(False) configu32.setOverwrite(False) diff --git a/Testing/Patterns/DSP/Distance/DistanceF16/DTWRef10_f16.txt b/Testing/Patterns/DSP/Distance/DistanceF16/DTWRef10_f16.txt new file mode 100644 index 00000000..7f0e5ec5 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF16/DTWRef10_f16.txt @@ -0,0 +1,8 @@ +H +3 +// 0.299623 +0x34cb +// 0.413192 +0x369c +// 0.617100 +0x38f0 diff --git a/Testing/Patterns/DSP/Distance/DistanceF16/PathRef10_s16.txt b/Testing/Patterns/DSP/Distance/DistanceF16/PathRef10_s16.txt new file mode 100644 index 00000000..78a88592 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF16/PathRef10_s16.txt @@ -0,0 +1,46 @@ +H +22 +// 0 +0x0000 +// 0 +0x0000 +// 1 +0x0001 +// 0 +0x0000 +// 2 +0x0002 +// 0 +0x0000 +// 3 +0x0003 +// 0 +0x0000 +// 4 +0x0004 +// 0 +0x0000 +// 5 +0x0005 +// 1 +0x0001 +// 6 +0x0006 +// 2 +0x0002 +// 7 +0x0007 +// 2 +0x0002 +// 8 +0x0008 +// 2 +0x0002 +// 9 +0x0009 +// 3 +0x0003 +// 9 +0x0009 +// 4 +0x0004 diff --git a/Testing/Patterns/DSP/Distance/DistanceF16/Query10_f16.txt b/Testing/Patterns/DSP/Distance/DistanceF16/Query10_f16.txt new file mode 100644 index 00000000..d6be48f1 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF16/Query10_f16.txt @@ -0,0 +1,22 @@ +H +10 +// 0.083872 +0x2d5e +// 0.680823 +0x3972 +// 1.067564 +0x3c45 +// 0.889145 +0x3b1d +// 0.425134 +0x36cd +// -0.325905 +0xb537 +// -0.809349 +0xba7a +// -0.909794 +0xbb47 +// -0.640265 +0xb91f +// 0.069237 +0x2c6e diff --git a/Testing/Patterns/DSP/Distance/DistanceF16/Template10_f16.txt b/Testing/Patterns/DSP/Distance/DistanceF16/Template10_f16.txt new file mode 100644 index 00000000..c9a7629a --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF16/Template10_f16.txt @@ -0,0 +1,12 @@ +H +5 +// 1.000000 +0x3c00 +// 0.000796 +0x1286 +// -0.999999 +0xbc00 +// -0.002389 +0x98e5 +// 0.999995 +0x3c00 diff --git a/Testing/Patterns/DSP/Distance/DistanceF32/DTWRef10_f32.txt b/Testing/Patterns/DSP/Distance/DistanceF32/DTWRef10_f32.txt new file mode 100644 index 00000000..246fc20b --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF32/DTWRef10_f32.txt @@ -0,0 +1,8 @@ +W +3 +// 0.299623 +0x3e996838 +// 0.413192 +0x3ed38dd7 +// 0.617100 +0x3f1dfa43 diff --git a/Testing/Patterns/DSP/Distance/DistanceF32/PathRef10_s16.txt b/Testing/Patterns/DSP/Distance/DistanceF32/PathRef10_s16.txt new file mode 100644 index 00000000..78a88592 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF32/PathRef10_s16.txt @@ -0,0 +1,46 @@ +H +22 +// 0 +0x0000 +// 0 +0x0000 +// 1 +0x0001 +// 0 +0x0000 +// 2 +0x0002 +// 0 +0x0000 +// 3 +0x0003 +// 0 +0x0000 +// 4 +0x0004 +// 0 +0x0000 +// 5 +0x0005 +// 1 +0x0001 +// 6 +0x0006 +// 2 +0x0002 +// 7 +0x0007 +// 2 +0x0002 +// 8 +0x0008 +// 2 +0x0002 +// 9 +0x0009 +// 3 +0x0003 +// 9 +0x0009 +// 4 +0x0004 diff --git a/Testing/Patterns/DSP/Distance/DistanceF32/Query10_f32.txt b/Testing/Patterns/DSP/Distance/DistanceF32/Query10_f32.txt new file mode 100644 index 00000000..88d12081 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF32/Query10_f32.txt @@ -0,0 +1,22 @@ +W +10 +// 0.083872 +0x3dabc511 +// 0.680823 +0x3f2e4a66 +// 1.067564 +0x3f88a5f1 +// 0.889145 +0x3f639f09 +// 0.425134 +0x3ed9ab29 +// -0.325905 +0xbea6dd0f +// -0.809349 +0xbf4f317c +// -0.909794 +0xbf68e848 +// -0.640265 +0xbf23e865 +// 0.069237 +0x3d8dcc1a diff --git a/Testing/Patterns/DSP/Distance/DistanceF32/Template10_f32.txt b/Testing/Patterns/DSP/Distance/DistanceF32/Template10_f32.txt new file mode 100644 index 00000000..9a064235 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF32/Template10_f32.txt @@ -0,0 +1,12 @@ +W +5 +// 1.000000 +0x3f800000 +// 0.000796 +0x3a50c095 +// -0.999999 +0xbf7fffeb +// -0.002389 +0xbb1c9067 +// 0.999995 +0x3f7fffab diff --git a/Testing/Patterns/DSP/Distance/DistanceF64/DTWRef10_f64.txt b/Testing/Patterns/DSP/Distance/DistanceF64/DTWRef10_f64.txt new file mode 100644 index 00000000..ab1c5fa8 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF64/DTWRef10_f64.txt @@ -0,0 +1,8 @@ +D +3 +// 0.299623 +0x3fd32d07076c6930 +// 0.413192 +0x3fda71bad76ba597 +// 0.617100 +0x3fe3bf485eb516e2 diff --git a/Testing/Patterns/DSP/Distance/DistanceF64/PathRef10_s16.txt b/Testing/Patterns/DSP/Distance/DistanceF64/PathRef10_s16.txt new file mode 100644 index 00000000..78a88592 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF64/PathRef10_s16.txt @@ -0,0 +1,46 @@ +H +22 +// 0 +0x0000 +// 0 +0x0000 +// 1 +0x0001 +// 0 +0x0000 +// 2 +0x0002 +// 0 +0x0000 +// 3 +0x0003 +// 0 +0x0000 +// 4 +0x0004 +// 0 +0x0000 +// 5 +0x0005 +// 1 +0x0001 +// 6 +0x0006 +// 2 +0x0002 +// 7 +0x0007 +// 2 +0x0002 +// 8 +0x0008 +// 2 +0x0002 +// 9 +0x0009 +// 3 +0x0003 +// 9 +0x0009 +// 4 +0x0004 diff --git a/Testing/Patterns/DSP/Distance/DistanceF64/Query10_f64.txt b/Testing/Patterns/DSP/Distance/DistanceF64/Query10_f64.txt new file mode 100644 index 00000000..5bbd4034 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF64/Query10_f64.txt @@ -0,0 +1,22 @@ +D +10 +// 0.083872 +0x3fb578a228337ad7 +// 0.680823 +0x3fe5c94cc5558a20 +// 1.067564 +0x3ff114be2ac8808d +// 0.889145 +0x3fec73e1132ad516 +// 0.425134 +0x3fdb356527212c20 +// -0.325905 +0xbfd4dba1e745f4d7 +// -0.809349 +0xbfe9e62f8f39c447 +// -0.909794 +0xbfed1d090a6abd0d +// -0.640265 +0xbfe47d0cab3420c4 +// 0.069237 +0x3fb1b98343ecbedb diff --git a/Testing/Patterns/DSP/Distance/DistanceF64/Template10_f64.txt b/Testing/Patterns/DSP/Distance/DistanceF64/Template10_f64.txt new file mode 100644 index 00000000..7f0d3b16 --- /dev/null +++ b/Testing/Patterns/DSP/Distance/DistanceF64/Template10_f64.txt @@ -0,0 +1,12 @@ +D +5 +// 1.000000 +0x3ff0000000000000 +// 0.000796 +0x3f4a18129720662e +// -0.999999 +0xbfeffffd573f6831 +// -0.002389 +0xbf63920cdb4e508b +// 0.999995 +0x3feffff55c743065 diff --git a/Testing/Source/Tests/DistanceTestsF32.cpp b/Testing/Source/Tests/DistanceTestsF32.cpp index f2a990fa..bf1ed46a 100755 --- a/Testing/Source/Tests/DistanceTestsF32.cpp +++ b/Testing/Source/Tests/DistanceTestsF32.cpp @@ -5,6 +5,102 @@ + void DistanceTestsF32::test_dtw_distance_f32() + { + const float32_t *inpA = inputA.ptr(); + const float32_t *inpB = inputB.ptr(); + arm_matrix_instance_f32 distances; + arm_matrix_instance_f32 costs; + arm_matrix_instance_q7 window; + + distances.numRows=this->queryLength; + distances.numCols=this->templateLength; + distances.pData = tmpA.ptr(); + + costs.numRows=this->queryLength; + costs.numCols=this->templateLength; + costs.pData = tmpB.ptr(); + + window.numRows=this->queryLength; + window.numCols=this->templateLength; + window.pData = tmpC.ptr(); + + + float32_t *outp = output.ptr(); + int16_t *outPathp = outPath.ptr(); + uint32_t pathLength; + + + for(int i=0; i < this->nbPatterns ; i ++) + { + float32_t *c = distances.pData; + for(int q=0; q < this->queryLength; q++) + { + for(int t=0; t < this->templateLength; t++) + { + *c = fabs(inpA[q] - inpB[t]); + c++; + } + } + + + arm_status status = arm_dtw_distance_f32(&distances, NULL,&costs,outp); + outp++; + ASSERT_TRUE(status == ARM_MATH_SUCCESS); + + arm_dtw_path_f32(&costs,outPathp,&pathLength); + + /* ARM_DTW_SAKOE_CHIBA_WINDOW 5*/ + status = arm_dtw_init_window_q7(ARM_DTW_SAKOE_CHIBA_WINDOW,5,&window); + ASSERT_TRUE(status == ARM_MATH_SUCCESS); + + c = distances.pData; + for(int q=0; q < this->queryLength; q++) + { + for(int t=0; t < this->templateLength; t++) + { + /* Distance does not have + to be computed outside of + the window */ + if (window.pData[q*this->templateLength+t]) + { + *c = fabs(inpA[q] - inpB[t]); + } + c++; + } + } + + status = arm_dtw_distance_f32(&distances, &window,&costs,outp); + ASSERT_TRUE(status == ARM_MATH_SUCCESS); + outp++; + + /* ARM_DTW_SAKOE_CHIBA_WINDOW 3 */ + status = arm_dtw_init_window_q7(ARM_DTW_SAKOE_CHIBA_WINDOW,3,&window); + ASSERT_TRUE(status == ARM_MATH_SUCCESS); + status = arm_dtw_distance_f32(&distances, &window,&costs,outp); + ASSERT_TRUE(status == ARM_MATH_ARGUMENT_ERROR); + + /* ARM_DTW_SLANTED_BAND_WINDOW 1*/ + status = arm_dtw_init_window_q7(ARM_DTW_SLANTED_BAND_WINDOW,1,&window); + ASSERT_TRUE(status == ARM_MATH_SUCCESS); + /* Here again we could compute the distance matrix + only on a subset */ + + status = arm_dtw_distance_f32(&distances, &window,&costs,outp); + ASSERT_TRUE(status == ARM_MATH_SUCCESS); + outp++; + + + inpA += this->queryLength; + inpB += this->templateLength; + outPathp += 2*pathLength; + } + + ASSERT_NEAR_EQ(output,ref,(float32_t)1e-3); + ASSERT_EQ_PARTIAL(2*pathLength,outPath,refPath); + + } + void DistanceTestsF32::test_braycurtis_distance_f32() { const float32_t *inpA = inputA.ptr(); @@ -283,6 +379,28 @@ } break; + case DistanceTestsF32::TEST_DTW_DISTANCE_F32_10: + { + inputA.reload(DistanceTestsF32::INPUT_QUERY_F32_ID,mgr); + inputB.reload(DistanceTestsF32::INPUT_TEMPLATE_F32_ID,mgr); + + + this->nbPatterns=1; + this->queryLength=inputA.nbSamples(); + this->templateLength=inputB.nbSamples(); + output.create(3*this->nbPatterns,DistanceTestsF32::OUT_F32_ID,mgr); + tmpA.create(this->queryLength*this->templateLength,DistanceTestsF32::TMPA_F32_ID,mgr); + tmpB.create(this->queryLength*this->templateLength,DistanceTestsF32::TMPB_F32_ID,mgr); + tmpC.create(this->queryLength*this->templateLength,DistanceTestsF32::TMPC_Q7_ID,mgr); + + outPath.create(2*(this->queryLength+this->templateLength),DistanceTestsF32::OUTA_S16_ID,mgr); + + ref.reload(DistanceTestsF32::REF10_F32_ID,mgr); + refPath.reload(DistanceTestsF32::REF10_S16_PATH_ID,mgr); + + } + break; + } diff --git a/Testing/cmsis_build/runall.py b/Testing/cmsis_build/runall.py index e204da8e..c28bfd45 100644 --- a/Testing/cmsis_build/runall.py +++ b/Testing/cmsis_build/runall.py @@ -10,6 +10,8 @@ parser = argparse.ArgumentParser(description='Parse test description') parser.add_argument('-avh', nargs='?',type = str, default="C:/Keil_v5/ARM/VHT", help="AVH folder") parser.add_argument('-d', action='store_true', help="Debug log") parser.add_argument('-n', action='store_true', help="No force rebuild") +parser.add_argument('-r', action='store_true', help="Raw results only") +parser.add_argument('-c', action='store_true', help="Display cycles (so passing test are displayed)") args = parser.parse_args() @@ -165,8 +167,7 @@ for t in tests: #("StatsTestsF32","../Output.pickle") #] -allSuites=[("WindowTestsF32","../Output.pickle"), -("WindowTestsF64","../Output.pickle")] +allSuites=[("DistanceTestsF32","../Output.pickle")] #allSuites=[("StatsTestsQ7","../Output.pickle")] @@ -200,6 +201,18 @@ solutions={ ] } +solutions={ + 'testac6.csolution.yml':[ + # ("VHT-Corstone-310","CS310"), + ("VHT-Corstone-300","CS300") + ], + 'testgcc.csolution.yml':[ + #("VHT-Corstone-310","CS310"), + #("VHT_M55","M55"), + ##("VHT_M33","M33_DSP_FP"), + ("VHT_M7","M7DP"), + ] +} HTMLHEADER="""
@@ -274,18 +287,24 @@ with open("summary.html","w") as f: else: with open("results.txt","w") as o: print(res.msg,file=o) - res=run(sys.executable,"../processResult.py","-f",pickle,"-e","-ahtml","-r","results.txt",dumpStdErr=False) - if res.error: - printError("Error processResult") - print("

Error processing %s result

" % s,file=f)
-                    print(res.msg,file=f)
-                    print("
",file=f) - continue - else: - pass - # When no error the section is not - # included in final file - #print(res.msg,file=f) + # Dump raw result + if args.r: + print(res.msg) + # If raw result, no post processing + if not args.r: + res=run(sys.executable,"../processResult.py","-f",pickle,"-e","-ahtml","-r","results.txt",dumpStdErr=False) + if res.error: + printError("Error processResult") + print("

Error processing %s result

" % s,file=f)
+                        print(res.msg,file=f)
+                        print("
",file=f) + continue + else: + # When no error the section is + # included in final file on when + # cycles are requested + if args.c: + print(res.msg,file=f) print(HTMLFOOTER,file=f) if ERROR_OCCURED: diff --git a/Testing/cmsis_build/test.Release+VHT-Corstone-300.cprj b/Testing/cmsis_build/test.Release+VHT-Corstone-300.cprj index f140891a..0b43d420 100644 --- a/Testing/cmsis_build/test.Release+VHT-Corstone-300.cprj +++ b/Testing/cmsis_build/test.Release+VHT-Corstone-300.cprj @@ -1,6 +1,6 @@ - + Automatically generated project @@ -18,10 +18,10 @@ - + - EMBEDDED;NORMALFVP;CORTEXM + EMBEDDED;CORTEXM;SSE300MPS3 ../../Include;../../PrivateInclude;../FrameworkInclude;../GeneratedInclude;../Include/Tests diff --git a/Testing/cmsis_build/test.Release+VHT-Corstone-310.cprj b/Testing/cmsis_build/test.Release+VHT-Corstone-310.cprj index b08d86a3..b7fa64f6 100644 --- a/Testing/cmsis_build/test.Release+VHT-Corstone-310.cprj +++ b/Testing/cmsis_build/test.Release+VHT-Corstone-310.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M0P.cprj b/Testing/cmsis_build/test.Release+VHT_M0P.cprj index db76b411..0c4d9811 100644 --- a/Testing/cmsis_build/test.Release+VHT_M0P.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M0P.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M23.cprj b/Testing/cmsis_build/test.Release+VHT_M23.cprj index c61011ab..944b0ff7 100644 --- a/Testing/cmsis_build/test.Release+VHT_M23.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M23.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M3.cprj b/Testing/cmsis_build/test.Release+VHT_M3.cprj index f4ea3c64..bc11c0c3 100644 --- a/Testing/cmsis_build/test.Release+VHT_M3.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M3.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M33.cprj b/Testing/cmsis_build/test.Release+VHT_M33.cprj index 4aafd093..d44e5bf6 100644 --- a/Testing/cmsis_build/test.Release+VHT_M33.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M33.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M4.cprj b/Testing/cmsis_build/test.Release+VHT_M4.cprj index 1265c810..ec8b4240 100644 --- a/Testing/cmsis_build/test.Release+VHT_M4.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M4.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M55.cprj b/Testing/cmsis_build/test.Release+VHT_M55.cprj index 4db6630d..41f8a5ab 100644 --- a/Testing/cmsis_build/test.Release+VHT_M55.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M55.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M7.cprj b/Testing/cmsis_build/test.Release+VHT_M7.cprj index faf3a590..f0da7e5b 100644 --- a/Testing/cmsis_build/test.Release+VHT_M7.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M7.cprj @@ -1,6 +1,6 @@ - + Automatically generated project diff --git a/Testing/cmsis_build/test.Release+VHT_M7_UNROLLED.cprj b/Testing/cmsis_build/test.Release+VHT_M7_UNROLLED.cprj index 970aaf07..dffc8279 100644 --- a/Testing/cmsis_build/test.Release+VHT_M7_UNROLLED.cprj +++ b/Testing/cmsis_build/test.Release+VHT_M7_UNROLLED.cprj @@ -1,6 +1,6 @@ - + Automatically generated project @@ -17,10 +17,10 @@ - + - EMBEDDED;NORMALFVP;CORTEXM;ARM_MATH_LOOPUNROLL + EMBEDDED;CORTEXM;ARM_MATH_LOOPUNROLL;ARMCM7_DP ../../Include;../../PrivateInclude;../FrameworkInclude;../GeneratedInclude;../Include/Tests diff --git a/Testing/cmsis_build/testac6.csolution.yml b/Testing/cmsis_build/testac6.csolution.yml index 83c1dcb7..c026036b 100644 --- a/Testing/cmsis_build/testac6.csolution.yml +++ b/Testing/cmsis_build/testac6.csolution.yml @@ -11,6 +11,19 @@ solution: - -std=c11 - -Ofast - -ffast-math + - -Wno-packed + - -Wno-missing-variable-declarations + - -Wno-missing-prototypes + - -Wno-missing-noreturn + - -Wno-sign-conversion + - -Wno-nonportable-include-path + - -Wno-reserved-id-macro + - -Wno-unused-macros + - -Wno-documentation-unknown-command + - -Wno-documentation + - -Wno-license-management + - -Wno-parentheses-equality + - -Wno-reserved-identifier - CPP: - -fno-rtti - -DNDEBUG @@ -34,7 +47,6 @@ solution: - ../Include/Tests defines: - EMBEDDED - - NORMALFVP packs: - pack: ARM::CMSIS@5.9.0 @@ -48,37 +60,44 @@ solution: device: ARM::SSE-310-MPS3 defines: - CORTEXM + - SSE310MPS3 - type: VHT-Corstone-300 device: ARM::SSE-300-MPS3 defines: - CORTEXM + - SSE300MPS3 - type: VHT_M33 device: ARMCM33_DSP_FP defines: - CORTEXM + - ARMCM33_DSP_FP - type: VHT_M7 device: ARMCM7_DP defines: - CORTEXM + - ARMCM7_DP - type: VHT_M7_UNROLLED device: ARMCM7_DP defines: - CORTEXM - ARM_MATH_LOOPUNROLL + - ARMCM7_DP - type: VHT_M4 device: ARMCM4_FP defines: - CORTEXM + - ARMCM4_FP - type: VHT_M3 device: ARMCM3 defines: - CORTEXM + - ARMCM3 - type: VHT_M23 device: ARMCM23 @@ -89,6 +108,7 @@ solution: device: ARMCM0P defines: - CORTEXM + - ARMCM0P build-types: - type: Release diff --git a/Testing/desc.txt b/Testing/desc.txt index bc412644..2986012d 100644 --- a/Testing/desc.txt +++ b/Testing/desc.txt @@ -2092,6 +2092,9 @@ group Root { Pattern INPUTA_JEN_F32_ID : InputA8_f32.txt Pattern INPUTB_JEN_F32_ID : InputB8_f32.txt + Pattern INPUT_QUERY_F32_ID : Query10_f32.txt + Pattern INPUT_TEMPLATE_F32_ID : Template10_f32.txt + Pattern REF1_F32_ID : Ref1_f32.txt Pattern REF2_F32_ID : Ref2_f32.txt Pattern REF3_F32_ID : Ref3_f32.txt @@ -2102,9 +2105,15 @@ group Root { Pattern REF8_F32_ID : Ref8_f32.txt Pattern REF9_F32_ID : Ref9_f32.txt + Pattern REF10_F32_ID : DTWRef10_f32.txt + Pattern REF10_S16_PATH_ID : PathRef10_s16.txt + Output OUT_F32_ID : Output Output TMPA_F32_ID : TmpA Output TMPB_F32_ID : TmpB + Output TMPC_Q7_ID : TmpC + Output OUTA_S16_ID : OutA + Output OUTB_S16_ID : OutB Functions { arm_braycurtis_distance_f32:test_braycurtis_distance_f32 @@ -2116,6 +2125,7 @@ group Root { arm_euclidean_distance_f32:test_euclidean_distance_f32 arm_jensenshannon_distance_f32:test_jensenshannon_distance_f32 arm_minkowski_distance_f32:test_minkowski_distance_f32 + arm_dtw_distance_f32:test_dtw_distance_f32 } }