Akifumi Takahashi / CubicSpline

Fork of TRP105F_Spline by Akifumi Takahashi

CubicSpline.c

Committer:
aktk
Date:
2016-05-20
Revision:
4:8db89b731133
Parent:
3:75f50dbedf1b
Child:
6:c4f36cee3ceb

File content as of revision 4:8db89b731133:

#define DEBUG
#include "TRP105F_Spline.h"
#include <cmath>

//  To get voltage of TRP105F
AnalogIn g_Sensor_Voltage(p16);
//  To get sample distance via seral com
Serial g_Serial_Signal(USBTX, USBRX);

LocalFileSystem local("local");  // マウントポイントを定義(ディレクトリパスになる)
// for debug
#ifdef DEBUG
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
#endif

CubicSpline2d::CubicSpline2d()
    :_Data_Input_Type(SYSTEM)
{
    _Sample_Num = 5;
    _Sample_Set = (Vxyt  *)malloc(_Sample_Num * sizeof(Vxyt));
    //_u_param    = (double*)malloc(_Sample_Num * sizeof(double));
    for(int i = 0; i < _4; i++) {
        _C_x[i] = (double*)malloc((_Sample_Num - 1)* sizeof(double));
        _C_y[i] = (double*)malloc((_Sample_Num - 1) * sizeof(double));
    }
    //calibrateSensor();
}

CubicSpline2d::CubicSpline2d(
    unsigned int arg_num
)
    :_Data_Input_Type(SYSTEM)
{
    _Sample_Num = arg_num;
    _Sample_Set = (Vxyt  *)malloc(_Sample_Num * sizeof(Vxyt));
    //_u_param    = (double*)malloc(_Sample_Num * sizeof(double));
    for(int i = 0; i < 4; i++) {
        _C_x[i] = (double*)malloc((_Sample_Num - 1) * sizeof(double));
        _C_y[i] = (double*)malloc((_Sample_Num - 1) * sizeof(double));
    }
    //calibrateSensor();
}

CubicSpline2d::CubicSpline2d(
    unsigned int    arg_num,
    UseType         arg_useType
)
    :_useType(arg_useType)
{
    _Sample_Num = arg_num;
    _Sample_Set = (Vxyt  *)malloc(_Sample_Num * sizeof(Vxyt));
    //_u_param    = (double*)malloc(_Sample_Num * sizeof(double));
    for(int i = 0; i < 4; i++) {
        _C_x[i] = (double*)malloc((_Sample_Num - 1) * sizeof(double));
        _C_y[i] = (double*)malloc((_Sample_Num - 1) * sizeof(double));
    }
    //calibrateSensor();
}

CubicSpline2d::~CubicSpline2d()
{
    free(_Sample_Set);
    //free(_u_param);
    for(int i = 0; i < 4; i++) {
        free(_C_x[i]);
        free(_C_y[i]);
    }
}

unsigned short CubicSpline2d::getDistance()
{
    int idx;
    unsigned short pv = 0;

    //  low-pass filter
    for(int i = 0; i < 10; i++)
        pv += g_Sensor_Voltage.read_u16() / 10;

    idx = _getNearest(_LIDX, _RIDX, pv);

    if (idx != 0xFFFF)    //  unless occuring error
        return _Set[idx].dst;
    else
        return 0xFFFF;
}


