CMSIS-DSP: New PythonWrapper example

Jupyter notebook showing how to implement a simple kws
and then convert it into an Arduino implementation.
pull/19/head
Christophe Favergeon 4 years ago
parent 75cf0da8e6
commit f74b040be0

@ -0,0 +1,162 @@
###########################################
# Project: CMSIS DSP Library
# Title: appnodes.py
# Description: Application nodes for kws example
#
# $Date: 16 March 2022
# $Revision: V1.10.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.
############################################
from cmsisdsp.sdf.nodes.simu import *
from custom import *
import cmsisdsp.fixedpoint as fix
import cmsisdsp as dsp
# Sink node displaying the recognized word
class Sink(GenericSink):
def __init__(self,inputSize,fifoin):
GenericSink.__init__(self,inputSize,fifoin)
def run(self):
i=self.getReadBuffer()
if i[0] == -1:
print("Unknown")
if i[0] == 0:
print("Yes")
return(0)
# Source node getting sample from NumPy buffer
# At the end of the buffer we generate 0 samples
class Source(GenericSource):
def __init__(self,outputSize,fifoout,buffer):
GenericSource.__init__(self,outputSize,fifoout)
self._offset=0
self._buffer=np.array(buffer)
def run(self):
a=self.getWriteBuffer()
if self._offset + self._outputSize >= len(self._buffer):
a[0:self._outputSize] = np.zeros(self._outputSize,dtype=np.int16)
else:
a[0:self._outputSize] = self._buffer[self._offset:self._offset+self._outputSize]
self._offset = self._offset + self._outputSize
return(0)
# Same implementation as the one in the python notebook
def dsp_zcr_q15(w):
m = dsp.arm_mean_q15(w)
# Negate can saturate so we use CMSIS-DSP function which is working on array (and we have a scalar)
m = dsp.arm_negate_q15(np.array([m]))[0]
w = dsp.arm_offset_q15(w,m)
f=w[:-1]
g=w[1:]
k=np.count_nonzero(np.logical_and(np.logical_or(np.logical_and(f>0,g<0), np.logical_and(f<0,g>0)),g>f))
# k < len(f) so shift should be 0 except when k == len(f)
# When k==len(f) normally quotient is 0x4000 and shift 1 and we convert
# this to 0x7FFF
status,quotient,shift_val=dsp.arm_divide_q15(k,len(f))
if shift_val==1:
return(dsp.arm_shift_q31(np.array([quotient]),shift)[0])
else:
return(quotient)
# Same implementation as the one in the notebook
class FIR(GenericNode):
def __init__(self,inputSize,outSize,fifoin,fifoout):
GenericNode.__init__(self,inputSize,outSize,fifoin,fifoout)
self._firq15=dsp.arm_fir_instance_q15()
def run(self):
a=self.getReadBuffer()
b=self.getWriteBuffer()
errorStatus = 0
blockSize=self._inputSize
numTaps=10
stateLength = numTaps + blockSize - 1
dsp.arm_fir_init_q15(self._firq15,10,fix.toQ15(np.ones(10)/10.0),np.zeros(stateLength,dtype=np.int16))
b[:] = dsp.arm_fir_q15(self._firq15,a)
return(errorStatus)
class Feature(GenericNode):
def __init__(self,inputSize,outSize,fifoin,fifoout,window):
GenericNode.__init__(self,inputSize,outSize,fifoin,fifoout)
self._window=window
def run(self):
a=self.getReadBuffer()
b=self.getWriteBuffer()
errorStatus = 0
b[:] = dsp_zcr_q15(dsp.arm_mult_q15(a,self._window))
return(errorStatus)
class KWS(GenericNode):
def __init__(self,inputSize,outSize,fifoin,fifoout,coef_q15,coef_shift,intercept_q15,intercept_shift):
GenericNode.__init__(self,inputSize,outSize,fifoin,fifoout)
self._coef_q15=coef_q15
self._coef_shift=coef_shift
self._intercept_q15=intercept_q15
self._intercept_shift=intercept_shift
def run(self):
a=self.getReadBuffer()
b=self.getWriteBuffer()
errorStatus = 0
res=dsp.arm_dot_prod_q15(self._coef_q15,a)
scaled=dsp.arm_shift_q15(np.array([self._intercept_q15]),self._intercept_shift-self._coef_shift)[0]
# Because dot prod output is in Q34.30
# and ret is on 64 bits
scaled = np.int64(scaled) << 15
res = res + scaled
if res<0:
b[0]=-1
else:
b[0]=0
return(errorStatus)

File diff suppressed because one or more lines are too long

