SourceForge.net Logo timeSeries: timeSeries Class Library

campVIRTTEXAnalysis.cpp

CAMP FCW trial analysis, updated for VIRTTEX implementation

The VIRTTEX analysis is based on the program written for the NADS data by me in 2004. However, it is different in three key respects:

1) The VIRTTEX sessions contain up to 34 trial runs per data file. The NADS data had one trial run per data file. This program uses the facilities in the stateflag classes to segment the data.

2) The VIRTTEX trials contain some additional factors related to visual resolution. These are recorded in the output files for future ANOVA's

3) The code and style have been updated to the current version of the timeSeries class library

-- Jeff Greenberg May, 2005

Copyright Jeff Greenberg.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <vector>
#include <limits>

using namespace std;
#include "dataFrame.h"
#include "dataFile.h"
#include "timeSeries.h"
#include "timeSeriesArray.h"
#include "lookupTable.h"
#include "TTC2.h"
#include "filter.h"
#include "measures.h"
#include "stateFlag.h"

#include "camp_utilities.h"

using namespace std;

const double MPHPERFPS=0.68182;
const double FTPERMETER=3.28084;
const double NoCrash = 999.99;

std::vector<measures>  process_file(dataFile& data,  lookupTable& t, string& s);

iir_t *init_lowpass_20();
iir_t *init_lowpass_50();
iir_t *init_cheby1_20();
iir_t *init_cheby1_50();

dataFile openDataFile(std::string fileName,int filenum,int argc);

template <class T>
void filtfilt(iir_t *lpf,timeSeries<T>& POVspeed_filt);

template <class T>
int findBrakingReactionFrame(timeSeries<T> SVaccel,
                             timeSeries<T> SVspeed, 
                             timeSeries<T> throttle, 
                             timeSeries<T> brake);

template <class T>
int findSteeringReactionFrame(timeSeries<T> SVaccel,
                              timeSeries<T> swavel, 
                              timeSeries<T> swa,
                              timeSeries<T> lanePos, 
                              timeSeries<T> SVYawRate);

void outputMeasures(const std::string& measuresFile,
                    const std::string& headerFile,
                    const std::vector<measures>& dependentMeasures,
                    const int filenum);

vector<state> findAllLevels(stateFlag& sf);
vector<state> findAllScenarios(stateFlag& sf);
vector<state> validScenarios(vector<state>& s,
                             timeSeries<float>& subno,
                             stateFlag& kin,
                             timeSeries<int>& mode,
                             timeSeries<int>& effort,
                             timeSeries<int>& res,
                             timeSeries<int>& aa);
bool sameScenario(state& s1, state& s2,                              
                  stateFlag& kinematic_cond,
                  timeSeries<int>& mode,
                  timeSeries<int>& effort,
                  timeSeries<int>& resolution,
                  timeSeries<int>& aa);
    
string computeSubjectNo(timeSeries<float> subj);
string intToCondition(const int c);
string intToResolution(const int c);
string intToAA(const int c);

float sampleTime(string s);

#ifdef WIN32
string convertLink(const char *fname);
int analysisMain (int argc, char *  argv[])
#else
int main (int argc, char *  argv[])
#endif
{   // get files from the command line
    vector<string> fileList = parseFileList(argc, argv);
    int nFiles = fileList.size();
    
    // define a lookup table for subject meta-data
    string subjectTablePath="subject_data.txt";
    
    try {
        static lookupTable subjectTable(subjectTablePath,"Subject");
        
        for (int filenum=0;filenum<nFiles;++filenum) {
            try {
                string dataFileName = fileList[filenum];
                dataFile data = openDataFile(dataFileName, filenum+1, nFiles);
                vector<measures> dependentMeasures=process_file(data,subjectTable,
                                                                dataFileName);
                outputMeasures(dataFileName,
                               "camp_virttex.tit",      // label file name
                               dependentMeasures,
                               filenum+1);
            }
            // these are all errors that cause us to skip a data file
            // but not abort the run
            catch (tsException& tse) {
                tse.debug_print();
                cerr << "skipping to next file..." << endl;
            }
            catch (dataFile::dataInputExceptions& die) {
                die.debug_print();
                cerr << "skipping to next file..." << endl;
            }
            catch (lookupTable::lookupExceptions& lookupError) {
                lookupError.debug_print();
                cerr << "skipping to next file..." << endl;
            }
        }
    }
    catch (lookupTable::lookupExceptions& lookupError) {
        // if we can't read a lookup file we have to just exit
        lookupError.debug_print();
        exit(1);
    }           
}