void CubicSpline2d::_sampleData()
{
    int     tmp;
    char    sig;
    Vxyt    tmp_set;

    //  For evry set,
    //  1, get dst data via serai com,
    //  2, get vol data,
    //  and then do same for next index set.
    for(int i = 0; i < _Sample_Num; i++) {
        if(_useType == AsDebug) {
            //
            //  Recieve a Distance datus and store it into member
            //
            g_Serial_Signal.printf("X:");
            _Sample_Set[i].x = 0;
            do {
                sig = g_Serial_Signal.getc();
                if('0' <= sig && sig <= '9') {
                    _Sample_Set[i].x = 10 * _Sample_Set[i].x + sig - 48;
                    g_Serial_Signal.putc(char(sig));
                } else if(sig == 0x08) {
                    _Sample_Set[i].x = 0;
                    g_Serial_Signal.printf("[canseled!]");
                    g_Serial_Signal.putc('\n');
                    g_Serial_Signal.putc('>');
                }
            } while (!(sig == 0x0a || sig == 0x0d));
            g_Serial_Signal.putc('\n');
            //
            //  Recieve a Voltage datus and store it into member
            //
            //  LOW PASS FILTERED
            //  Get 10 data and store mean as a sample.
            //  After get one original sample, system waits for 0.1 sec,
            //  thus it takes 1 sec evry sampling.
            _Sample_Set[i].y = 0;
            for(int j = 0; j < 10; j++) {
                tmp_set.y = g_Sensor_Voltage.read();
#ifdef DEBUG
                g_Serial_Signal.printf("%d,",tmp_set.y);
#endif
                _Sample_Set[i].y += (tmp_set.y / 10);
                wait(0.1);
            }
#ifdef DEBUG
            g_Serial_Signal.printf("(%d)\n",_Sample_Set[i].y);
#endif
        }

        //  if the input data is over the bound, it is calibrated
        if (_Sample_Set[i].x < 0)
            _Sample_Set[i].x = 0;
    }
    //
    //  Sort set data array in x-Ascending order
    //
    tmp = 0;
    for(    int i = 0              ; i < _Sumple_Num; i++) {
        for(int j = _Sample_Num - 1; j < i+1        ; j++) {
            //  use dst as index for dst range [2,20]
            if (_Sample_Set[i].x > _Sample_set[j].x) {
                tmp_set.x     = _Sample_Set[i].x;
                tmp_set.y     = _Sample_Set[i].y;
                _Sample_Set[i].x = _Sample_Set[j].x;
                _Sample_Set[i].y = _Sample_Set[j].y;
                _Sample_Set[j].x = tmp_set.x;
                _Sample_Set[j].y = tmp_set.y;
            }
            // if a same dst has been input, calcurate mean.
            else if (_Sample_Set[i].x == _Sample_set[j]) {
                tmp_set.y = (_Sample_Set[i].y + _Sample_Set[j].y)/2;
                _Sample_Set[i] = _Sample_Set[j] = tmp_set.y;
                tmp++;
            }
        }
    }
#ifdef DEBUG
    g_Serial_Signal.printf("  _Sample_num: %d\n", _Sample_Num );
    g_Serial_Signal.printf("-)        tmp: %d\n", tmp );
#endif
    //  substruct tmp from number of sample.
    _Sample_Num -= tmp;
#ifdef DEBUG
    g_Serial_Signal.printf("-----------------\n");
    g_Serial_Signal.printf("  _Sample_num: %d\n", _Sample_Num );
#endif

    //  generate t which is parameter related to x,y
    _Sample_Set[i].t = 0;
    for(int i = 1; i < _Sample_Num; i++)
        _Sample_Set[i].t =
            _Sample_Set[i-1]
            + sqrt(pow(_Sample_Set[i].x - _Sample_Set[i-1].x, 2)
                   +pow(_Sample_Set[i].y - _Sample_Set[i-1].y, 2));
}