@ -0,0 +1,352 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: AppNodes.h
* Description: Application nodes for the C compute graph
*
* $Date: 16 March 2022
*
* 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.
*/
#ifndef _APPNODES_H_
#define _APPNODES_H_
#include <hal/nrf_pdm.h>
#include "coef.h"
#include <Arduino.h>
#include <HardwareSerial.h>
// When enabled, lots of additional trace is generated
//#define DEBUG
// Buffer to read samples into, each sample is 16-bits
// This is written by the PDM driver
extern short sampleBuffer[AUDIOBUFFER_LENGTH];
// Number of audio samples available in the audio buffer
extern volatile int samplesRead;
// Sink node. It is just printing the recognized word
template<typename IN, int inputSize> class Sink;
template<int inputSize>
class Sink<q15_t, inputSize>: public GenericSink<q15_t, inputSize>
{
public:
Sink(FIFOBase<q15_t> &src):GenericSink<q15_t,inputSize>(src){};
int run()
{
#if defined(DEBUG)
Serial.println("==== Sink");
#endif
q15_t *b=this->getReadBuffer();
if (b[0]==-1)
{
Serial.println("Unknown");
};
if (b[0]==0)
{
Serial.println("Yes");
};
return(0);
};
};
// Source node. It is getting audio data from the PDM driver
template<typename OUT, int outputSize> class Source;
template<int outputSize>
class Source<q15_t,outputSize>: public GenericSource<q15_t,outputSize>
{
public:
Source(FIFOBase<q15_t> &dst):GenericSource<q15_t,outputSize>(dst)
{
};
int run(){
#if defined(DEBUG)
Serial.println("==== Source");
#endif
q15_t *b=this->getWriteBuffer();
// We wait until enough samples are available.
// In a future version we may experiment with sleeping the board
while(samplesRead<outputSize)
{
#if defined(DEBUG)
Serial.print("Sample reads ");
Serial.println(samplesRead);
#endif
};
#if defined(DEBUG)
Serial.println("Received");
#endif
// We get the samples and update the
// sampleBuffer.
// Since this buffer is also accessed by the IRQ, we need to disable it
NVIC_DisableIRQ(PDM_IRQn);
memcpy(b,sampleBuffer,sizeof(q15_t)*outputSize);
if ((samplesRead-outputSize) > 0)
{
memmove(sampleBuffer,sampleBuffer+outputSize,sizeof(q15_t)*(samplesRead-outputSize));
}
samplesRead = samplesRead - outputSize;
NVIC_EnableIRQ(PDM_IRQn);
#if defined(DEBUG)
Serial.print("After read : Sample reads ");
Serial.println(samplesRead);
#endif
return(0);
};
};
template<typename IN, int inputSize,typename OUT,int outputSize> class FIR;
// FIR node
template<int inputSize>
class FIR<q15_t,inputSize,q15_t,inputSize>: public GenericNode<q15_t,inputSize,q15_t,inputSize>
{
public:
FIR(FIFOBase<q15_t> &src,FIFOBase<q15_t> &dst):GenericNode<q15_t,inputSize,q15_t,inputSize>(src,dst){
int blockSize=inputSize;
int numTaps=10;
int stateLength = numTaps + blockSize - 1;
state=(q15_t*)malloc(stateLength * sizeof(q15_t*));
};
int run(){
#if defined(DEBUG)
Serial.println("==== FIR");
#endif
q15_t *a=this->getReadBuffer();
q15_t *b=this->getWriteBuffer();
int blockSize=inputSize;
int stateLength = NUMTAPS + blockSize - 1;
arm_status status=arm_fir_init_q15(&(this->firq15),NUMTAPS,fir_coefs,state,blockSize);
arm_fir_q15(&(this->firq15),a,b,blockSize);
return(0);
};
arm_fir_instance_q15 firq15;
q15_t *state;
};
/* Not available in the older CMSIS-DSP version provided with Arduino.
So we copy the definition here */
arm_status arm_divide_q15(q15_t numerator,
q15_t denominator,
q15_t *quotient,
int16_t *shift)
{
int16_t sign=0;
q31_t temp;
int16_t shiftForNormalizing;
*shift = 0;
sign = (numerator>>15) ^ (denominator>>15);
if (denominator == 0)
{
if (sign)
{
*quotient = 0x8000;
}
else
{
*quotient = 0x7FFF;
}
return(ARM_MATH_NANINF);
}
numerator = abs(numerator);
denominator = abs(denominator);
temp = ((q31_t)numerator << 15) / ((q31_t)denominator);
shiftForNormalizing= 17 - __CLZ(temp);
if (shiftForNormalizing > 0)
{
*shift = shiftForNormalizing;
temp = temp >> shiftForNormalizing;
}
if (sign)
{
temp = -temp;
}
*quotient=temp;
return(ARM_MATH_SUCCESS);
}
// We similar to the Python implementation
q15_t dsp_zcr_q15(q15_t *w,int blockSize)
{
q15_t m;
arm_mean_q15(w,blockSize,&m);
// Negate can saturate so we use CMSIS-DSP function which is working on array (and we have a scalar)
arm_negate_q15(&m,&m,1);
arm_offset_q15(w,m,w,blockSize);
int k=0;
for(int i=0;i<blockSize-1;i++)
{
int f = w[i];
int g = w[i+1];
if ((((f>0) && (g<0)) || ((f<0) && (g>0))) && g>f)
{
k++;
}
}
// k < len(f) so shift should be 0 except when k == len(f)
// When k==len(f) normally quotient is 0x4000 and shift 1 and we convert
// this to 0x7FFF
q15_t quotient;
int16_t shift;
arm_status status=arm_divide_q15(k,blockSize-1,&quotient,&shift);
if (shift==1)
{
arm_shift_q15(&quotient,shift,&quotient,1);
return(quotient);
}
else
{
return(quotient);
}
};
template<typename IN, int inputSize,typename OUT,int outputSize> class Feature;
template<int inputSize>
class Feature<q15_t,inputSize,q15_t,1>: public GenericNode<q15_t,inputSize,q15_t,1>
{
public:
Feature(FIFOBase<q15_t> &src,FIFOBase<q15_t> &dst,const q15_t *window):
GenericNode<q15_t,inputSize,q15_t,1>(src,dst),mWindow(window){
};
int run(){
#if defined(DEBUG)
Serial.println("==== Feature");
#endif
q15_t *a=this->getReadBuffer();
q15_t *b=this->getWriteBuffer();
arm_mult_q15(a,this->mWindow,a,inputSize);
b[0] = dsp_zcr_q15(a,inputSize);
return(0);
};
const q15_t* mWindow;
};
template<typename IN, int inputSize,typename OUT,int outputSize> class KWS;
template<int inputSize>
class KWS<q15_t,inputSize,q15_t,1>: public GenericNode<q15_t,inputSize,q15_t,1>
{
public:
KWS(FIFOBase<q15_t> &src,FIFOBase<q15_t> &dst,
const q15_t* coef_q15,
const int coef_shift,
const q15_t intercept_q15,
const int intercept_shift):GenericNode<q15_t,inputSize,q15_t,1>(src,dst),
mCoef_q15(coef_q15),
mCoef_shift(coef_shift),
mIntercept_q15(intercept_q15),
mIntercept_shift(intercept_shift)
{
};
int run(){
#if defined(DEBUG)
Serial.println("==== KWS");
#endif
q15_t *a=this->getReadBuffer();
q15_t *b=this->getWriteBuffer();
q63_t res;
arm_dot_prod_q15(this->mCoef_q15,a,inputSize,&res);
q15_t scaled;
arm_shift_q15(&(this->mIntercept_q15),this->mIntercept_shift-this->mCoef_shift,&scaled,1);
// Because dot prod output is in Q34.30
// and ret is on 64 bits
q63_t scaled_Q30 = (q63_t)(scaled) << 15;
res = res + scaled_Q30;
if (res<0)
{
b[0]=-1;
}
else
{
b[0]=0;
}
return(0);
};
const q15_t* mCoef_q15;
const int mCoef_shift;
const q15_t mIntercept_q15;
const int mIntercept_shift;
};
#endif