dataFile openDataFile(string fileName,int nFile,int maxFiles) {
    //const double Ts=0.05;
#ifdef WIN32
    fileName=convertLink(fileName.c_str());
#endif
    
    dataFrame expDataFrame(removePathExt(fileName)+".hdr");
    string dataFileName(removePathExt(fileName)+".bin");
    cout << endl;
    cout << "reading file " << dataFileName << " " << nFile << " of ";
    cout << maxFiles << "..." << flush;
    
    //open the header file and get the sample time
    float Ts = sampleTime(removePathExt(fileName)+".hdr");
    // load the entire data file into memory
    
    dataFile data(fileName,expDataFrame,Ts,dataFile::BigEndian);
    cout << "done" << endl;
    
    return data;
}

vector<measures> process_file(dataFile& data, lookupTable& subjectTable, 
                              string& filename)
{       
    // get the variables we're interested in
    
    timeSeries<float> tapa("TAPA",data);
    // remove the closed plate angle from the throttle position
    float minTap = tapa[tapa.min()];
    timeSeries<float> throttle = tapa - minTap;
    
    // create an aggregate braking torque
    timeSeries<float> b1("BRKTQ(1)",data);
    timeSeries<float> b2("BRKTQ(2)",data);
    timeSeries<float> b3("BRKTQ(3)",data);
    timeSeries<float> b4("BRKTQ(4)",data);
    timeSeries<float> brake = (b1+b2+b3+b4)/4.0;
    
    timeSeries<float> steerin("STEERIN",data);
    // VIRTTEX has a -2.5deg bias in the steering
    // correct it out here
    //timeSeries<float> swa = steerin - steerin.mean();
    timeSeries<float> swa = steerin;
    
    timeSeries<float> pov_xpos("POV_XPOS",data);    // pov position in feet
    timeSeries<float> sv_xpos("VEHYPOS",data);      // sv posiition in meters
    const float bumper_offset=15.2;                 //avg of 3 test runs in VIRTTEX
    timeSeries<float> range = pov_xpos - sv_xpos*FTPERMETER - bumper_offset;

    timeSeries<float> SVYawRate("VEHOMEGAZ",data);
    timeSeries<float> lanepos("LANEPOS",data);

    // calculate steering wheel velocity
    
    timeSeries<float> swavel = swa.differentiate();
    timeSeries<float> swavel_f = swavel;
    
    int sampleRate = int(floor((1.0/swavel.sampleTime()) + 0.5));
    iir_t *lpf;
    if (sampleRate == 20) {
        lpf = init_cheby1_20();
    } else {
        lpf = init_cheby1_50();
    }
    filtfilt(lpf, swavel_f);
    free_iir_filter(lpf);               // free the filter
    
    // the SVaccel is in ft/s, since this is (mostly) what NADS uses. We'll keep to ft 
    // and s for the kinematics here to be consistent
    timeSeries<float> accelx("VEHRPACCELX",data);
    timeSeries<float> SVaccel = accelx*FTPERMETER;
    
    timeSeries<float> vmph("VMPH",data);
    timeSeries<float> SVspeed = vmph/MPHPERFPS;
    
    timeSeries<float> POVspeed("POV_SPEED",data);
    
    // POV accel is not directly available, so once again, we calculate it.
    // Use a 10Hz, acausal, phaseless filter to smooth POVspeed first, since the NADS 
    // SCC objects are updated at a much lower sample frequency 
    timeSeries<float>POVspeed_filt = POVspeed;
    if (sampleRate == 20) {
        lpf = init_lowpass_20();
    } else {
        lpf = init_lowpass_50();
    }
    filtfilt(lpf,POVspeed_filt);
    timeSeries<float>POVaccel = POVspeed_filt.differentiate();
    free_iir_filter(lpf);
    
    // extract the lateral lane position
    timeSeries<float>SVLatLanePos = lanepos*FTPERMETER;

        
    int reactionFrame;
    timeSeries<float> accely("VEHRPACCELY",data);
    timeSeries<float> SVLatAccel = accely*FTPERMETER;

    stateFlag scenarioFlag = getVirttexStateFlag("SCENARIO_NUMBER",data);
    timeSeries<float> effort_float("EFFORT",data);
    //timeSeries<int> effort = timeSeries<int>(effort_float);
    timeSeries<int> effort = effort_float;
    timeSeries<float> scenario_type_float("SCENARIO_TYPE",data);
    timeSeries<int> scenario_type = timeSeries<int>(scenario_type_float);
    timeSeries<float> resolution_float("RESOLUTION",data);
    timeSeries<int> resolution = timeSeries<int>(resolution_float);
    timeSeries<float> aa_float("AA",data);
    timeSeries<int> aa = timeSeries<int>(aa_float);
    timeSeries<float> subno("SUBNO",data);
    
    string subject = computeSubjectNo(subno);
    cout << "subject " << subject << endl;
    
    // iterate over the scenarios in the experiment and compute the relavent 
    // measures
    
    string subjectType = subjectTable.find<string>(subject,"Mode");
    cout << "test mode: " << subjectType << endl;
    
    string gender = subjectTable.find<string>(subject,"Gender");
    string ageGroup = subjectTable.find<string>(subject,"Age");
    
    cout << "gender = " << gender << endl;
    cout << "age = " << ageGroup << endl;
    
    string motionType = subjectTable.find<string>(subject,"Motion");
    
    vector<measures> event_measures;
    vector<state> scenarios;
    // if a '.scn' file exists read the scenario state definitions from there
    // otherwise figure them out from the data file
    
    string scnFileName = removePathExt(filename)+".scn";
    ifstream scnFile(scnFileName.c_str(),ios::in);
    if (scnFile.is_open()) {
        state s(0,0);
        while (!scnFile.eof()) {
            scnFile >> s;
            scenarios.push_back(s);
        };
    } else {
        vector<state> allScenarios = findAllScenarios(scenarioFlag);
        // prune out duplicates and test runs before beginning the analyis
        
        scenarios = validScenarios(allScenarios,subno,scenarioFlag,scenario_type,
                                                 effort,resolution,aa);
    }
    
    if (getPrintState()) {
        cout << "============================" << endl;
        for (int i=0;i<scenarios.size();i++) {
            cout << scenarios[i] << endl;
        }
        cout << "============================" << endl;
    }
    
    for (int ns=0;ns<scenarios.size();ns++) {
         
        int endIndex = scenarios[ns].end();
        bool brakingTrial = (scenario_type[endIndex] == 0);
        
        
        if (brakingTrial) {
            reactionFrame = findBrakingReactionFrame(SVaccel.range(scenarios[ns]),
                                                     SVspeed.range(scenarios[ns]),
                                                     throttle.range(scenarios[ns]),
                                                     brake.range(scenarios[ns]));
        } else {
            reactionFrame = findSteeringReactionFrame(SVLatAccel.range(scenarios[ns]),
                                                      swavel.range(scenarios[ns]),
                                                      swa.range(scenarios[ns]),
                                                      SVLatLanePos.range(scenarios[ns]), 
                                                      SVYawRate.range(scenarios[ns]));
        }
        
        cout << (brakingTrial ? "braking " : "steering ") << "onset frame= " ;
        cout << reactionFrame << endl;
        
        int scenario_number = scenarioFlag[endIndex];
        bool stationaryTrial = (scenario_number >= 15) && (scenario_number <= 17);
        bool decelTrial = (scenario_number >= 1) && (scenario_number <= 9);
        bool constantDeltaV = (scenario_number >= 10) && (scenario_number <= 14);
        string instruction = (effort[endIndex] ? "hard" : "normal");
        
    // Calculates TTC2
        double ttc;
        try {
            ttc = TTC2(SVspeed[reactionFrame],
                    POVspeed[reactionFrame],                
                    0.0,        //SVaccel
                   (decelTrial ? POVaccel[reactionFrame] : 0.0),
                    range[reactionFrame]);
        }
        catch (TTC::TTCExceptions& ttce) {
            ttc = measures::MISSING;
        }
        
        if (ttc == NoCrash) ttc = measures::MISSING;

    // Looking for mininum TTC2 from onset reactionFrame to end of run 
        int i, finalFrame, finalFrameLC;
        double tmp2, minttc2;
        double min_seen2 = numeric_limits<double>::max();

        if(brakingTrial) {
            finalFrame = scenarios[ns].end();
        }
        else {
            timeSeries<float> lp = lanepos.range(reactionFrame,scenarios[ns].end());
            const float minLC = 1.5;        // lane pos to just clear the POV
            finalFrameLC = find(lp<= minLC).front();
            finalFrame = finalFrameLC;
        }
        for (i = reactionFrame; i < finalFrame; ++i){
            try {
                tmp2 = TTC2(SVspeed[i],     //calls TTC2 function in TTC2.cpp program
                        POVspeed[i],
                        0.0,    //SVaccel
                        (decelTrial ? POVaccel[reactionFrame] : 0.0),
                        range[i]);
            }
            catch (TTC::TTCExceptions& ttce) {
                break;      //if an exception error is found break out of for loop
            }
            if (tmp2 < min_seen2) { 
                min_seen2 = tmp2;
            }
        }       // iterating for minimum TTC2 here
        minttc2 = min_seen2;
        if (minttc2 == NoCrash) minttc2 = measures::MISSING;

    // calculates TTC1 and InvTTC1
        double ttc1, inv_ttc1;  

        ttc1 = range[reactionFrame]/(SVspeed[reactionFrame] - POVspeed[reactionFrame]);
        inv_ttc1 = 1/ttc1;

    // Looking for mininum TTC1 from onset reactionFrame to end of run
        double tmp1, minttc1;
        double min_seen1 = numeric_limits<double>::max();

        if(brakingTrial) {
            finalFrame = SVspeed.getMaxIndex();
        }
        else {
            finalFrame = finalFrameLC;
        }
        for (i = reactionFrame; i < finalFrame; ++i){
            try {
                tmp1 = TTC2(SVspeed[i],     //calls TTC2 function in TTC2.cpp program
                            POVspeed[i],
                            0.0,    //SVAccel
                            0.0,    //POVAccel
                            range[i]);
            }
            catch (TTC::TTCExceptions& ttce) {
                break;      //if an exception error is found break out of for loop
            }
            if (tmp1 < min_seen1) { 
                min_seen1 = tmp1;
            }
        }       // iterating for minimum TTC1 here
        minttc1 = min_seen1;
        if (minttc1 == NoCrash) minttc1 = measures::MISSING;
        
        // Calculates Required Deceleration
        const double SystemDelay=0.0;
        double reqDec;
        try {
            reqDec= requiredDecel(SystemDelay,
                                  SVspeed[reactionFrame],
                                  POVspeed[reactionFrame],
                                  0.0,  //SVaccel
                                  (decelTrial ? POVaccel[reactionFrame] : 0.0),
                                  range[reactionFrame])/32.174; // converted to "g's"
        }
        catch (TTC::TTCExceptions& ttce) {
            reqDec = measures::MISSING;
        }
        

    // Initial Headway @ POV Deceleration = -0.1 g 
        int priorToOnsetFrame;
        vector<int> onsetIndx;
        double Treact, initHdwyRange=0.0, initHdwyTime = 0.0;
        double initSVHdwySpeed, initPOVHdwySpeed;
        if (decelTrial) {
            Treact = POVaccel.time(reactionFrame); 
            timeSeries<float> POVbeforeOnset = POVaccel.range(Treact-7.0,Treact); 
            onsetIndx = find(POVbeforeOnset < -0.1*32.174);
            if (onsetIndx.size() == 0) { 
                cout << "POV is flat over range & SV onset occurs before POV onset.";
                cout << endl;
                continue;
            } else {
                priorToOnsetFrame = onsetIndx.front();      
                initHdwyRange = range[priorToOnsetFrame]; 
                initHdwyTime =  range[priorToOnsetFrame]/SVspeed[priorToOnsetFrame]; 
            }
        }    

    // Calculates Peak Deceleration during braking/steering maneuver 
    // from reactFrame to end of maneuver
        double pkDecel=0.0;  
        int pkDecelFrame; 

        if(brakingTrial) {      // finds maximum longitudinal braking acceleration
            finalFrame = scenarios[ns].end();
            pkDecelFrame = SVaccel.range(reactionFrame,finalFrame).min();
            pkDecel = SVaccel[pkDecelFrame]/32.174;
        }
        else {      // finds maximum lateral steering deceleration
            finalFrame = finalFrameLC;
            pkDecelFrame = SVLatAccel.range(reactionFrame,finalFrame).min();
            pkDecel = SVLatAccel[pkDecelFrame]/32.174;
        }
        
        // find minimum range
        
        double minRange =  numeric_limits<double>::max();
        if (brakingTrial) {
            finalFrame = scenarios[ns].end();
        } else {
            finalFrame = finalFrameLC;
        }
        
        for (i=reactionFrame;i<finalFrame;i++) {
            if (range[i] < minRange) {
                minRange = range[i];
            }
        }

        string condition = intToCondition(scenario_number);
        string res = intToResolution(resolution[scenarios[ns].end()]);
        string antialias = intToAA(aa[scenarios[ns].end()]);
        cout << condition << endl;
        cout << instruction << " " << res << " " << antialias << endl;
        cout << "TTC1 = " << ttc1 << "  InvTTC1 = " << inv_ttc1 << endl;    
        cout << "minTTC1= " << minttc1 << " minTTC2= " << minttc2 << endl;
        cout << "TTC2= " << ttc  << endl;
        cout << "Initial headway = " << initHdwyRange << " ft";
        cout << " Peak Dec= " << pkDecel << " g's" << endl;
        cout << "rDec=" << reqDec << " g's"  << endl;
        cout << endl << flush;
        
        // create the measures
        
        measures meas;
        
        meas.entry("subno", subject);
        meas.entry("subtype",subjectType);
        meas.entry("filename",getLeafName(filename));
        meas.entry("gender",gender);
        meas.entry("age",ageGroup);
        meas.entry("condition", condition);
        meas.entry("instruction", instruction);
        meas.entry("mode",(brakingTrial ? "brake" : "steer"));
        string kinType;
        if (stationaryTrial) {
            kinType = "stationary";
        } else if (decelTrial) {
            kinType = "decel";
        } else {
            kinType = "constdv";
        }
        meas.entry("kintype",kinType);
        meas.entry("resolution",res);
        meas.entry("antialias",antialias);
        meas.entry("motion",motionType);
        meas.entry("reactionTime",SVspeed.time(reactionFrame));
        meas.entry("reqdec",reqDec);
        meas.entry("TTC2",ttc);
        meas.entry("SVspeed",SVspeed[reactionFrame]);
        meas.entry("POVspeed",POVspeed[reactionFrame]);
        meas.entry("SVaccel",SVaccel[reactionFrame]);
        meas.entry("POVaccel",(decelTrial ? POVaccel[reactionFrame] : 0.0));
        meas.entry("Range", range[reactionFrame]);
        meas.entry("minRange",minRange);
        meas.entry("minTTC2", minttc2);
        float SVspdinit;
        float POVspdinit;
        if (decelTrial) {
            if (onsetIndx.size() == 0) {
                initHdwyRange = measures::MISSING;
                initHdwyTime = measures::MISSING;
                SVspdinit = SVspeed[reactionFrame]*MPHPERFPS;
                POVspdinit = POVspeed[reactionFrame]*MPHPERFPS;
            } else {
                SVspdinit = SVspeed[priorToOnsetFrame]*MPHPERFPS;
                POVspdinit = POVspeed[priorToOnsetFrame]*MPHPERFPS;
            }
        } else {
            initHdwyRange = measures::MISSING;
            initHdwyTime = measures::MISSING;
            SVspdinit = measures::MISSING;
            POVspdinit = measures::MISSING;
        }
        meas.entry("initHdwyRange", initHdwyRange);
        meas.entry("initHdwyTime", initHdwyTime);
        meas.entry("SVspdinit", SVspdinit);
        meas.entry("POVspdinit", POVspdinit);
        meas.entry("peakDec",pkDecel);
        
        if (ttc1 < 0) {                 // negative TTC1 cases are undefined
            ttc1 = measures::MISSING;
            inv_ttc1 = measures::MISSING;
            minttc1 = measures::MISSING;
        }
        
        meas.entry("TTC1",ttc1);
        meas.entry("InvTTC1",inv_ttc1);
        meas.entry("minTTC1",minttc1);      
        // save this measures object
        event_measures.push_back(meas);
    }
    return event_measures;
}