//
//  Function to define _u_spline, specific constants of spline.
//
void CubicSpline2d::_makeSpline(double* arg_t, double* arg_ft, double* arg_C[4], unsigned int arg_num)
{
    //  arg_t :     t; parameter of x or y
    //  arg_ft:     f(t); cubic poliminal. Value:<=> x or y.
    //  arg_C[i]:   Ci; The parameter (set) that defines Spline Model Poliminal. Coefficient of t^i of f(t).
    //  arg_num:    j in [0,_Sample_Num-1]; The number of interval. 
    //  f(t)j = C3j*t^3 + C2j*t^2 + C1j*t + C0j
    //
    //  N: max of index <=> (_Sample_Num - 1)
    //
    //  u[i] === d^2/dx^2(Spline f)[i]
    //  i:[0,N]
    //  u[0] = u[N] = 0
    double *u = (double*)malloc((arg_num    ) * sizeof(double));
    //
    //  h[i] = x[i+1] - x[i]
    //  i:[0,N-1]; num of elm: N<=>_Sample_Num - 1
    double *h = (double*)malloc((arg_num - 1) * sizeof(double));
    //
    //  v[i] = 6*((y[i+2]-y[i+1])/h[i+1] + (y[i+1]-y[i])/h[i])
    //  i:[0,N-2]
    double *v = (double*)malloc((arg_num - 2) * sizeof(double));
    //
    //  temporary array whose num of elm equals v array
    double *w = (double*)malloc((arg_num - 2) * sizeof(double));
    //
    //  [ 2(h[0]+h[1])  , h[1]          ,                                 O                 ]   [u[1]  ]   [v[0]  ]
    //  [ h[1]          , 2(h[1]+h[2])  , h[2]                                              ]   [u[2]  ]   [v[1]  ]
    //  [                       ...                                                         ] * [...   ] = [...   ]
    //  [                   h[j]          , 2(h[j]+h[j+1])  , h[j+1]                        ]   [u[j+1]]   [v[j]  ]
    //  [                                   ...                                             ]   [ ...  ]   [ ...  ]
    //  [                               h[N-3]        , 2(h[N-3]+h[N-2]), h[N-2]            ]   [u[j+1]]   [v[j]  ]
    //  [       O                                       h[N-2]          , 2(h[N-2]+h[N-1])  ]   [u[N-1]]   [v[N-2]]
    //
    // For LU decomposition
    double *Upper = (double*)malloc((arg_num - 2) * sizeof(double));
    double *Lower = (double*)malloc((arg_num - 2) * sizeof(double));
#ifdef DEBUG
    _printOutData(arg_t, arg_ft, arg_num, "\nargment set\n");
#endif
    for(int i = 0; i < arg_num - 1; i++)
        h[i] =  (double)(arg_t[i + 1] - arg_t[i]);

    for(int i = 0; i < arg_num - 2; i++)
        v[i] = 6 * (
                   ((double)(arg_ft[i + 2] - arg_ft[i + 1])) / h[i + 1]
                   -
                   ((double)(arg_ft[i + 1] - arg_ft[i]))     / h[i]
               );

    //
    //  LU decomposition
    //
    Upper[0] = 2 * (h[0] + h[1]);
    Lower[0] = 0;
    for (int i = 1; i < arg_num - 2; i++) {
        Lower[i] = h[i] / Upper[i - 1];
        Upper[i] = 2 * (h[i] + h[i + 1]) - Lower[i] * h[i];
    }


    //
    //  forward substitution
    //
    w[0] = v[0];
    for (int i = 1; i < arg_num - 2; i ++) {
        w[i] = v[i] - Lower[i] * w[i-1];
    }

    //
    //  backward substitution
    //
    u[arg_num - 2] =  w[arg_num - 3]                     / Upper[arg_num - 3];
    for(int i = arg_num - 3; i > 0; i--) {
        u[i]       = (w[(i - 1)] -  h[(i)] * u[(i) + 1]) / Upper[(i - 1)];
    }

    // _u_spline[i] === d^2/dx^2(Spline f)[i]
    u[0] = u[arg_num - 1] = 0.0;

#ifdef DEBUG
    _printOutData(h,     arg_num - 1, "h");
    _printOutData(v,     arg_num - 2, "v");
    _printOutData(w,     arg_num - 2, "w");
    _printOutData(Upper, arg_num - 2, "Upper");
    _printOutData(Lower, arg_num - 2, "Lower");
    _printOutData(u,     arg_num    , "u");
#endif

    for(int itv = 0; itv < arg_num - 1; itv++) {
        C[3][itv] = (u[itv + 1] - u[itv]) / 6.0 / (arg_t[itv + 1] - arg_t[itv]);
        C[2][itv] = (u[itv]) / 2.0;
        C[1][itv] = (arg_ft[itv + 1] - arg_ft[itv]) / (arg_t[itv + 1] - arg_t[itv])
                    -
                    (arg_t[itv + 1]  - arg_t[itv])  * (u[itv + 1] + 2.0 * u[itv]) / 6.0;
        C[0][itv] = (arg_ft[itv]);
    }
    free(h);
    free(u);
    free(v);
    free(w);
    free(Upper);
    free(Lower);
}