@ -0,0 +1,297 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: Sched.h
* Description: C++ support templates for the SDF scheduler
*
* $Date: 29 July 2021
* $Revision: V1.10.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.
*/
#ifndef _SCHEDGEN_H_
#define _SCHEDGEN_H_
#include <vector>
// FIFOS
#ifdef DEBUGSCHED
template<typename T>
struct debugtype{
typedef T type;
};
template<>
struct debugtype<char>{
typedef int type;
};
template<typename T>
using Debug = struct debugtype<T>;
#endif
template<typename T>
class FIFOBase{
public:
virtual T* getWriteBuffer(int nb)=0;
virtual T* getReadBuffer(int nb)=0;
};
template<typename T, int length, int isArray=0>
class FIFO: public FIFOBase<T>
{
public:
FIFO(T *buffer,int delay=0):mBuffer(buffer),readPos(0),writePos(delay) {};
FIFO(uint8_t *buffer,int delay=0):mBuffer((T*)buffer),readPos(0),writePos(delay) {};
T * getWriteBuffer(int nb) override
{
if (isArray==1)
{
return(mBuffer);
}
T *ret;
if (readPos > 0)
{
memcpy((void*)mBuffer,(void*)(mBuffer+readPos),(writePos-readPos)*sizeof(T));
writePos -= readPos;
readPos = 0;
}
ret = mBuffer + writePos;
writePos += nb;
return(ret);
};
T* getReadBuffer(int nb) override
{
if (isArray==1)
{
return(mBuffer);
}
T *ret = mBuffer + readPos;
readPos += nb;
return(ret);
}
#ifdef DEBUGSCHED
void dump()
{
int nb=0;
std::cout << std::endl;
for(int i=0; i < length ; i++)
{
std::cout << (Debug<T>::type)mBuffer[i] << " ";
nb++;
if (nb == 10)
{
nb=0;
std::cout << std::endl;
}
}
std::cout << std::endl;
std::cout << std::endl;
}
#endif
protected:
T *mBuffer;
int readPos,writePos;
};
// GENERIC NODES
class NodeBase
{
public:
virtual int run()=0;
};
template<typename IN, int inputSize,typename OUT, int outputSize>
class GenericNode:public NodeBase
{
public:
GenericNode(FIFOBase<IN> &src,FIFOBase<OUT> &dst):mSrc(src),mDst(dst){};
protected:
OUT * getWriteBuffer(){return mDst.getWriteBuffer(outputSize);};
IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);};
private:
FIFOBase<IN> &mSrc;
FIFOBase<OUT> &mDst;
};
template<typename IN, int inputSize,typename OUT1, int output1Size,typename OUT2, int output2Size>
class GenericNode12:public NodeBase
{
public:
GenericNode12(FIFOBase<IN> &src,FIFOBase<OUT1> &dst1,FIFOBase<OUT2> &dst2):mSrc(src),
mDst1(dst1),mDst2(dst2){};
protected:
OUT1 * getWriteBuffer1(){return mDst1.getWriteBuffer(output1Size);};
OUT2 * getWriteBuffer2(){return mDst2.getWriteBuffer(output2Size);};
IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);};
private:
FIFOBase<IN> &mSrc;
FIFOBase<OUT1> &mDst1;
FIFOBase<OUT2> &mDst2;
};
template<typename IN1, int input1Size,typename IN2, int input2Size,typename OUT, int outputSize>
class GenericNode21:public NodeBase
{
public:
GenericNode21(FIFOBase<IN1> &src1,FIFOBase<IN2> &src2,FIFOBase<OUT> &dst):mSrc1(src1),
mSrc2(src2),
mDst(dst){};
protected:
OUT * getWriteBuffer(){return mDst.getWriteBuffer(outputSize);};
IN1 * getReadBuffer1(){return mSrc1.getReadBuffer(input1Size);};
IN2 * getReadBuffer2(){return mSrc2.getReadBuffer(input2Size);};
private:
FIFOBase<IN1> &mSrc1;
FIFOBase<IN2> &mSrc2;
FIFOBase<OUT> &mDst;
};
template<typename OUT, int outputSize>
class GenericSource:public NodeBase
{
public:
GenericSource(FIFOBase<OUT> &dst):mDst(dst){};
protected:
OUT * getWriteBuffer(){return mDst.getWriteBuffer(outputSize);};
private:
FIFOBase<OUT> &mDst;
};
template<typename IN,int inputSize>
class GenericSink:public NodeBase
{
public:
GenericSink(FIFOBase<IN> &src):mSrc(src){};
protected:
IN * getReadBuffer(){return mSrc.getReadBuffer(inputSize);};
private:
FIFOBase<IN> &mSrc;
};
#define REPEAT(N) for(int i=0;i<N;i++)
// GENERIC APPLICATION NODES
template<typename IN,int windowSize, int overlap>
class SlidingBuffer: public GenericNode<IN,windowSize-overlap,IN,windowSize>
{
public:
SlidingBuffer(FIFOBase<IN> &src,FIFOBase<IN> &dst):GenericNode<IN,windowSize-overlap,IN,windowSize>(src,dst)
{
static_assert((windowSize-overlap)>0, "Overlap is too big");
memory.resize(overlap);
};
int run(){
IN *a=this->getReadBuffer();
IN *b=this->getWriteBuffer();
memcpy((void*)b,(void*)memory.data(),overlap*sizeof(IN));
memcpy((void*)(b+overlap),(void*)a,(windowSize-overlap)*sizeof(IN));
memcpy((void*)memory.data(),(void*)(b+windowSize-overlap),overlap*sizeof(IN)) ;
return(0);
};
protected:
std::vector<IN> memory;
};
template<typename IN,int windowSize, int overlap>
class OverlapAdd: public GenericNode<IN,windowSize,IN,windowSize-overlap>
{
public:
OverlapAdd(FIFOBase<IN> &src,FIFOBase<IN> &dst):GenericNode<IN,windowSize,IN,overlap>(src,dst)
{
static_assert((windowSize-overlap)>0, "Overlap is too big");
memory.resize(overlap);
};
int run(){
int i;
IN *a=this->getReadBuffer();
IN *b=this->getWriteBuffer();
for(i=0;i<overlap;i++)
{
memory[i] = a[i] + memory[i];
}
if (2*overlap - windowSize > 0)
{
memcpy((void*)b,(void*)memory.data(),(windowSize-overlap)*sizeof(IN));
memmove(memory.data(),memory.data()+windowSize-overlap,(2*overlap - windowSize)*sizeof(IN));
memcpy(memory.data()+2*overlap - windowSize,a+overlap,(windowSize-overlap)*sizeof(IN));
}
else if (2*overlap - windowSize < 0)
{
memcpy((void*)b,(void*)memory.data(),overlap*sizeof(IN));
memcpy((void*)(b+overlap),(void*)(a+overlap),(windowSize - 2*overlap)*sizeof(IN));
memcpy((void*)memory.data(),(void*)(a+windowSize-overlap),overlap*sizeof(IN));
}
else
{
memcpy((void*)b,(void*)memory.data(),overlap*sizeof(IN));
memcpy((void*)memory.data(),(void*)(a+overlap),overlap*sizeof(IN));
}
return(0);
};
protected:
std::vector<IN> memory;
};
#if !defined(CHECKERROR)
#define CHECKERROR if (sdfError < 0) \
{\
break;\
}
#endif
#endif

