0012. ピーク検出(C言語)

戻る

detpeak.cのソースコード】


/*
 * CSV形式のスペクトルデータからピークを検出し、
 * ピーク位置とそのときの値の一覧表(list)を
 * 新たなCSVファイルとして出力するプログラム
 * detpeak.c(detect peak)
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strlen(), strcmp(), strcpy(), strcat() */
#include <ctype.h>  /* tolower() */

#define BUF_SIZE 256
#define NUM_DATA 4000





/*
 * 自作のbool型の定義
 */
typedef enum {
    false, /* 0 */
    true   /* 1 */
} bool;





/*
 * ユーザー定義関数の関数原型宣言
 */
void print_title(void);
void init_val(void);
void input_fnamein(void);
char *strtolower(char *sp);
void open_fin(void);
void input_datatype(void);
void read_data(void);
void gen_fname(char *fnamein, char *fnameout);
void open_fout(void);
void write_data(void);
void close_fio(void);
bool retry(void);





/*
 * グローバル変数
 */
char fnamein[BUF_SIZE], fnameout[BUF_SIZE], datatype;
int n, numpeak;
long double x_tmp, x[NUM_DATA], y_tmp, y[NUM_DATA];
FILE *finp, *foutp;





int main(void)
{
    while (1) {
        
        /* 表題・説明 */
        print_title();
        
        /* 変数の初期化 */
        init_val();
        
        /* 入力ファイルの名前の入力 */
        input_fnamein();
        
        /* 入力ファイルを開く処理 */
        open_fin();
        
        /* データの種類の入力 */
        input_datatype();
        
        /* 入力ファイルからのデータの読み込み */
        read_data();
        
        /* 出力ファイルの名前の生成 */
        gen_fname(fnamein, fnameout);
        
        /* 出力ファイルを開く処理 */
        open_fout();
        
        /* 出力ファイルへのデータの書き込み */
        write_data();
        
        /* 入出力ファイルを閉じる処理 */
        close_fio();
        
        /* 操作を続けるかどうかの選択 */
        if (!retry())
            break;
    }
    
    return EXIT_SUCCESS;
}





/*
 * 表題およびプログラムの説明を表示する関数
 */
void print_title(void)
{
    printf("【ピーク検出プログラム】\n");
    printf("CSV形式のスペクトルデータ(*.csv)からピークを検出し、\n");
    printf("ピーク位置とそのときの値の一覧表(list)を\n");
    printf("新たなCSVファイル(*_l.csv)として出力します。\n\n");
}



/*
 * 変数を初期化する関数
 */
void init_val(void)
{
    n = 0;
    numpeak = 1;
}



/*
 * 入力ファイルの名前を入力する関数
 * strtolower()関数を使用する。
 */
void input_fnamein(void)
{
    while (1) {
        printf("入力ファイルの名前(*.csv)を入力してください。\n");
        fgets(fnamein, sizeof fnamein, stdin);
        fnamein[strlen(fnamein) - 1] = '\0';
        if (strcmp(strtolower(&fnamein[strlen(fnamein) - 4]), ".csv") != 0) {
            printf("ファイル名が正しくありません。\n");
            continue;
        } else
            break;
    }
}



/*
 * 文字列単位で英大文字を小文字に変換する関数
 */
char *strtolower(char *sp)
{
    char *p;
    
    for (p = sp; *p; p++)
        *p = tolower(*p);
    
    return sp;
}



/*
 * 入力ファイルを開く関数
 */
void open_fin(void)
{
    finp = fopen(fnamein, "r");
    if (finp == NULL) {
        printf("ファイル%sを開けません。終了します。\n", fnamein);
        exit(EXIT_FAILURE);
    }
}



/*
 * データの種類を入力する関数
 */
void input_datatype(void)
{
    char buf[BUF_SIZE], zz;
    
    while (1) {
        printf("\nデータの種類を入力してください。\n");
        printf("\tピークが上向きのデータ(吸光度など) -> 1\n");
        printf("\tピークが下向きのデータ(透過率など) -> 2\n");
        
        fgets(buf, sizeof buf, stdin);
        sscanf(buf, "%c%c", &datatype, &zz);
        
        if (((datatype != '1') && (datatype != '2')) || (zz != '\n')) {
            printf("無効な入力です。\n");
            printf("1または2を入力してください。\n\n");
            continue;
        } else
            break;
    }
}



/*
 * 入力ファイルからデータを読み込む関数
 */