/* lowpass_20 is a 3rd order butterworth filter with a break
   frequency at 9 Hz, sampling freq. at 20 Hz
*/

iir_t *init_lowpass_20()
    { double coeff[][6]= {
    {1, 1.00000959440837, 0, 1, 0.726542528005365, 0},
    {1, 1.99999040559162, 0.999990405683675, 1, 1.64755221570399, 0.732338917272799}
    };
    double gain=0.729440722639082;
    iir_t *f;

    f=init_iir_filter(coeff, gain, 2);

    return f;
}

/* lowpass_50 is a 3rd order butterworth filter with a break
frequency at 10 Hz, sampling freq. at 50 Hz
*/

iir_t *init_lowpass_50()
    { double coeff[][6]= {
    {1, 1.00000959440837, 0, 1, -0.158384440324536, 0},
    {1, 1.99999040559162, 0.999990405683675, 1, -0.418856084481767, 0.35544676217239}
    };
    double gain=0.098531160923927;
    iir_t *f;

    f=init_iir_filter(coeff, gain, 2);

    return f;
}
/* cheby1_20 is a 3rd order low pass Chebychev1 filter with a break frequency of
   5 hz and 1db of passband ripple, 20Hz sampling rate
*/


iir_t *init_cheby1_20()
{ double coeff[][6]= {
    {1, 1.00000959440837, 0, 1, -0.338535233784181, 0},
    {1, 1.99999040559162, 0.999990405683675, 1, -0.00465798986434177, 0.60281664390126}
    };
    double gain=0.13214070505854;
    iir_t *f;

    f=init_iir_filter(coeff, gain, 2);

    return f;
}