@ -0,0 +1,14 @@
arduino-cli board list
arduino-cli config init
arduino-cli lib install Arduino_CMSIS-DSP
arduino-cli compile -b arduino:mbed_nano:nano33ble -v
# Bootloader COM port
arduino-cli upload -b arduino:mbed_nano:nano33ble -p COM5
pip install pyserial
python getData.py

@ -0,0 +1,65 @@
#include "arm_math.h"
#include "coef.h"
const q15_t fir_coefs[NUMTAPS]={3277,3277,3277,3277,3277,3277,3277,3277,3277,3277,
};
const q15_t coef_q15[98]={-3346,-6224,-9697,-12936,-16920,-20357,-22705,-25301,-27291,-29189,
-27827,-26920,-25001,-23132,-20190,-18492,-17783,-16639,-16174,-14871,
-13628,-11917,-10446,-8731,-7502,-6340,-5441,-5151,-4475,-4342,
-4000,-4071,-4295,-3900,-2454,-234,2701,6316,9346,12216,
14414,15401,15285,13877,11377,9229,6648,4804,3306,2451,
2082,2763,4166,5516,6320,6501,6728,6403,5883,5333,
6515,8275,10031,11890,14189,17285,19272,19242,19158,18224,
15625,13057,11268,9628,8184,6156,5943,8021,10310,13040,
16011,17826,19139,20029,20433,20198,18052,15731,13999,11727,
9499,8258,7410,6984,7233,7581,8690,9118,};
const q15_t intercept_q15 = -18108;
const int coef_shift=1;
const int intercept_shift=2;
const q15_t window[400]={0,2,8,18,32,51,73,99,129,163,
202,244,290,340,395,453,515,581,651,724,
802,883,969,1058,1151,1247,1348,1452,1559,1671,
1786,1904,2027,2152,2282,2414,2551,2690,2833,2979,
3129,3282,3438,3597,3760,3926,4094,4266,4441,4618,
4799,4982,5168,5357,5549,5743,5940,6140,6342,6547,
6754,6963,7175,7389,7605,7823,8044,8266,8491,8717,
8946,9176,9408,9642,9877,10114,10353,10593,10834,11077,
11321,11566,11813,12061,12309,12559,12810,13062,13314,13567,
13821,14075,14331,14586,14842,15099,15355,15612,15869,16127,
16384,16641,16899,17156,17413,17669,17926,18182,18437,18693,
18947,19201,19454,19706,19958,20209,20459,20707,20955,21202,
21447,21691,21934,22175,22415,22654,22891,23126,23360,23592,
23822,24051,24277,24502,24724,24945,25163,25379,25593,25805,
26014,26221,26426,26628,26828,27025,27219,27411,27600,27786,
27969,28150,28327,28502,28674,28842,29008,29171,29330,29486,
29639,29789,29935,30078,30217,30354,30486,30616,30741,30864,
30982,31097,31209,31316,31420,31521,31617,31710,31799,31885,
31966,32044,32117,32187,32253,32315,32373,32428,32478,32524,
32566,32605,32639,32669,32695,32717,32736,32750,32760,32766,
32767,32766,32760,32750,32736,32717,32695,32669,32639,32605,
32566,32524,32478,32428,32373,32315,32253,32187,32117,32044,
31966,31885,31799,31710,31617,31521,31420,31316,31209,31097,
30982,30864,30741,30616,30486,30354,30217,30078,29935,29789,
29639,29486,29330,29171,29008,28842,28674,28502,28327,28150,
27969,27786,27600,27411,27219,27025,26828,26628,26426,26221,
26014,25805,25593,25379,25163,24945,24724,24502,24277,24051,
23822,23592,23360,23126,22891,22654,22415,22175,21934,21691,
21447,21202,20955,20707,20459,20209,19958,19706,19454,19201,
18947,18693,18437,18182,17926,17669,17413,17156,16899,16641,
16384,16127,15869,15612,15355,15099,14842,14586,14331,14075,
13821,13567,13314,13062,12810,12559,12309,12061,11813,11566,
11321,11077,10834,10593,10353,10114,9877,9642,9408,9176,
8946,8717,8491,8266,8044,7823,7605,7389,7175,6963,
6754,6547,6342,6140,5940,5743,5549,5357,5168,4982,
4799,4618,4441,4266,4094,3926,3760,3597,3438,3282,
3129,2979,2833,2690,2551,2414,2282,2152,2027,1904,
1786,1671,1559,1452,1348,1247,1151,1058,969,883,
802,724,651,581,515,453,395,340,290,244,
202,163,129,99,73,51,32,18,8,2,
};