//
//  Function to return Voltage for distance.
//
unsigned short CubicSpline2d:: _getSplineYof(
    double arg_x       //  the argument is supposed as distance [mm]
)
{
    double y;       //  voltage calculated by spline polynomial
    double a,b,c,d; //  which is specific constant of spline, and can be expressed with _u.
    int itv = 0;    //  interval(section) of interpolation
    //  the number of interval is less 1 than the number of sample sets,
    //  which means the max number of interval is _Sample_num - 2.
    if((double)(_Sample_Set[0].dst) <= arg_x) {
        while (!((double)(_Sample_Set[itv].dst) <= arg_x && arg_x < (double)(_Sample_Set[itv + 1].dst))) {
            itv++;
            if(itv > _Sample_Num - 2) {
                itv = _Sample_Num - 2;
                break;
            }
        }
    }
    a = (double)(_u_spline[itv + 1] - _u_spline[itv]) / 6.0 / (double)(_Sample_Set[itv + 1].dst - _Sample_Set[itv].dst);
    b = (double)(_u_spline[itv]) / 2.0;
    c = (double)(_Sample_Set[itv + 1].vol - _Sample_Set[itv].vol) / (double)(_Sample_Set[itv + 1].dst - _Sample_Set[itv].dst)
        -
        (double)(_Sample_Set[itv + 1].dst - _Sample_Set[itv].dst) * (double)(_u_spline[itv + 1] + 2.0 * _u_spline[itv]) / 6.0;
    d = (double)(_Sample_Set[itv].vol);
    //  cubic spline expression
    y = a * (arg_x - (double)(_Sample_Set[itv].dst)) * (arg_x - (double)(_Sample_Set[itv].dst)) * (arg_x - (double)(_Sample_Set[itv].dst))
        +
        b * (arg_x - (double)(_Sample_Set[itv].dst)) * (arg_x - (double)(_Sample_Set[itv].dst))
        +
        c * (arg_x - (double)(_Sample_Set[itv].dst))
        +
        d;

#ifdef DEBUG2
    g_Serial_Signal.printf("%f(interval: %d)", arg_x, itv);
    g_Serial_Signal.printf("a:%f, b:%f, c:%f, d:%f, ", a,b,c,d);
    g_Serial_Signal.printf("(y:%f -> %d)\n", y, (unsigned short)y);
#endif

    return ((unsigned short)(int)y);
}

void CubicSpline2d::calibrateSensor()
{
    _sampleData();
    _makeSpline();

    for(int i = 0; i < _ENUM; i++) {
        _Set[i].dst     = i;
        _Set[i].vol     = _getSplineYof((double)(_Set[i].dst));
        _Threshold[i]   = _getSplineYof((double)(_Set[i].dst) + 0.5);
#ifdef DEBUG2
        g_Serial_Signal.printf("(get...threashold:%d)\n", _Threshold[i]);
#endif
    }
}

void CubicSpline2d::saveSetting()
{
    FILE *fp;

    fp = fopen("/local/savedata.log", "wb");

    for(int i = 0; i < _ENUM; i++) {
        fwrite(&_Set[i].dst,    sizeof(unsigned short), 1, fp);
        fputc(0x2c, fp);
        fwrite(&_Set[i].vol,    sizeof(unsigned short), 1, fp);
        fputc(0x2c, fp);
        fwrite(&_Threshold[i],  sizeof(unsigned short), 1, fp);
        fputc(0x3b, fp);
    }
    fwrite(&_Sample_Num, sizeof(int), 1, fp);
    fputc(0x3b, fp);
    for(int i = 0; i < _Sample_Num; i++) {
        fwrite(&_Sample_Set[i].dst,    sizeof(unsigned short), 1, fp);
        fputc(0x2c, fp);
        fwrite(&_Sample_Set[i].vol,    sizeof(unsigned short), 1, fp);
        fputc(0x3b, fp);
    }
    fclose(fp);

}