/* cheby1_50 is a 3rd order low pass Chebychev1 filter with a break frequency of
5 hz and 1db of passband ripple, 50Hz sampling rate
*/


iir_t *init_cheby1_50()
{ double coeff[][6]= {
    {1, 1.00000959440837, 0, 1, -0.723297433052849, 0},
    {1, 1.99999040559162, 0.999990405683675, 1, -1.41449248783418, 0.746246746816894}
    };
    double gain=0.0114746568820209;
    iir_t *f;

    f=init_iir_filter(coeff, gain, 2);

    return f;
}

/*
    The brake reaction time is defined as 70ms  prior to the
    point at which the SVaccel dips below 0.1g
 */

template <class T>
int findBrakingReactionFrame(timeSeries<T> SVaccel,
                             timeSeries<T> SVspeed,
                             timeSeries<T> throttle,
                             timeSeries<T> brake) 
{   const float bDelay = 0.167; // 167ms in CAMP but 70ms in virttex because
                                // our brakes are too fast  
    vector<int> bindx;
    
    // there can be big accel/decel spikes at the prndl transition so
    // start the search for the peak decel after the SV is safely in
    // motion
    bindx = find(SVspeed > 20.0/MPHPERFPS);
    int moving = bindx[0];
    int peak = SVaccel.range(moving,SVaccel.getMaxIndex()).min();

    // find the last throttle release prior to the peak decel
    bindx = find((throttle.range(moving,peak) > 0.05));
    int beg = bindx.back();
    
    // if this is a left-footed braker and still has the right foot on
    // the gas, give up and just set the window back an arbitrary 5s
    const float bthresh=2.0;
    if (brake[beg] > bthresh) {
        beg = SVaccel.index(SVaccel.time(beg) - 5.0);
    }
    // now find the first decel of more than 0.1 g's
    const double decelThresh = -0.1*32.0;
    bindx = find(SVaccel.range(beg,peak) < decelThresh);
    int j = bindx.front();
    
    // interpolate to find  the time at which SVaccel crossed thre threshold
    float deltaT = SVaccel.sampleTime();
    float deltaA = SVaccel[j] - SVaccel[j-1];
    float tcross = (deltaT/deltaA)*(decelThresh - SVaccel[j-1]) + SVaccel.time(j-1);
    tcross -= bDelay;
    
    return SVaccel.index(tcross);
}   