@ -0,0 +1,42 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: coef.h
* Description: Parameters for the ML model and filter
*
* $Date: 16 March 2022
*
* 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.
*/
#ifndef COEF_H
#define COEF_H
#define NUMTAPS 10
#define AUDIOBUFFER_LENGTH 512
extern const q15_t fir_coefs[NUMTAPS];
extern const q15_t coef_q15[98];
extern const q15_t intercept_q15 ;
extern const int coef_shift;
extern const int intercept_shift;
extern const q15_t window[400];
#endif

@ -0,0 +1,118 @@
/* ----------------------------------------------------------------------
* Project: CMSIS DSP Library
* Title: kws.ino
* Description: Very simple Yes detector
*
* $Date: 16 March 2022
*
* 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 <PDM.h>
#include "arm_math.h"
#include "coef.h"
#include "scheduler.h"
// default number of output channels
static const char channels = 1;
// default PCM output frequency
static const int frequency = 16000;
// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[AUDIOBUFFER_LENGTH];
// Number of audio samples read
volatile int samplesRead=0;
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Starting ...");
// Configure the data receive callback
PDM.onReceive(onPDMdata);
// Optionally set the gain
// Defaults to 20 on the BLE Sense and 24 on the Portenta Vision Shield
// PDM.setGain(30);
// Initialize PDM with:
// - one channel (mono mode)
// - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
// - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
if (!PDM.begin(channels, frequency)) {
Serial.println("Failed to start PDM!");
while (1);
}
}
void loop() {
int error;
uint32_t nb;
// Start the CMSIS-DSP generated synchronous scheduling
Serial.println("Scheduling ...");
nb = scheduler(&error,window,coef_q15,coef_shift,intercept_q15,intercept_shift);
Serial.println("End of scheduling");
Serial.print("Error status = ");
Serial.println(error);
Serial.print("Nb iterations");
Serial.println(nb);
}
/**
* Callback function to process the data from the PDM microphone.
* NOTE: This callback is executed as part of an ISR.
* Therefore using `Serial` to print messages inside this function isn't supported.
* */
void onPDMdata() {
// Query the number of available bytes
int bytesAvailable = PDM.available();
// Get free remaining bytes in the buffer
// If real time is respected, there should never be
// any overflow.
int remainingFreeBytes = AUDIOBUFFER_LENGTH*2 - samplesRead*2;
if (remainingFreeBytes >= bytesAvailable)
{
// Read into the sample buffer
int nbReadBytes = PDM.read(sampleBuffer+samplesRead, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead += nbReadBytes / 2;
}
else if (remainingFreeBytes > 0)
{
// Read into the sample buffer
int nbReadBytes = PDM.read(sampleBuffer+samplesRead, remainingFreeBytes);
// 16-bit, 2 bytes per sample
samplesRead += nbReadBytes / 2;
}
}

@ -0,0 +1,131 @@
/*
Generated with CMSIS-DSP SDF Scripts.
The generated code is not covered by CMSIS-DSP license.
The support classes and code is covered by CMSIS-DSP license.
*/
#include "arm_math.h"
#include "custom.h"
#include "GenericNodes.h"
#include "AppNodes.h"
#include "scheduler.h"
/* List of nodes */
static NodeBase *nodeArray[7]={0};
/*
Description of the scheduling. It is a list of nodes to call.
The values are indexes in the previous array.
*/
static unsigned int schedule[151]=
{
6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,
0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,
1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,
6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,6,0,1,2,3,4,5,
};
/***********
FIFO buffers
************/
#define FIFOSIZE0 160
#define FIFOSIZE1 400
#define FIFOSIZE2 49
#define FIFOSIZE3 98
#define FIFOSIZE4 98
#define FIFOSIZE5 1
#define BUFFERSIZE0 160
q15_t buf0[BUFFERSIZE0]={0};
#define BUFFERSIZE1 400
q15_t buf1[BUFFERSIZE1]={0};
#define BUFFERSIZE2 49
q15_t buf2[BUFFERSIZE2]={0};
#define BUFFERSIZE3 98
q15_t buf3[BUFFERSIZE3]={0};
#define BUFFERSIZE4 98
q15_t buf4[BUFFERSIZE4]={0};
#define BUFFERSIZE5 1
q15_t buf5[BUFFERSIZE5]={0};
/**************
Classes created for pure function calls (like some CMSIS-DSP functions)
***************/
uint32_t scheduler(int *error,const q15_t *window,
const q15_t *coef_q15,
const int coef_shift,
const q15_t intercept_q15,
const int intercept_shift)
{
int sdfError=0;
uint32_t nbSchedule=0;
/*
Create FIFOs objects
*/
FIFO<q15_t,FIFOSIZE0,1> fifo0(buf0);
FIFO<q15_t,FIFOSIZE1,1> fifo1(buf1);
FIFO<q15_t,FIFOSIZE2,0> fifo2(buf2);
FIFO<q15_t,FIFOSIZE3,1> fifo3(buf3);
FIFO<q15_t,FIFOSIZE4,1> fifo4(buf4);
FIFO<q15_t,FIFOSIZE5,1> fifo5(buf5);
/*
Create node objects
*/
SlidingBuffer<q15_t,400,240> audioWin(fifo0,fifo1);
nodeArray[0]=(NodeBase*)&audioWin;
Feature<q15_t,400,q15_t,1> feature(fifo1,fifo2,window);
nodeArray[1]=(NodeBase*)&feature;
SlidingBuffer<q15_t,98,49> featureWin(fifo2,fifo3);
nodeArray[2]=(NodeBase*)&featureWin;
FIR<q15_t,98,q15_t,98> fir(fifo3,fifo4);
nodeArray[3]=(NodeBase*)&fir;
KWS<q15_t,98,q15_t,1> kws(fifo4,fifo5,coef_q15,coef_shift,intercept_q15,intercept_shift);
nodeArray[4]=(NodeBase*)&kws;
Sink<q15_t,1> sink(fifo5);
nodeArray[5]=(NodeBase*)&sink;
Source<q15_t,160> src(fifo0);
nodeArray[6]=(NodeBase*)&src;
/* Run several schedule iterations */
while(sdfError==0)
{
/* Run a schedule iteration */
for(unsigned long id=0 ; id < 151; id++)
{
unsigned int nodeId = schedule[id];
sdfError = nodeArray[nodeId]->run();
CHECKERROR;
}
nbSchedule++;
}
*error=sdfError;
return(nbSchedule);
}

@ -0,0 +1,29 @@
/*
Generated with CMSIS-DSP SDF Scripts.
The generated code is not covered by CMSIS-DSP license.
The support classes and code is covered by CMSIS-DSP license.
*/
#ifndef _SCHED_H_
#define _SCHED_H_
#ifdef __cplusplus
extern "C"
{
#endif
extern uint32_t scheduler(int *error,const q15_t *window,
const q15_t *coef_q15,
const int coef_shift,
const q15_t intercept_q15,
const int intercept_shift);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,7 @@
{
"cpu": {
"fqbn": "arduino:mbed_nano:nano33ble",
"name": "Arduino Nano 33 BLE",
"port": "serial://COM6"
}
}

@ -0,0 +1,99 @@
digraph structs {
node [shape=plaintext]
rankdir=LR
edge [arrowsize=0.5]
fontname="times"
audioWin [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">audioWin<BR/>(SlidingBuffer)</TD>
</TR>
</TABLE>>];
feature [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">feature<BR/>(Feature)</TD>
</TR>
</TABLE>>];
featureWin [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">featureWin<BR/>(SlidingBuffer)</TD>
</TR>
</TABLE>>];
fir [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">fir<BR/>(FIR)</TD>
</TR>
</TABLE>>];
kws [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">kws<BR/>(KWS)</TD>
</TR>
</TABLE>>];
sink [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">sink<BR/>(Sink)</TD>
</TR>
</TABLE>>];
src [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">src<BR/>(Source)</TD>
</TR>
</TABLE>>];
src:i -> audioWin:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
</TD></TR></TABLE>>,label="q15(160)"]
audioWin:i -> feature:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
</TD></TR></TABLE>>,label="q15(400)"]
feature:i -> featureWin:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >49</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>,label="q15(49)"]
featureWin:i -> fir:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,label="q15(98)"]
fir:i -> kws:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,label="q15(98)"]
kws:i -> sink:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>,label="q15(1)"]
}

