First version of the dynamic time warping algorithm.

F32 only. Some windows suppported.
pull/94/head
Christophe Favergeon 3 years ago
parent 5bee006eaa
commit b46a2f86b5

@ -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

@ -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))

@ -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")

@ -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"

@ -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 <limits.h>
#include <math.h>
#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
*/

@ -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 <limits.h>
#include <math.h>
#include <stdlib.h>
/**
@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
*/

@ -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 <limits.h>
#include <math.h>
#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 (temp<current)
{
current=temp;
p=2;
}
}
if (t>0)
{
temp = E(pDTW,q,t-1);
if (temp<current)
{
current=temp;
p=0;
}
}
if ((q>0) && (t>0))
{
temp = E(pDTW,q-1,t-1);
if (temp<current)
{
current=temp;
p=1;
}
}
pPath[2 * (*pathLength)] = q;
pPath[2 * (*pathLength) + 1] = t;
*pathLength = *pathLength + 1;
switch(p)
{
case 0:
t = t-1;
break;
case 1:
t=t-1;
q=q-1;
break;
case 2:
q=q-1;
break;
}
}
pPath[2 * (*pathLength)] = 0;
pPath[2 * (*pathLength) + 1] = 0;
*pathLength = *pathLength + 1;
/* Reverse the path */
int16_t *fh,*sh;
fh = pPath;
sh = pPath + 2* (*pathLength)-2;
int halfLength = (*pathLength)>>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
*/

@ -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 <typename T>
void assert_equal_partial(unsigned long nb,unsigned long nbSamples,AnyPattern<T> &pa, AnyPattern<T> &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 <typename T>
void assert_equal(unsigned long nb,AnyPattern<T> &pa, AnyPattern<T> &pb)
{

@ -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.

@ -19,12 +19,19 @@ class DistanceTestsF32:public Client::Suite
Client::LocalPattern<float32_t> output;
Client::LocalPattern<float32_t> tmpA;
Client::LocalPattern<float32_t> tmpB;
Client::LocalPattern<q7_t> tmpC;
Client::LocalPattern<int16_t> outPath;
// Reference patterns are not loaded when we are in dump mode
Client::RefPattern<float32_t> ref;
Client::RefPattern<int16_t> refPath;
int vecDim;
int nbPatterns;
int queryLength;
int templateLength;
};

@ -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)

@ -0,0 +1,8 @@
H
3
// 0.299623
0x34cb
// 0.413192
0x369c
// 0.617100
0x38f0

@ -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

@ -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

@ -0,0 +1,12 @@
H
5
// 1.000000
0x3c00
// 0.000796
0x1286
// -0.999999
0xbc00
// -0.002389
0x98e5
// 0.999995
0x3c00

@ -0,0 +1,8 @@
W
3
// 0.299623
0x3e996838
// 0.413192
0x3ed38dd7
// 0.617100
0x3f1dfa43

@ -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

@ -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

@ -0,0 +1,12 @@
W
5
// 1.000000
0x3f800000
// 0.000796
0x3a50c095
// -0.999999
0xbf7fffeb
// -0.002389
0xbb1c9067
// 0.999995
0x3f7fffab

@ -0,0 +1,8 @@
D
3
// 0.299623
0x3fd32d07076c6930
// 0.413192
0x3fda71bad76ba597
// 0.617100
0x3fe3bf485eb516e2

@ -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

@ -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

@ -0,0 +1,12 @@
D
5
// 1.000000
0x3ff0000000000000
// 0.000796
0x3f4a18129720662e
// -0.999999
0xbfeffffd573f6831
// -0.002389
0xbf63920cdb4e508b
// 0.999995
0x3feffff55c743065

@ -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;
}

@ -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="""<html>
<header>
@ -274,6 +287,11 @@ with open("summary.html","w") as f:
else:
with open("results.txt","w") as o:
print(res.msg,file=o)
# 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")
@ -282,10 +300,11 @@ with open("summary.html","w") as f:
print("</PRE>",file=f)
continue
else:
pass
# When no error the section is not
# included in final file
#print(res.msg,file=f)
# 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:

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:29:13" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:48:15" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>
@ -18,10 +18,10 @@
<target Ddsp="DSP" Dfpu="DP_FPU" Dmve="FP_MVE" Dname="SSE-300-MPS3" Dsecure="Non-secure" Dtz="TZ" Dvendor="ARM:82">
<output intdir="tmp/test/VHT-Corstone-300/Release" name="test.Release+VHT-Corstone-300" outdir="out/test/VHT-Corstone-300/Release" rtedir="RTE" type="exe"/>
<asflags add="-masm=auto" compiler="AC6"/>
<cflags add="-Wsign-compare -Wdouble-promotion -DNDEBUG -Wall -Wextra -Werror -std=c11 -Ofast -ffast-math" compiler="AC6"/>
<cflags add="-Wsign-compare -Wdouble-promotion -DNDEBUG -Wall -Wextra -Werror -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" compiler="AC6"/>
<cxxflags add="-fno-rtti -DNDEBUG -Wall -Wextra -std=c++11 -Ofast -ffast-math" compiler="AC6"/>
<ldflags add="--entry=Reset_Handler --info=summarysizes --info=sizes --info=totals --info=unused --info=veneers" compiler="AC6" file="RTE/Device/SSE-300-MPS3/fvp_sse300_mps3_s.sct"/>
<defines>EMBEDDED;NORMALFVP;CORTEXM</defines>
<defines>EMBEDDED;CORTEXM;SSE300MPS3</defines>
<includes>../../Include;../../PrivateInclude;../FrameworkInclude;../GeneratedInclude;../Include/Tests</includes>
</target>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:35:59" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:50:01" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<cprj schemaVersion="1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="CPRJ.xsd">
<created timestamp="2022-12-16T07:29:13" tool="csolution 1.1.0"/>
<created timestamp="2023-01-13T09:48:15" tool="csolution 1.1.0"/>
<info isLayer="false">
<description>Automatically generated project</description>
@ -17,10 +17,10 @@
<target Dfpu="DP_FPU" Dname="ARMCM7_DP" Dsecure="Non-secure" Dvendor="ARM:82">
<output intdir="tmp/test/VHT_M7_UNROLLED/Release" name="test.Release+VHT_M7_UNROLLED" outdir="out/test/VHT_M7_UNROLLED/Release" rtedir="RTE" type="exe"/>
<asflags add="-masm=auto" compiler="AC6"/>
<cflags add="-Wsign-compare -Wdouble-promotion -DNDEBUG -Wall -Wextra -Werror -std=c11 -Ofast -ffast-math" compiler="AC6"/>
<cflags add="-Wsign-compare -Wdouble-promotion -DNDEBUG -Wall -Wextra -Werror -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" compiler="AC6"/>
<cxxflags add="-fno-rtti -DNDEBUG -Wall -Wextra -std=c++11 -Ofast -ffast-math" compiler="AC6"/>
<ldflags add="--entry=Reset_Handler --info=summarysizes --info=sizes --info=totals --info=unused --info=veneers" compiler="AC6" file="RTE/Device/ARMCM7_DP/ARMCM7_ac6.sct"/>
<defines>EMBEDDED;NORMALFVP;CORTEXM;ARM_MATH_LOOPUNROLL</defines>
<defines>EMBEDDED;CORTEXM;ARM_MATH_LOOPUNROLL;ARMCM7_DP</defines>
<includes>../../Include;../../PrivateInclude;../FrameworkInclude;../GeneratedInclude;../Include/Tests</includes>
</target>

@ -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

@ -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
}
}

Loading…
Cancel
Save