template <class T>
int findSteeringReactionFrame(timeSeries<T> SVLatAccel,
                              timeSeries<T> swavel, 
                              timeSeries<T> swa,
                              timeSeries<T> SVLatLanePos,
                              timeSeries<T> SVYawRate)
{   const double endingLanePos = 0;
    const double startingLanePos = 9.84;
    
    
    // find the point at which the SV is 60% of the way between lanes
    const double Pt60 = (0.4*startingLanePos+0.6*endingLanePos);
    vector<int> indx;
    indx = find(SVLatLanePos <= Pt60);
    int lane60 = indx.front();
    double t60 = SVLatLanePos.time(lane60);
    const double TswaRange=7.0;
    double t0 = t60 - TswaRange;
    
    // search in a time range beginning TswaRange seconds before
    // the 60% lane change point
    int minaccel = SVLatAccel.range(t0,t60).min();
    double Tminaccel = SVLatAccel.time(minaccel);
    
    // smooth out the swa velocity using a 5Hz acausal filter
    timeSeries<T> swav_f = swavel;
    int sampleRate = int(floor(1.0/swavel.sampleTime()+0.5));
    iir_t *lpf;
    if (sampleRate == 20) {
        lpf = init_cheby1_20();
    } else {
        lpf = init_cheby1_50();
    }
    filtfilt(lpf,swav_f);
    free_iir_filter(lpf);

    const double swaThresh = -6.5;
    //timeSeries<T> sv = swav_f.range(t0-10.0,Tminaccel);
    timeSeries<T> sv = swavel.range(t0-10.0,Tminaccel);
    timeSeries<T> sa = swa.range(t0-10.0,Tminaccel);
    vector<int> zerocross =  find((((sv>>1)*sv)<=0.0) && 
                                  (sv<=0.0) &&
                                  (sa>swaThresh));
    return zerocross.back();
}