@ -0,0 +1,527 @@
#
# Generated with CMSIS-DSP SDF Scripts.
# The generated code is not covered by CMSIS-DSP license.
#
# The support classes and code is covered by CMSIS-DSP license.
#
import sys
import numpy as np
import cmsisdsp as dsp
from cmsisdsp.sdf.nodes.simu import *
from appnodes import *
from custom import *
DEBUGSCHED=False
#
# FIFO buffers
#
FIFOSIZE0=160
buf0=np.zeros(FIFOSIZE0,dtype=np.int16)
FIFOSIZE1=400
buf1=np.zeros(FIFOSIZE1,dtype=np.int16)
FIFOSIZE2=49
buf2=np.zeros(FIFOSIZE2,dtype=np.int16)
FIFOSIZE3=98
buf3=np.zeros(FIFOSIZE3,dtype=np.int16)
FIFOSIZE4=98
buf4=np.zeros(FIFOSIZE4,dtype=np.int16)
FIFOSIZE5=1
buf5=np.zeros(FIFOSIZE5,dtype=np.int16)
def scheduler(input_array,window,coef_q15,coef_shift,intercept_q15,intercept_shift):
sdfError=0
nbSchedule=0
debugCounter=13
#
# Create FIFOs objects
#
fifo0=FIFO(FIFOSIZE0,buf0)
fifo1=FIFO(FIFOSIZE1,buf1)
fifo2=FIFO(FIFOSIZE2,buf2)
fifo3=FIFO(FIFOSIZE3,buf3)
fifo4=FIFO(FIFOSIZE4,buf4)
fifo5=FIFO(FIFOSIZE5,buf5)
#
# Create node objects
#
audioWin = SlidingBuffer(400,240,fifo0,fifo1)
feature = Feature(400,1,fifo1,fifo2,window)
featureWin = SlidingBuffer(98,49,fifo2,fifo3)
fir = FIR(98,98,fifo3,fifo4)
kws = KWS(98,1,fifo4,fifo5,coef_q15,coef_shift,intercept_q15,intercept_shift)
sink = Sink(1,fifo5)
src = Source(160,fifo0,input_array)
while((sdfError==0) and (debugCounter > 0)):
nbSchedule = nbSchedule + 1
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = src.run()
if sdfError < 0:
break
sdfError = audioWin.run()
if sdfError < 0:
break
sdfError = feature.run()
if sdfError < 0:
break
sdfError = featureWin.run()
if sdfError < 0:
break
sdfError = fir.run()
if sdfError < 0:
break
sdfError = kws.run()
if sdfError < 0:
break
sdfError = sink.run()
if sdfError < 0:
break
debugCounter = debugCounter - 1
return(nbSchedule,sdfError)