void CubicSpline2d::printThresholds()
{
    for(int i = 0; i < _ENUM; i++)
        g_Serial_Signal.printf("Threshold[%d]%d\n",i,_Threshold[i]);
}
void CubicSpline2d::loadSetting()
{
    FILE *fp;
    char tmp;

    //sprintf(filepath, "/local/%s", filename);
    //fp = fopen(filepath, "rb");
    fp = fopen("/local/savedata.log", "rb");
    for(int i = 0; i < _ENUM; i++) {

        fread(&_Set[i].dst,     sizeof(unsigned short), 1, fp);
        fread(&tmp,             sizeof(char),           1, fp);
#ifdef DEBUG2
        g_Serial_Signal.printf("%d%c",  _Set[i].dst, tmp);
#endif

        fread(&_Set[i].vol,     sizeof(unsigned short), 1, fp);
        fread(&tmp,             sizeof(char), 1, fp);
#ifdef DEBUG2
        g_Serial_Signal.printf("%d%c",  _Set[i].vol, tmp);
#endif

        fread(&_Threshold[i],   sizeof(unsigned short), 1, fp);
        fread(&tmp,             sizeof(char), 1, fp);
#ifdef DEBUG2
        g_Serial_Signal.printf("%d%c\n",_Threshold[i],      tmp);
#endif
    }

    fread(&_Sample_Num, sizeof(unsigned short),  1, fp);
    fread(&tmp,         sizeof(char), 1, fp);

    for(int i = 0; i < _Sample_Num; i++) {
        fread(&_Sample_Set[i].dst, sizeof(unsigned short), 1, fp);
        fread(&tmp, sizeof(char),1,fp);
        fread(&_Sample_Set[i].vol, sizeof(unsigned short), 1, fp);
        fread(&tmp, sizeof(char),1,fp);
    }
    fclose(fp);
}


void CubicSpline2d::saveSetting(
    const char *filename
)
{
    FILE *fp;
    char *filepath;
    int fnnum = 0;

    while (filename[fnnum] != 0) fnnum++;
    filepath = (char *)malloc((fnnum + 8) * sizeof(char)); // "/local/" are 7 char and \0 is 1 char.

    sprintf(filepath, "/local/%s", filename);
    fp = fopen(filepath, "wb");

    for(int i = 0; i < _ENUM; i++) {
        fwrite(&_Set[i].dst,    sizeof(unsigned short), 1, fp);
        fputc(0x2c, fp);
        fwrite(&_Set[i].vol,    sizeof(unsigned short), 1, fp);
        fputc(0x2c, fp);
        fwrite(&_Threshold[i],  sizeof(unsigned short), 1, fp);
        fputc(0x3b, fp);
    }
    fwrite(&_Sample_Num, sizeof(int), 1, fp);
    fputc(0x3b, fp);
    for(int i = 0; i < _Sample_Num; i++) {
        fwrite(&_Sample_Set[i].dst,    sizeof(unsigned short), 1, fp);
        fputc(0x2c, fp);
        fwrite(&_Sample_Set[i].vol,    sizeof(unsigned short), 1, fp);
        fputc(0x3b, fp);
    }
    fclose(fp);
    free(filepath);
}