void read_data(void)
{
    char zz;
    
    while(fscanf(finp, "%lf,%lf%c", &x_tmp, &y_tmp, &zz) != EOF) {
        x[n] = x_tmp;
        y[n] = y_tmp;
        n++;
    }
}



/*
 * 出力ファイルの名前を生成する関数
 */
void gen_fname(char *fnamein, char *fnameout)
{
    int i;
    char fnamebodyin[BUF_SIZE];
    
    strcpy(fnamebodyin, fnamein);
    for (i = strlen(fnamebodyin) - 1; i > 0; i--)
        if (fnamebodyin[i] == '.') {
            fnamebodyin[i] = '\0';
            break;
        }
    strcpy(fnameout, fnamebodyin);
    fnameout = strcat(fnameout, "_l.csv");
}



/*
 * 出力ファイルを開く関数
 */
void open_fout(void)
{
    foutp = fopen(fnameout, "w");
    if (foutp == NULL) {
        printf("ファイル%sを開けません。終了します。\n", fnameout);
        exit(EXIT_FAILURE);
    }
}



/*
 * 出力ファイルにデータを書き込む関数
 */
void write_data(void)
{
    int k;
    long double d0, d1;
    
    fprintf(foutp, "ピーク番号,ピーク位置,ピークの値\n");
    for(k = 1; k < n - 1; k++) {
        d0 = y[k] - y[k - 1];
        d1 = y[k + 1] - y[k];
        switch (datatype) {
        case '1':
            if ((d0 > 0) && (d1 < 0))
                fprintf(foutp, "%d,%LE,%LE\n", numpeak++, x[k], y[k]);
            break;
        case '2':
            if ((d0 < 0) && (d1 > 0))
                fprintf(foutp, "%d,%LE,%LE\n", numpeak++, x[k], y[k]);
            break;
        default:
            break;
        }
    }
}



/*
 * 入出力ファイルを閉じる関数
 */
void close_fio(void)
{
    fclose(finp);
    fclose(foutp);
}



/*
 * 操作を続けるかどうかを選択する関数
 * true: 繰り返す、false: 終了する。
 */
bool retry(void)
{
    bool ret;
    char buf[BUF_SIZE], ch, zz;
    
    while (1) {
        printf("\n続けますか?(y/n) ");
        
        fgets(buf, sizeof buf, stdin);
        sscanf(buf, "%c%c", &ch, &zz);
        
        if (((ch == 'y') || (ch == 'Y')) && (zz == '\n')) {
            printf("\n+++++\n\n");
            ret = true;
            break;
        } else if (((ch == 'n') || (ch == 'N')) && (zz == '\n')) {
            ret = false;
            break;
        }
        printf("無効な入力です。\n");
        printf("yまたはnを入力してください。\n");
    }
    
    return ret;
}


detpeakの実行時画面表示】赤字はキーボードからの入力を表す。

C:\Users\skonishi\Documents>dir

2022/04/06  20:19             9,216 delta.csv          ←元のデータファイル(*.csv)
2024/01/14  10:08           148,992 detpeak.exe

C:\Users\skonishi\Documents>detpeak
【ピーク検出プログラム】
CSV形式のスペクトルデータ(*.csv)からピークを検出し、
ピーク位置とそのときの値の一覧表(list)を
新たなCSVファイル(*_l.csv)として出力します。

入力ファイルの名前(*.csv)を入力してください。
delta.csv

データの種類を入力してください。
        ピークが上向きのデータ(吸光度など) -> 1
        ピークが下向きのデータ(透過率など) -> 2
1                                                      ←ピークが上向きなので1

続けますか?(y/n) n

C:\Users\skonishi\Documents>dir

2022/04/06  20:19             9,216 delta.csv
2024/01/14  10:17               267 delta_l.csv        ←作成されたピークデータリスト(list)のファイル(*_l.csv)
2024/01/14  10:08           148,992 detpeak.exe


【元のデータファイル(*.csv)をエクセルで読み込んだ様子(抜粋)】
グラフ1

【作成されたピークデータリストのファイル(*l.csv)をエクセルで読み込んだ様子】
グラフ2

【元のデータファイル(*.csv)をエクセルでグラフ化した様子】 ← y = 5 sin 2x + 4 sin 5x + 3 sin 7xx: 0°~540°のグラフ。

グラフ3


【上のグラフにピーク情報を付加した様子】 ←ピーク情報が付加された。
グラフ4
戻る