Weather casting with Machine Learning (SVM and SRNN).

Dependencies:   EthernetInterface GraphicHandler NTPClient SRNN SVM SensorModule mbed-rtos mbed

main.cpp

Committer:
yukari_hinata
Date:
2015-02-18
Revision:
2:20ecfe6edd71
Parent:
1:8538381cae81
Child:
3:5add3759e08a

File content as of revision 2:20ecfe6edd71:

#include "main.hpp"

LocalFileSystem *local_fs;  // マウントポイントを定義(ディレクトリパスになる)

// Pointer to Class instance (global)
SRNN            *srnn;
MCSVM           *mcsvm;
SensorModule    *sensor_module;
GraphicHandler  *graphic_handler;
// ネットワーク関係(global)
EthernetInterface    eth_if;
HTTPServer           *http_server;
NTPClient            ntp_client;

// 系列データ
float* new_seqence_data;        // 現在の(一番新しい)系列データ
float* new_predict_data;        // 現在の予測結果
int*   new_predict_weather;     // 現在の予測天気
float* new_predict_probability; // 現在の予測天気の確率(厳密には,確率ではない...)
FILE*  seqence_data_fp;    // 系列データのファイルポインタ(SRNNと計器の記録に使う)
FILE*  predict_data_fp;    // 予測データ

// 生存報告LED
DigitalOut live_led(LED1);

int thread_count = 0;

// 計器/機械学習タスク
void read_and_predict_task(void const *arg)
{
    // ローカル変数
    int line = 0, ret;
    time_t tmp_sec = get_JST();
    struct tm *tmp_tm = localtime(&tmp_sec);
    float* srnn_sample = new float[LEN_DATA_SEQUENCE * DIM_SIGNAL];            // SRNNのサンプル
    // 読み込みバッファ
    float buf_data[DIM_SIGNAL];
    char  str_buf[BUF_SIZE];

    // while (true) {
    // 時刻の取得
    // tmp_sec = get_JST();
    // tmp_tm = localtime(&tmp_sec);

    // 1. センサーから読み出す
    printf("[%d] S.T.A.R.T \r\n", thread_count++);

    // printf("[%d] Reading from sensors... %02d:%02d:%02d \r\n", thread_count++, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec);
    sensor_module->read_all_sensor();

    // データ更新
    __disable_irq(); // 割り込み禁止
    new_seqence_data[TEMPERATURE]  = sensor_module->get_temperture();
    new_seqence_data[AIR_PRESSURE] = sensor_module->get_pressure();
    new_seqence_data[HUMIDITY]     = sensor_module->get_humidity();
    __enable_irq();  // 割り込み許可

    printf("T:%f P:%f H:%f \r\n", new_seqence_data[TEMPERATURE], new_seqence_data[AIR_PRESSURE], new_seqence_data[HUMIDITY]);

    // 2. 記録(記録ファイルが長くなっていたら, 削る)
    printf("Write to File... %02d:%02d \r\n", tmp_tm->tm_hour, tmp_tm->tm_min);
    // 追加書き込み
    seqence_data_fp = fopen( SEQUENCE_DATA_NAME, "a");
    check_file_open( seqence_data_fp, SEQUENCE_DATA_NAME);
    // 形式に沿った文字列を書き出す : y/m/d h:m,<temperature>,<air_pressure>,<humidity>
    fprintf( seqence_data_fp, "%d/%d/%d %d:%d:%d,%f,%f,%f\n",
             (tmp_tm->tm_year + 1900), (tmp_tm->tm_mon + 1), tmp_tm->tm_mday, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec,
             new_seqence_data[TEMPERATURE], new_seqence_data[AIR_PRESSURE], new_seqence_data[HUMIDITY]);
    fclose( seqence_data_fp );
    // 古いデータの削除
    truncate_data_file();

    // 3. SRNNに学習データを読み込ませる.
    printf("Set SRNN sample... %02d:%02d \r\n", tmp_tm->tm_hour, tmp_tm->tm_min);
    seqence_data_fp = fopen( SEQUENCE_DATA_NAME, "r");
    check_file_open( seqence_data_fp, SEQUENCE_DATA_NAME);
    line = 0;
    while( ( ret = fscanf( seqence_data_fp, " %[^\n,],%f,%f,%f", str_buf, &(buf_data[0]), &(buf_data[1]), &(buf_data[2])) ) != EOF ) {
        memcpy(&(srnn_sample[line * DIM_SIGNAL]), buf_data, sizeof(float) * DIM_SIGNAL);
        // printf("sample %d : %s %f %f %f \r\n", line, str_buf, MATRIX_AT(srnn_sample,DIM_SIGNAL,line,0), MATRIX_AT(srnn_sample,DIM_SIGNAL,line,1), MATRIX_AT(srnn_sample,DIM_SIGNAL,line,2));
        line++;
    }
    fclose( seqence_data_fp );
    srnn->set_sample(srnn_sample);

    // 4. SRNNの学習/予測結果から, MCSVMで天気識別
    printf("Learning... %02d:%02d \r\n", tmp_tm->tm_hour, tmp_tm->tm_min);
    srnn->learning();
    srnn->predict(new_seqence_data);

    memcpy(new_predict_data, srnn->predict_signal, sizeof(float) * DIM_SIGNAL * PREDICT_LENGTH);
    // MCSVMによる天候識別
    for (int i_predict = 0; i_predict < PREDICT_LENGTH; i_predict++) {
        // printf("predict_data[%d] : %f %f %f \r\n", i_predict, new_predict_data[i_predict * DIM_SIGNAL], new_predict_data[i_predict * DIM_SIGNAL + 1], new_predict_data[i_predict * DIM_SIGNAL + 2]);
        new_predict_weather[i_predict]     = mcsvm->predict_label(&(new_predict_data[i_predict * DIM_SIGNAL]));
        new_predict_probability[i_predict] = mcsvm->predict_probability(&(new_predict_data[i_predict * DIM_SIGNAL]));
        // printf("P_W : %d P_P : %f \r\n", new_predict_weather[i_predict], new_predict_probability[i_predict]);
    }
    // printf("SVM predict finished \r\n");


    // 5. 予測結果の書き込み
    printf("Write out predict... %02d:%02d \r\n", tmp_tm->tm_hour, tmp_tm->tm_min);
    predict_data_fp = fopen( PREDICT_DATA_NAME, "w");
    check_file_open( predict_data_fp, PREDICT_DATA_NAME);
    for (int i_predict = 0; i_predict < PREDICT_LENGTH; i_predict++) {
        // 予測時刻へ変換
        tmp_sec += PREDICT_INTERVAL_TIME;
        tmp_tm = localtime(&tmp_sec);
        // 気象を文字列に変換
        switch(new_predict_weather[i_predict]) {
            case SHINY:
                strcpy(str_buf, "shiny");
                break;
            case CLOUDY:
                strcpy(str_buf, "cloudy");
                break;
            case RAINY:
                strcpy(str_buf, "rainy");
                break;
            case SNOWY:
                strcpy(str_buf, "snowy");
                break;
            default:
                fprintf( stderr, "Error in write predict result (in weather switch). \r\n");
                break;
        }
        // 書き出しフォーマット : y/m/d h:m,<weather>,<temperature>,<air_pressure>,<humidity>
        fprintf( predict_data_fp, "%d/%d/%d %d:%d:%d,%s,%f,%f,%f\n",
                 (tmp_tm->tm_year + 1900), (tmp_tm->tm_mon + 1), tmp_tm->tm_mday, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec,
                 str_buf,
                 new_predict_data[i_predict * DIM_SIGNAL + TEMPERATURE],
                 new_predict_data[i_predict * DIM_SIGNAL + AIR_PRESSURE],
                 new_predict_data[i_predict * DIM_SIGNAL + HUMIDITY]);
    }
    fclose( predict_data_fp );

    // GraphicHandlerの現在の観測/予測データのセット
    graphic_handler->set_now_data(new_seqence_data);
    graphic_handler->set_predict_data(new_predict_data, new_predict_weather, new_predict_probability);

    // printf("Finishing task... %02d:%02d:%02d \r\n", tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec);
    // Thread::wait(4 * 1000);
    // }

    delete [] srnn_sample;
    // delete tmp_tm; <- してはいけない(戒め)

}