void outputMeasures(const string& dataFileName,
                    const string& headerFileName,
                    const vector<measures>& dependentMeasures,
                    const int filenum)
{   // write the header file out the first time only
    if (filenum == 1) {
        ofstream headerFile(headerFileName.c_str(), ios::out);
        print_labels(headerFile,dependentMeasures[0]);
        headerFile.close();
    }
    string measFileName = removePathExt(dataFileName) + ".dat";
    ofstream mFile(measFileName.c_str(), ios::out);
    for (int i=0;i<dependentMeasures.size();i++) {
        mFile << dependentMeasures[i];
    }
    return;
    
}
// custom state detector that finds all level changes
vector<state> findAllLevels(stateFlag& sf) {
    vector<state> states;
    
    stateFlag::iterator<change> nextEdge;
    stateFlag::iterator<change> prevEdge;
    for (nextEdge=sf.begin<change>();nextEdge<sf.end<change>();) {
        prevEdge=nextEdge;
        state s(prevEdge.index(),(++nextEdge).index());
        states.push_back(s);
    }
    
    return states;
}

// custom state detector that finds all scenarios
//
// a scenario is defined by a rising transition to a value n
// followed by a falling edge transition to zero

vector<state> findAllScenarios(stateFlag& sf) {
vector<state> states;

stateFlag::iterator<rising> risingEdge;
stateFlag::iterator<falling> fallingEdge;
stateFlag::iterator<falling> lastFallingEdge = sf.end<falling>();
for (risingEdge=sf.begin<rising>(), fallingEdge=sf.begin<falling>();
     risingEdge < lastFallingEdge;
     ++risingEdge) {
    // find the first edge that falls to zero that follows
    // the rising edge
    while ((fallingEdge < risingEdge) || (*fallingEdge != 0)) {
        if (fallingEdge >= lastFallingEdge) {
            return states;
        }
        ++fallingEdge;
    }
    state s(risingEdge.index(),fallingEdge.index()-1);
    states.push_back(s);
}

return states;
}

