#include <deltas.h>
Métodos públicos | |
ParamDeltas () | |
ParamDeltas (INT Ndeltas, INT *windowSize, INT Ndim) | |
~ParamDeltas () | |
void | Initialize (INT Ndeltas, INT *windowSize, INT Ndim) |
Cambia el tamaño del buffer. | |
void | Push (const DOUBLE *e) |
Añade un nuevo vector de parámetros a los buffers de cálculo. | |
INT | Delay () const |
Devuelve el retardo de cálculo. | |
INT | Ndim () const |
Devuelve la dimensión de los parámetros. | |
INT | Ndeltas () const |
Devuelve el número de deltas calculadas. | |
void | Get (DOUBLE *e) const |
Devuelve un vector de parámetros con sus deltas. | |
Métodos protegidos | |
void | Populate (const DOUBLE *e) |
Popula el primer buffer. | |
Atributos protegidos | |
std::vector< buffer2D > | m_vDeltaBuffers |
Buffers usados para el cálculo de derivadas. | |
std::vector< buffer2D > | m_vMemBuffers |
Buffers usados para recordar muestras pasadas. | |
INT | m_Ndim |
Número de dimensiones de los parámetros (sin deltas). | |
bool | m_bInit |
Variable interna para saber si el objeto está inicializado. | |
DOUBLE * | m_pdDiff |
Buffer temporal para cálculo de derivadas. |
El esqueleto de la parametrización sería algo así (por supuesto, el código es muy mejorable, pero sirve para el ejemplo):
INT frameLen = 80: //Tamaño de la ventana de trama en muestras INT npars = 10; //Número de parámetros INT ndeltas = 2; //Número de derivadas a calcular (deriv. y aceleraciones) //array para recoger una trama de muestras DOUBLE* frame = new DOUBLE [frameLen]; //array para recoger un vector de parámetros (sin deltas) DOUBLE* params = new DOUBLE [npars]; //array para recoger las derivadas de los parámetros DOUBLE* deltaparams = new DOUBLE [npars]; //array para recoger un vector de parámetros junto con las deltas (concatenadas) DOUBLE* finalparams = new DOUBLE [npars*(ndeltas+1)]; for (INT i = 0; i < Nframes(); ++i) { frame = GetFrame(i); params = GetParams(frame); //Calculamos las primeras derivadas y las añadimos a los parámetros deltaparams = GetDeltas(params); finalparams = Catenate(params, deltaparams); //Calculamos las segundas derivadas y las añadimos a los parámetros deltaparams = GetDeltas(deltaparams); finalparams = Catenate(finalparams, deltaparams); //Hacemos algo con los parámetros DoSomething(finalparams); }
Salvo por un pequeño detalle. Si se quiere calcular la delta de una trama de forma precisa, es necesario disponer de una ventana de tramas por delante y por detrás de la trama actual. En modo gráfico:
trama -> i-3 i-2 i-1 i i+1 i+2 i+3 * * * * * * * ventana -> \----------------------------------/ | * delta -> i
Dicho de otra forma, para calcular la delta de la trama i-ésima, es necesario que el puntero del archivo esté leyendo la trama i+2 (en este ejemplo). Esto tiene varias implicaciones:
Todo esto se complica de sobremanera si estamos calculando deltas de deltas: El retardo del cálculo se acumula, cada delta puede tener ventanas de tamaño diferente, necesitas varias memorias (una para cada delta y otra para las muestras sin deltas), etc.
Bien, pues esta clase te permite abstraerte de (casi) todo esto. Lo único que debes tener en cuenta es que existe un retardo entre la trama que le das y la delta que te devuelve. Pero incluso este retrardo te lo calcula él de forma automática.
El ejemplo anterior, utilizando esta clase, sería algo así como:
INT frameLen = 80: //Tamaño de la ventana de trama en muestras INT npars = 10; //Número de parámetros INT ndeltas = 2; //Número de derivadas a calcular (deriv. y aceleraciones) INT wins [] = {2, 3}; //Tamaño de las ventanas para cálculo de deltas (en tramas) //Este objeto se encarga de todo el cálculo de deltas ParamDeltas deltas (ndeltas, wins, npars); //array para recoger una trama de muestras DOUBLE* frame = new DOUBLE [frameLen]; //array para recoger un vector de parámetros (sin deltas) DOUBLE* params = new DOUBLE [npars]; //array para recoger un vector de parámetros junto con las deltas (concatenadas) DOUBLE* finalparams = new DOUBLE [npars*(ndeltas+1)]; for (INT i = 0; i < Nframes()+deltas.Delay(); ++i) { //Estamos leyendo más allá del fichero. No debemos hacerlo //Si i >= NFrames(), símplemente se repite la última muestra if (i < NFrames()) frame = GetFrame(i); params = GetParams(frame); //Metemos los parámetros en el sistema deltas.Push(params); //El valor devuelto por el sistema no tiene sentido hasta que no hayamos //metido deltas.Delay() tramas if (i < deltas.Delay()) continue; //Recuperamos la trama con deltas //Será la trama i-deltas.Delay() deltas.Get(finalparams) //Hacemos algo con los parámetros DoSomething(finalparams); }
La clase automáticamente repite la primera trama al principio del fichero, con lo que es capaz de calcular la delta de la primera trama. Con respecto a la última trama, como no hay forma de que la clase sepa que es la última, pues ya nos encargamos nosotros, repitiendo la última trama Delay() veces.
Hay que tener en cuenta que Get() devuelve el vector con deltas para la trama i-Delay(). Si i<Delay(), entonces estamos recuperando una trama que en realidad no existe. El objeto está sin inicializar del todo, y sólo devuelve mierda.
Por último, si no se quiere que se repitan la primera y última trama (es decir, si podemos soportar no calcular deltas al principio y final del archivo), se puede hacer así:
INT frameLen = 80: //Tamaño de la ventana de trama en muestras INT npars = 10; //Número de parámetros INT ndeltas = 2; //Número de derivadas a calcular (deriv. y aceleraciones) INT wins [] = {2, 3}; //Tamaño de las ventanas para cálculo de deltas (en tramas) //Este objeto se encarga de todo el cálculo de deltas ParamDeltas deltas (ndeltas, wins, npars); //array para recoger una trama de muestras DOUBLE* frame = new DOUBLE [frameLen]; //array para recoger un vector de parámetros (sin deltas) DOUBLE* params = new DOUBLE [npars]; //array para recoger un vector de parámetros junto con las deltas (concatenadas) DOUBLE* finalparams = new DOUBLE [npars*(ndeltas+1)]; for (INT i = 0; i < Nframes(); ++i) { //Ahora ya no leemos más allá del final del archivo frame = GetFrame(i); params = GetParams(frame); //Metemos los parámetros en el sistema deltas.Push(params); //Descartamos 2*deltas.Delay(), ya que así nos aseguramos que las deltas //obtenidas se hayan calculado sin repetir la primera trama if (i < 2*deltas.Delay()) continue; //Recuperamos la trama con deltas //Será la trama i-deltas.Delay() //Sólo que ahora i={2*deltas.Delay(),...,Nframes()}, lo que significa //que sólo tenemos tramas completas en el rango i={deltas.Delay(),...,Nframes()-deltas.Delay()} deltas.Get(finalparams) //Hacemos algo con los parámetros DoSomething(finalparams); }
i
. Digamos que estas ventanas tienen semi-anchura N. Es decir, la anchura total de la ventana es de 2N+1.
Esto significa que para calcular la derivada de la trama i
es necesario conover las tramas i-N
hasta i+N
.
Bien, supongamos ahora que no sólo calculamos las diferencias, sino también aceleraciones. Las aceleraciones se calculan como la pendiente de la recta de regresión de las derivadas, en otra ventana de tamaño M (posiblemente diferente a N)
Y podríamos calcular terceras, cuartas... diferencias. Digamos que la semi-anchura de cada una de las ventanas es N[j] para la derivada j-ésima. Entonces se puede demostrar que el retardo total en el cálculo (o lo que es lo mismo, cuánto por delante de la trama i
debemos estar leyendo el archivo para poder calcular TODAS las derivadas de i
) es igual a la suma de todas las semi-ventanas: delay = sum(N[j]).
Definición en la línea 224 del archivo deltas.h.
ParamDeltas::ParamDeltas | ( | INT | Ndeltas, | |
INT * | windowSize, | |||
INT | Ndim | |||
) | [inline] |
void ParamDeltas::Initialize | ( | INT | Ndeltas, | |
INT * | windowSize, | |||
INT | Ndim | |||
) |
El número de deltas puede ser 0, pero ninguna ventana puede ser ni cero ni negativa, o se provoca un ASSERT.
Ndeltas
= 0 se trata como un caso especial
Ndeltas | Número de deltas a calcular |
windowSize | Tamaño de la ventana para el cálculo de cada delta |
Ndim | nº de dimensiones de los parámetros (sin deltas) |
Definición en la línea 95 del archivo deltas.cpp.
void ParamDeltas::Push | ( | const DOUBLE * | e | ) |
e | Vector a añadir. Debe tener Dim() elementos |
Definición en la línea 137 del archivo deltas.cpp.
void ParamDeltas::Get | ( | DOUBLE * | e | ) | const |
<Memoria donde escribir el vector. Debe tener Ndim()*(Ndeltas()+1) elementos
Devuelve un vector completo con deltas. Cuidado, ya que el vector devuelto tiene un retardo de Delay() tramas con respecto al último vector insertado con Push(). Dicho de otra manera, en el siguiente código:
INT ndeltas = 2; INT wins [] = {2, 3}; INT dim = 10; ParamDeltas deltas (ndeltas, wins, dim); DOUBLE* frame = new DOUBLE [dim]; //Trama sin deltas DOUBLE* deltaframe = new DOUBLE [(ndeltas+1)*dim]; //Trama con deltas for (int i = 0, i < Nframes(); ++i) { //Recogemos una trama frame = GetFrame(i); deltas.Push(frame); deltas.Get(deltaframe); }
Cuando metemos al sistema la trama i
mediante un Push(), Get() nos devuelve la trama i-Delay
().
Definición en la línea 186 del archivo deltas.cpp.
void ParamDeltas::Populate | ( | const DOUBLE * | e | ) | [protected] |
Cuando llega la primerísima trama, esta función se encarga de llenar el buffer [0] (el de las muestras sin deltas). En realidad lo llena por completo excepto la última posición, de la cual ya se encarga Push()
Definición en la línea 205 del archivo deltas.cpp.
std::vector<buffer2D> ParamDeltas::m_vDeltaBuffers [protected] |
std::vector<buffer2D> ParamDeltas::m_vMemBuffers [protected] |
INT ParamDeltas::m_Ndim [protected] |
bool ParamDeltas::m_bInit [protected] |
DOUBLE* ParamDeltas::m_pdDiff [protected] |