Latest changes without errors

Dependents:   SNOCC_V1 SNOCC_V2

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

                        
                }        
}