void CubicSpline2d::loadSetting(
    const char *filename
)
{
    FILE *fp;
    char *filepath;
    char tmp;
    int fnnum = 0;

    while (filename[fnnum] != 0) fnnum++;
    filepath = (char *)malloc((fnnum + 8) * sizeof(char)); // "/local/" are 7 char and \0 is 1 char.

    sprintf(filepath, "/local/%s", filename);
    fp = fopen(filepath, "rb");
    for(int i = 0; i < _ENUM; i++) {

        fread(&_Set[i].dst,     sizeof(unsigned short), 1, fp);
        fread(&tmp,             sizeof(char), 1, fp);
#ifdef DEBUG3
        g_Serial_Signal.printf("%d%c",  _Set[i].dst, tmp);
#endif

        fread(&_Set[i].vol,     sizeof(unsigned short), 1, fp);
        fread(&tmp,             sizeof(char), 1, fp);
#ifdef DEBUG3
        g_Serial_Signal.printf("%d%c",  _Set[i].vol, tmp);
#endif

        fread(&_Threshold[i],   sizeof(unsigned short), 1, fp);
        fread(&tmp,             sizeof(char), 1, fp);
#ifdef DEBUG3
        g_Serial_Signal.printf("%d%c\n",_Threshold[i],      tmp);
#endif
    }

    fread(&_Sample_Num, sizeof(unsigned short), 1, fp);
    fread(&tmp,         sizeof(char),           1, fp);
#ifdef DEBUG3
    g_Serial_Signal.printf("%d%c\n",_Sample_Num,      tmp);
#endif

    for(int i = 0; i < _Sample_Num; i++) {
        fread(&_Sample_Set[i].dst,  sizeof(unsigned short), 1, fp);
        fread(&tmp,                 sizeof(char),1,fp);
#ifdef DEBUG3
        g_Serial_Signal.printf("%d%c",  _Sample_Set[i].dst, tmp);
#endif

        fread(&_Sample_Set[i].vol,  sizeof(unsigned short), 1, fp);
        fread(&tmp,                 sizeof(char),1,fp);
#ifdef DEBUG3
        g_Serial_Signal.printf("%d%c",  _Sample_Set[i].vol, tmp);
#endif
    }
    fclose(fp);
    free(filepath);
}

void CubicSpline2d::printOutData()
{
    FILE *fp;

    fp = fopen("/local/log.txt", "w");  // open file in writing mode
    fprintf(fp, "dst, vol,(threshold)\n");
    for(int i = 0; i < _ENUM; i++) {
        fprintf(fp, "%d,%d,(%d)\n", _Set[i].dst, _Set[i].vol, _Threshold[i]);
    }
    fprintf(fp, "\nSample:dst, vol\n");
    for(int i = 0; i < _Sample_Num; i++) {
        fprintf(fp, "%d,%d\n", _Sample_Set[i].dst, _Sample_Set[i].vol);
    }
    fclose(fp);

}
void CubicSpline2d::_printOutData(unsigned short *arg, int num, char* name)
{
    FILE *fp;
    fp = fopen("/local/varlog.txt", "a");  // open file in add mode
    fprintf(fp, "%10s\n", name);
    for(int i = 0; i < num; i++) {
        fprintf(fp, "%d, ", arg[i]);
    }
    fprintf(fp, "\n");
    fclose(fp);
}
void CubicSpline2d::_printOutData(double *arg, int num, char* name)
{
    FILE *fp;

    fp = fopen("/local/varlog.txt", "a");  // open file in add mode
    fprintf(fp, "%10s\n", name);
    for(int i = 0; i < num; i++) {
        fprintf(fp, "%.2f, ", arg[i]);
    }
    fprintf(fp, "\n");
    fclose(fp);
}
void CubicSpline2d::_printOutDataCouple(double *arg1, double *arg2, int num, char* name)
{
    FILE *fp;

    fp = fopen("/local/varlog.txt", "a");  // open file in add mode
    fprintf(fp, "%10s\n", name);
    for(int i = 0; i < num; i++) {
        fprintf(fp, "(%.2f, %.2f)\n", arg1[i], arg2[i]);
    }
    fprintf(fp, "\n");
    fclose(fp);
}
void CubicSpline2d::_printOutData(Vxyt *arg, int num, char* name)
{
    FILE *fp;

    fp = fopen("/local/varlog.txt", "a");  // open file in add mode
    fprintf(fp, "%10s\n", name);
    for(int i = 0; i < num; i++) {
        fprintf(fp, "%d, ", arg[i].vol);
    }
    fprintf(fp, "\n");
    fclose(fp);
}