// 描画スレッド : 優先度低め
void draw_task(void const *arg)
{
    while (true) {
        // 1. 描画更新 <- 学習中は止めたい...
        //printf("draw thread start. \r\n");
        if (time(NULL) % 60 == 0) {
            // 一分毎に表示時間を更新
            graphic_handler->update_time();
        }
        graphic_handler->update_image();
        graphic_handler->update_draw();
        //printf("draw thread finish. \r\n");

        Thread::wait(2 * 1000);
    }
}


// ネットワークスレッド
void network_task(void const *arg)
{
    while (true) {
        // 1. ポート80のListen <- 学習中は止めたい...
        //http_server->poll();
        Thread::wait(0.5 * 1000);
    }
}

// 生存報告LEDチカ
void liveled_task(void const *arg)
{
    while (true) {
        live_led = !live_led;
        Thread::wait(1 * 1000);
    }
}

// エントリ. スレッドの生成, そして待つ
int main(void)
{
    set_new_handler(no_memory);
    local_fs = new LocalFileSystem("local");
    setup();

    RtosTimer ml_timer(read_and_predict_task, osTimerPeriodic, NULL);
    Thread draw_thread(draw_task, NULL, osPriorityBelowNormal);
    Thread network_thread(network_task, NULL, osPriorityLow);
    Thread liveled_thread(liveled_task, NULL);

    ml_timer.start(5 * 1000);

    Thread::wait(osWaitForever);

}