Latest changes without errors
VCODATA.cpp
- Committer:
- gstedile
- Date:
- 2017-07-30
- Revision:
- 11:b12388526706
- Parent:
- 10:08e1dc33199e
File content as of revision 11:b12388526706:
/* VCO DATA Library * Copyright (c) 2008-2010, sford * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "VCODATA.h" //#include <math.h> /*############################################################################ ##############################################################################*/ //--------------------------------------------------------------------------------------------------------------------------------------- /* CONSTRUCTORES: */ VCODATA::VCODATA(NAVDATA InitData, int Vel_Max){ vel_max= Vel_Max; // Velocidad máxima. DeltaV=1; InitData.paddata(); // Inicializamos el vector LAST_NAV_DATA con valores default. Las constantes Klong, Klat; Ksen y ZH no se modifican. NAV_DATA = new NAVDATA[vel_max+1]; // Array de "vel_max+1" elementos tipo NAVDATA. Posicion 101 para el Objeto a validar. for (int i=0;i<=vel_max;i+=1) this->NAV_DATA[i]= InitData; // Inicializa NAV_DATA[]. Carga el array repitiendo Initdata en todas las posiciones. } VCODATA::VCODATA(const VCODATA &VCOOBJ){ // Cosntructor copia. vel_max=VCOOBJ.vel_max; DeltaV=VCOOBJ.DeltaV; NAV_DATA = new NAVDATA[vel_max+1]; // Array de "vel_max+1" elementos tipo NAVDATA. Posicion 101 para el Objeto a validar. for (int i=0;i<=vel_max;i+=1) this->NAV_DATA[i]= VCOOBJ.NAV_DATA[i]; // Copio todos los objetos NAV_DATA del VCOOBJ a este. } /*DESTRUCTOR: */ VCODATA::~VCODATA(){ delete[]NAV_DATA; } //--------------------------------------------------------------------------------------------------------------------------------------- //store_data (NAVDATA LastData): Almacena el objeto LastData. Si la velocidad se mantiene constante, sigue concatenando hasta "cant_per" períodos en el objeto de la ultima posicion int VCODATA::store_data (NAVDATA &LastData,int cant_per){ int k_hist_data=3; // Coeficiente para dar peso al valor histórico almacenado. int k_new_data=1; // Coeficiente para dar peso al valor nuevo a almacenar. int k_total=k_hist_data+k_new_data; // Denominador int cp=cant_per; // Periodos consecutivos a velocidad constante para validar datos. int buff_index=int(this->NAV_DATA[vel_max].LAST_NAV_DATA[speed_p]+0.5); // (2)Indice del dato del "buffer" (situado en la posicion vel_max). Si hay cambio de velocidad, // esto se actualiza cuando se "pisa" el objeto del buffer con el entrante. (Ver + adelante(*)) int last_index=int(LastData.LAST_NAV_DATA[speed_p]+0.5); // Indice del dato entrante. if (last_index<0 || last_index > vel_max) return 4; // si el indice esta fuera de rango, salgo con error. double cons_m_hist4last_index=this->NAV_DATA[last_index].LAST_NAV_DATA[cons_mile_p]; // Valor historico corresp. a la velocidad en cuestion. double cons_h_hist4last_index=this->NAV_DATA[last_index].LAST_NAV_DATA[cons_hour_p]; // Valor historico corresp. a la velocidad en cuestion. int last_data_type=LastData.LAST_NAV_DATA[cons_interpolated]; // Tipo de dato entrante double delta_t=LastData.LAST_NAV_DATA[time_f]- this->NAV_DATA[vel_max].LAST_NAV_DATA[time_f]; // Delta de tiempo entre entrante y buffer. if ((delta_t > 0) || (last_data_type!=0)|| (this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_interpolated]!=0)){ // Solo valido el dato entrante si el timestamp es posterior al almacenado // o se trata de un valor inicial (no recolectado). if ( delta_t > this->NAV_DATA->max_period_time || (fabs(this->NAV_DATA[vel_max].LAST_NAV_DATA[speed_p] - LastData.LAST_NAV_DATA[speed_p])> this->DeltaV) || (this->NAV_DATA[vel_max].np_concat==0)) { //Evaluacion de: delta de velocidad para considerar no aceleracion, no ser fin de concatenacion a vel cte. ni datos de inicio de ciclo. this->NAV_DATA[vel_max]=LastData; // Cargo el entrante en la posicion [vel_max], reemplazando al anterior. if (cp == 1) { // No se concatenan períodos-->corresponde almacenar los datos y resetear np_concat. buff_index=last_index; //(*)(2) Indice: del nuevo dato del "buffer" (situado en la posicion vel_max) int data_type4buff_index=this->NAV_DATA[buff_index].LAST_NAV_DATA[cons_interpolated]; //(1) Tipo de dato historico: 0-> real ; 1->interpolated; 2->smoothed; -1-> initial padding this->NAV_DATA[buff_index] = this->NAV_DATA[vel_max]; // Carga el objeto del buffer reemplazando al anterior NAV_DATA para luego actualizar el valor de consumo promediandolo con el del buffer. if (data_type4buff_index==0 && this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_interpolated]==0){ // (1) Solo si valores existente y entrante son recolectado---> promediar cons. historico con buffer. this->NAV_DATA[buff_index].LAST_NAV_DATA[cons_mile_p]=(k_new_data*this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_mile_p] + k_hist_data*cons_m_hist4last_index)/k_total; this->NAV_DATA[buff_index].LAST_NAV_DATA[cons_hour_p]=(k_new_data*this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_hour_p]+ k_hist_data*cons_h_hist4last_index)/k_total; } this->NAV_DATA[vel_max].np_concat=0; // Reset de la cantidad de concatenamientos. } else this->NAV_DATA[vel_max].np_concat=1; // Actualización de la cantidad de concatenamientos. return 0; } else{ // Periodo validado que no es inicio de serie. //(*) El indice sigue siendo el mismo, pues no hay cambio de velocidad con respecto al período anterior. if (this->merge_data(LastData)== -1) return 3; //Combina los datos del actual con el anterior y los deja en la posicion[vel_max].Si no pudo sale con 3. this->NAV_DATA[vel_max].np_concat+=1; // Actualización de la cantidad de concatenamientos. if (this->NAV_DATA[vel_max].np_concat == cp) { // Se alcanzo el numero de períodos cp a velocidad constante-->corresponde almacenar los datos y resetear np_concat. buff_index=int(this->NAV_DATA[vel_max].LAST_NAV_DATA[speed_p]+0.5); //ACTUALIZO despues de merge(2) Indice: del dato del "buffer" (situado en la posicion vel_max) int data_type4buff_index=this->NAV_DATA[buff_index].LAST_NAV_DATA[cons_interpolated]; //(1) Tipo de dato historico: 0-> real ; 1->interpolated; 2->smoothed; -1-> initial padding this->NAV_DATA[buff_index] = this->NAV_DATA[vel_max]; // Carga el objeto del buffer reemplazando al anterior NAV_DATA para luego actualizar el valor de consumo promediandolo con el del buffer. if (data_type4buff_index==0){ // (1) Solo si el valor existente es recolectado---> promediar cons. historico con buffer. this->NAV_DATA[buff_index].LAST_NAV_DATA[cons_mile_p]=(k_new_data*this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_mile_p] + k_hist_data*cons_m_hist4last_index)/k_total; this->NAV_DATA[buff_index].LAST_NAV_DATA[cons_hour_p]=(k_new_data*this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_hour_p]+ k_hist_data*cons_h_hist4last_index)/k_total; } this->NAV_DATA[vel_max].np_concat=0; // Reset de la cantidad de concatenamientos. } } return 0; } else return -1; } //--------------------------------------------------------------------------------------------------------------------------------------- /* get_VCO(int* VCC): Obtiene la Velocidad Crucero Optima (VCO) y Velocidad de Maximo Consumo (VMC) y las carga en el array VCC */ /* Ademas devuelve la VCO o -1 en caso de no poder calcularla */ int VCODATA::get_VCO(int* VCC){ // Velocidades Crucero Críticas: VCC[0]:VCO y VCC[1]:VMC (Vel. de Maximo Consumo) int GET_Min=0; enum find {NO, SI, POSIBLE}; int Ratio_Min=6; // Entorno de evaluación de Máximos / Mínimos. int n_events_eps=0; // Contador de valores de v menores al Minimo (o mayores al Máximo) dentro del entorno Ratio_Min para evaluar validez de Minimo (o Maximo segun sea el caso). int n_events_critical=3; //Cantidad de ocurrencias para considerar la invalidéz del mínimo (o máximo) hallado; float ConsMin=100; // Consumo mínimo inicial. float ConsMAX=0; // Consumo máximo inicial. int VCO=-1; find GET_MAX=NO; for (int vel=5;vel<vel_max;vel++){ if(GET_MAX==SI){ // Si halle el maximo y if(GET_Min == 0){ // no encontré el Minimo. (Aun no halle la VCO) if (this->NAV_DATA[vel].LAST_NAV_DATA[cons_mile_p]<=ConsMin){ //La curva sigue decreciendo ConsMin=this->NAV_DATA[vel].LAST_NAV_DATA[cons_mile_p]; } else{ int vel2=0; float ConsMin2=0; n_events_eps=0; for (int eps=1; eps < Ratio_Min;eps++){ if (this->NAV_DATA[vel+eps].LAST_NAV_DATA[cons_mile_p]<=ConsMin) {//hay valores menores al minimo hallado en un entorno de v? n_events_eps++; if (n_events_eps==1){ ConsMin2=this->NAV_DATA[vel+eps].LAST_NAV_DATA[cons_mile_p]; vel2=vel+eps; } } } if (n_events_eps >= n_events_critical){ // falso minimo (hay muchos valores menores al minimo hallado) ConsMin=ConsMin2; vel=vel2; // nueva ubicación del minimo } else { GET_Min=1; VCO=vel-1; } } } } else{ if (this->NAV_DATA[vel].LAST_NAV_DATA[cons_mile_p]>=ConsMAX){ //La curva sigue creciendo o se mantiene cte. ConsMAX=this->NAV_DATA[vel].LAST_NAV_DATA[cons_mile_p]; GET_MAX=POSIBLE; } else{ n_events_eps=0; float ConsMAX2=0; if (GET_MAX==POSIBLE){ int vel2=0; for (int eps=1; eps<Ratio_Min;eps++){ if (this->NAV_DATA[vel+eps].LAST_NAV_DATA[cons_mile_p]>ConsMAX) {//hay valores mayores al maximo hallado en un entorno de v? n_events_eps++; if (n_events_eps==1){ ConsMAX2=this->NAV_DATA[vel+eps].LAST_NAV_DATA[cons_mile_p]; vel2=vel+eps; } } } if (n_events_eps > n_events_critical) { // falso maximo (hay muchos valores mayores al maximo hallado) vel=vel2; // nueva ubicación del maximo siguiente ConsMAX=ConsMAX2; } else { GET_MAX=SI; VCC[1]=vel-1; } } } } } VCC[0]=VCO; return VCC[0]; } //--------------------------------------------------------------------------------------------------------------------------------------- // performance: Devuelve un valor entre 0 y 1 que mide la performance a velocidad Vi. 1--> OPTIMO; 0=PESIMO; // Devuelve -1 si no se puede calcular; float VCODATA::performance(int Vi){ int vcc[2]; if( this->get_VCO(vcc)!=-1){ double cons_VCO=this->NAV_DATA[vcc[0]].LAST_NAV_DATA[cons_mile_p]; // VCO=VCC[0]; Consumo@VCO. double cons_VMC=this->NAV_DATA[vcc[1]].LAST_NAV_DATA[cons_mile_p]; // VMC=VCC[1]; Consumo@Velocidad de Maximo Consumo. double cons_Vi= this->NAV_DATA[Vi].LAST_NAV_DATA[cons_mile_p]; // Consumo@Vi. float PERF=(cons_Vi-cons_VCO)/(cons_VMC-cons_VCO); if ((cons_VMC-cons_VCO)!=0){ if ( PERF<0)return -1; else if (PERF>1) return 0; return (1-PERF); } else return -1; } else return -1; } //--------------------------------------------------------------------------------------------------------------------------------------- //interpolate(): Interpola los valores de consumo para completar la curva. void VCODATA::interpolate(){ int x_P1=0;//this->get_next_P(0); int x_P2=this->get_next_P(x_P1); while (x_P2>0 ) { // Puntos validos? (Si es no válido get_next devuelve -1). if ( x_P2>x_P1+1) this->interp_x1_x2(x_P1, x_P2); // Interpola entre los 2 puntos dados. x_P1=x_P2; x_P2=this->get_next_P(x_P1); } } //--------------------------------------------------------------------------------------------------------------------------------------- //get_next_P(int x_value): Retorna la ordenada del siguiente valor recolectado, que no es resultado de la interpolacion. int VCODATA::get_next_P(int x_value){ //int i=1; int j=x_value+1; while (j<this->vel_max){ if ( this->NAV_DATA[j].LAST_NAV_DATA[cons_mile_p] <=0 || this->NAV_DATA[j].LAST_NAV_DATA[cons_interpolated] != 0) j++; // Avanzar mientras haya valores ya interpolados, nulos, o -1 (caso de distancia recorrida nula-->0 milla) else break; } if (j==this->vel_max)return(-1); // Llego al final sin hallar punto válido. else return(j); } //--------------------------------------------------------------------------------------------------------------------------------------- //interp_x1_x2(int x1,int x2): Interpola la matríz de datos tomando puntos de la recta que pasa por x1 y x2 void VCODATA::interp_x1_x2(int x1,int x2){ double step=(this->NAV_DATA[x2].LAST_NAV_DATA[cons_mile_p] - this->NAV_DATA[x1].LAST_NAV_DATA[cons_mile_p])/(x2-x1); // Pendiente: A for (int i=x1+1; i<x2; i++){ this->NAV_DATA[i].LAST_NAV_DATA[cons_mile_p]= (i-x1)*step + this->NAV_DATA[x1].LAST_NAV_DATA[cons_mile_p]; // Y= Ax + B this->NAV_DATA[i].LAST_NAV_DATA[cons_interpolated]=1; } } //--------------------------------------------------------------------------------------------------------------------------------------- //merge_data(NAVDATA LastVector): Modifica los valores del array LAST_NAV_DATA del objeto almacenado en la ultima posicion de NAV_DATA, // combinándolos con LastVector. int VCODATA::merge_data(NAVDATA LastVector){ // El ultimo vector se guarda y se va concatenando el siguiente, si corresponde. Puede evaluarse dejar siempre los últimos valores en vez del promedio. // El valor que se almacena en la matriz, siempre es la consolidacion del último vector guardado con el recientemente ingresado. //(2)if ((this->NAV_DATA[vel_max].LAST_NAV_DATA[time_f]>this->NAV_DATA[vel_max].LAST_NAV_DATA[time_i]) &&(this->NAV_DATA[vel_max].LAST_NAV_DATA[distance_p]!=0)){ //Chequeos de tiempos y distancia validos. if ((LastVector.LAST_NAV_DATA[time_f]>this->NAV_DATA[vel_max].LAST_NAV_DATA[time_f]) &&(this->NAV_DATA[vel_max].LAST_NAV_DATA[distance_p]!=0)){ //(2)Chequeos de tiempos y distancia validos. this->NAV_DATA[vel_max].LAST_NAV_DATA[longitude_f]=LastVector.LAST_NAV_DATA[longitude_f]; // Longitud, latitud y tiempo_f se reemplazan directamente. this->NAV_DATA[vel_max].LAST_NAV_DATA[latitude_f]=LastVector.LAST_NAV_DATA[latitude_f]; this->NAV_DATA[vel_max].LAST_NAV_DATA[time_f]=LastVector.LAST_NAV_DATA[time_f]; this->NAV_DATA[vel_max].LAST_NAV_DATA[distance_p]+=LastVector.LAST_NAV_DATA[distance_p]; // Distancia se suma a la anterior para luego usarla al promediar el consumo //(1)this->NAV_DATA[vel_max].LAST_NAV_DATA[speed_p]=(this->NAV_DATA[vel_max].LAST_NAV_DATA[speed_p] + LastVector.LAST_NAV_DATA[speed_p])/2; //Promedio de velocidades; this->NAV_DATA[vel_max].LAST_NAV_DATA[speed_p]=this->NAV_DATA[vel_max].LAST_NAV_DATA[distance_p]/(this->NAV_DATA[vel_max].LAST_NAV_DATA[time_f]-this->NAV_DATA[vel_max].LAST_NAV_DATA[time_i]); //(1) Recaculo (periodos concatenados) this->NAV_DATA[vel_max].LAST_NAV_DATA[consumption_f]=LastVector.LAST_NAV_DATA[consumption_f]; // Actualizacion de contador del flujometro this->NAV_DATA[vel_max].LAST_NAV_DATA[consumption_p]+=LastVector.LAST_NAV_DATA[consumption_p]; // El consumo del período se suma al anterior al extenderse el mismo. //this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_mile_p]=(LastVector.LAST_NAV_DATA[cons_mile_p]+this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_mile_p])/2; //Promedio-->Evaluar recalcular en base a los otros datos. //this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_hour_p]=(LastVector.LAST_NAV_DATA[cons_hour_p]+this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_hour_p])/2; //Promedio-->Evaluar recalcular en base a los otros datos. ; this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_mile_p]=this->NAV_DATA[vel_max].LAST_NAV_DATA[consumption_p]/this->NAV_DATA[vel_max].LAST_NAV_DATA[distance_p]; // Fusion de periodos=>Consumo de ambos periodos / Distancia de ambos periodos. this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_hour_p]=this->NAV_DATA[vel_max].LAST_NAV_DATA[consumption_p]/(this->NAV_DATA[vel_max].LAST_NAV_DATA[time_f]-this->NAV_DATA[vel_max].LAST_NAV_DATA[time_i]); // Fusion de periodos=> Consumo de ambos periodos( //this->NAV_DATA[vel_max].LAST_NAV_DATA[cons_interpolated]=0; return 0; } else return -1; // Los datos no son válidos. (Division por 0). } //--------------------------------------------------------------------------------------------------------------------------------------- // smooth(int n_dots,VCODATA &REFERENCE_MTRX): Suaviza la curva discreta, promediando n puntos del entorno de cada punto. // REFERENCE_MTRX resultara ser una copia suavizada de esta matríz (this). void VCODATA::smooth(int n_dots,VCODATA &REFERENCE_MTRX){ int n_int=int (n_dots/2); int n_dif_l=0; // Valor para sesgar el entorno de promediado, respecto de la posicion actual, en caso de n par. if ((n_dots%n_int)==0)n_dif_l=1; // si n es par entonces tomo una muestra menos del lado derecho. Elijo esta forma porque // esto cambio....>> // al discretizar la curva hemos redondeado hacia abajo los valores de velocidad; esto significa que el // valor de consumo asociado a una velocidad fue desplazado hacia la izquierda, por lo tanto, promediandolo // con valores corresp. a velocidades con cierto sesgo hacia izquierda, mejora la representación y mas aún // con respecto al caso opuesto. Debe pensarse estadisticamente teniendo en cuenta que // la media de cada periodo de velocidades se encuentra en el medio del período. Ejemplo: // | c1 c3 // | cm12 // | c2 // |__x1________xm12_x2__________x3 vemos que el valor real de velocidad de xm12 es mas cercano a x2 que el real de c2. for (int j=0;j<vel_max;j++){ float sum_cons=0; int n_samp=0; this->NAV_DATA[j]=REFERENCE_MTRX.NAV_DATA[j]; // Copia de objetos NAVDATA for (int i=-n_int;i<=n_int-n_dif_l;i++){// si es impar va desde (n-1)/2 muestras a la izq, la propia muestra y (n-1)/2 muestras a la deracha. // si es par reduce una muestra a la derecha. (n/2) a izq, la propia y n/2-1 a derecha. if (j+i>=0 && j+i<vel_max){ // para excluir valores de velocidad fuera de rango. (extremos) n_samp++; sum_cons+= REFERENCE_MTRX.NAV_DATA[i+j].LAST_NAV_DATA[cons_mile_p]; } } if (n_samp>0){ this->NAV_DATA[j].LAST_NAV_DATA[cons_mile_p]= sum_cons/n_samp; this->NAV_DATA[j].LAST_NAV_DATA[cons_interpolated]=2; // 2: Valor promediado. } } }