@ -0,0 +1,99 @@
digraph structs {
node [shape=plaintext]
rankdir=LR
edge [arrowsize=0.5]
fontname="times"
audioWin [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">audioWin<BR/>(SlidingBuffer)</TD>
</TR>
</TABLE>>];
feature [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">feature<BR/>(Feature)</TD>
</TR>
</TABLE>>];
featureWin [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">featureWin<BR/>(SlidingBuffer)</TD>
</TR>
</TABLE>>];
fir [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">fir<BR/>(FIR)</TD>
</TR>
</TABLE>>];
kws [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">kws<BR/>(KWS)</TD>
</TR>
</TABLE>>];
sink [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">sink<BR/>(Sink)</TD>
</TR>
</TABLE>>];
src [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
<TR>
<TD ALIGN="CENTER" PORT="i">src<BR/>(Source)</TD>
</TR>
</TABLE>>];
src:i -> audioWin:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >160</FONT>
</TD></TR></TABLE>>,label="q15(160)"]
audioWin:i -> feature:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >400</FONT>
</TD></TR></TABLE>>,label="q15(400)"]
feature:i -> featureWin:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >49</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>,label="q15(49)"]
featureWin:i -> fir:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,label="q15(98)"]
fir:i -> kws:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >98</FONT>
</TD></TR></TABLE>>,label="q15(98)"]
kws:i -> sink:i [headlabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>,taillabel=<
<TABLE BORDER="0" CELLPADDING="2"><TR><TD><FONT COLOR="blue" POINT-SIZE="12.0" >1</FONT>
</TD></TR></TABLE>>,label="q15(1)"]
}
Loading…
Cancel
Save