string computeSubjectNo(timeSeries<float> subj) {
    stateFlag subState(subj);
    
    // histogram the subject numbers
    vector<state> subHist = findAllLevels(subState);
    
    // and then pick the subject number with the longest duration
    
    int subject;
    int duration = 0;
    for (int i=0;i<subHist.size();i++) {
        if ((subHist[i].length() > duration) && (subj[subHist[i].begin()] > 0)){
            duration = subHist[i].length();
            subject = subj[subHist[i].begin()];
        }
    }
    
    ostringstream subjectStr;
    subjectStr << subject;
    
    return subjectStr.str();
}

string intToCondition(const int c) {
    switch (c) {
        case 1 : return "30/30/15";
        case 2 : return "30/30/28";
        case 3 : return "30/30/39";
        case 4 : return "45/45/15";
        case 5 : return "45/45/28";
        case 6 : return "45/45/39";
        case 7 : return "60/60/15";
        case 8 : return "60/60/28";
        case 9 : return "60/60/39";
        case 10 : return "30/20/0";
        case 11 : return "30/10/0";
        case 12 : return "60/50/0";
        case 13 : return "60/30/0";
        case 14 : return "60/15/0";
        case 15 : return "30/0/0";
        case 16 : return "45/0/0";
        case 17 : return "60/0/0";
        default:
            cout << "error...condition out of range (" << c << ")" << endl;
            return "";
        break;
    }
}

