Akifumi Takahashi / CubicSpline

Fork of TRP105F_Spline by Akifumi Takahashi

CubicSpline.c

Committer:
aktk
Date:
2016-05-24
Revision:
7:e032ddec6ed5
Parent:
6:c4f36cee3ceb
Child:
8:e7d451bb4fd4

File content as of revision 7:e032ddec6ed5:

#define DEBUG
#include "CubicSpline.h"

//  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]);
    }
}

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].t
            + sqrt(pow(_Sample_Set[i].x - _Sample_Set[i-1].x, 2)
                   +pow(_Sample_Set[i].y - _Sample_Set[i-1].y, 2));
}

#define VERSION_C
//
//  Function to define _u_spline, specific constants of spline.
//
void CubicSpline2d::_makeModel(double* arg_t, double* arg_ft, double* arg_C[4], const unsigned int arg_num)
{
    //  arg_t :     t; The variable of f(t)
    //  arg_ft:     f(t); The cubic poliminal in Interval-j.
    //  arg_C[i]:   Ci; The coefficient of t^i of f(t) that defines Spline Model Poliminal 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
#if defined (VERSION_C)
    double *u = (double*)malloc((arg_num    ) * sizeof(double));
#elif defined (VERSION_C++)
    double *u = new double[arg_num];
#elif defined (VERSION_C++11)
    std::array<double,arg_num> u;
#endif
    //
    //  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);
}
//
//  Fuction to return the value of Cubic polyminal f(t)
//
double  CubicSpline2d::_cubic_f(const double   arg_t, const double* arg_C[4])
{
    double ft;  //the value of Spline f(t).

    ft = arg_C[3] * pow(arg_t, 3) + arg_C[2] * pow(arg_t, 2) + arg_C[1] * arg_t + arg_C[0];

    return ft;
}
//
//  Function to solve a cubic poliminal
//  by using Gardano-Tartaglia formula
//
void _solve_cubic_f(
    std::complex<double>* arg_t,
    const double* arg_C[4],
    const double  arg_ft)
{
    double c[3];
    //f(t)  = arg_ft/arg_C[3]
    //      = t^3 + c[2]*t^2 + c[1]*t + c[0].
    for(int i = 0; i < 3; i++) {
        c[i] = arg_C[i] / arg_C[3];
    }
    //modify the formula
    //t^3 + c[2]*t^2 + c[1]*t + (c[0] - ft) = 0.
    c[0] -= arg_ft / argC[3];

    //The values defined from coefficients of the formula
    //that identify solutions
    double p,q,d;
    p = (   -pow(c[2], 2) + 3 * c[1]) / 9;
    q = (2 * pow(c[2], 3) - 9 * c[2] * c[1] + 27 * c[0]) / 54;
    d = - c[2] / 3;

    //Discriminant section
    double D;
    D = pow(p, 3) + pow(q, 2);

    //The values defined from p and q
    //that idetify solutions
    std::complex<double> u,v;

    //Real root only
    if(D <= 0) {
        u.real(-q);
        u.imag(+sqrt(-D));
        v.real(-q);
        v.real(-sqrt(-D));
    }
    //One real root and two complex root
    else {
        u.real(-q+sqrt(D));
        u.imag(0.0);
        v.real(-q-sqrt(D));
        v.real(0.0);
    }
    u = pow(u, 1/3);
    v = pow(v, 1/3);

    //Cubic root of 1
    std::complex<double> omega[3]= {
        std::complex<double>( 1.0, 0.0),
        std::complex<double>(-1/2, sqrt(3)/2),
        std::complex<double>(-1/2,-sqrt(3)/2)
    };
    
    //Solution of the formula
    arg_t[0] = omega[0] * u + omega[0] * v + d;
    arg_t[1] = omega[1] * u + omega[2] * v + d;
    arg_t[2] = omega[2] * u + omega[1] * v + d;
}

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);
}