vector<state> validScenarios(vector<state>& s,
                             timeSeries<float>& subno,
                             stateFlag& kin,
                             timeSeries<int>& mode,
                             timeSeries<int>& effort,
                             timeSeries<int>& res,
                             timeSeries<int>& aa) {
    vector<state> vs1;
    
        
    for (int i=0;i<s.size();i++) {
        bool delState = false;
        // if this scenario is the same as a future one
        // skip it
        
        for (int j=i+1;j<s.size();j++) {
            if (sameScenario(s[i],s[j],kin,mode,effort,res,aa)) {
                delState=true;
                break;
            }
        }
        
        // if this scenario is a test scenario
        // skip it
        if (subno[s[i].end()] <= 0) {
            delState=true;
        }
        
        if (!delState) {
            vs1.push_back(s[i]);
        }
    }
    
    return vs1;
}

bool sameScenario(state& s1, state& s2,                              
                  stateFlag& kinematic_cond,
                  timeSeries<int>& mode,
                  timeSeries<int>& effort,
                  timeSeries<int>& resolution,
                  timeSeries<int>& aa) {
    
    int k1 = kinematic_cond[s1.end()];
    int k2 = kinematic_cond[s2.end()];
    int m1 = mode[s1.end()];
    int m2 = mode[s2.end()];
    int e1 = effort[s1.end()];
    int e2 = effort[s2.end()];
    int r1 = resolution[s1.end()];
    int r2 = resolution[s2.end()];
    int a1 = aa[s1.end()];
    int a2 = aa[s2.end()];
    
    bool same = (k1 == k2) &&
                (e1 == e2) && 
                (m1 == m2) &&
                (r1 == r2) && 
                (a1 == a2);
        
    return same;
}

float sampleTime(string s) {
    ifstream hfile(s.c_str());
    if (!hfile.is_open()) {
        cout << "can't open file " << s << endl;
        exit(1);
    }
    
    float t0, tf, dt;
    hfile >> t0 >> tf >> dt;
    
    return dt;
}
    
string intToResolution(const int c) {
    string res;
    switch (c) {
        case 0:
            res = "1024x768";
        break;
            
        case 1:
            res = "1600x1200";
        break;
            
        case 2:
            res = "2048x1536";
        break;
        
        default:
            cout << "unknown resolution: " << c << endl;
            res = "error";
        break;
    }
    
    return res;
}

string intToAA(const int c) {
    string aa;
    switch (c) {
        case 0:
            aa = "2x2";
        break;
        
        case 1:
            aa = "8x8";
        break;
            
        default:
            cout << "unknown antialiasing: " << c << endl;
            aa = "error";
        break;
    }
    return aa;
}

Generated on Tue Mar 16 15:10:49 2010 for timeSeries by  doxygen 1.6.3