シェルスクリプトマガジン

AWKでデジタル信号処理(Vol.82掲載)

著者:斉藤博文

プログラミング言語「AWK」は、データストリーム(データの流れ)を逐次処理するのに適しています。本連載では、電子回路の分野でその特徴を生かし、シェルスクリプトを組み合わせてデジタル信号を処理します。第4回は「微分フィルタ」を使って目的の波形を取り出す方法を紹介します。

シェルスクリプトマガジン Vol.82は以下のリンク先でご購入できます。

図10 微分フィルタの差分方程式のAWKプログラム(dif.awk)

#! /usr/bin/gawk -f

BEGIN {
    # define number of order
    num_ord = num_ord ? num_ord : 31;

    # define length of ring buffers
    len_data_raw = num_ord + 1;
    len_data_dif = 1;

    # initialize ring buffers
    for (i = 0; i < len_data_raw; i++) {
        arr_data_raw[i] = 0.0;
    }
    for (i = 0; i < len_data_dif; i++) {
        arr_data_dif[i] = 0.0;
    }

    # initialize index of ring buffers
    idx_data_raw = 0;
    idx_data_dif = 0;

    # initialize number of data
    num_data_raw = 0;
}

{
    # add number of data
    num_data_raw++;

    # update index of ring buffers (write pointers)
    idx_data_raw = num_data_raw % len_data_raw;
    idx_data_dif = num_data_raw % len_data_dif;

    # clear number of data
    if (idx_data_raw == 0 && idx_data_dif == 0) {
        num_data_raw = 0;
    }

    # store input raw data
    val_data_raw = $0;
    arr_data_raw[idx_data_raw] = val_data_raw;

    # apply differential filter
    arr_data_dif[idx_data_dif] = dif(arr_data_raw, idx_data_raw, num_ord, len_data_raw);

    # print results
    print arr_data_dif[idx_data_dif];
}

# get value of ring buffer
function get_buffer(arr, idx, len) {
    if (idx < 0) {
        return arr[idx + len];
    }

    return arr[idx];
}

# differential filter
function dif(arr_x, idx_x, ord, len_x,      _ret, _half, i) {
    _ret = 0.0;
    _half = int((ord - 1) / 2);

    for (i = 0; i < ord; i++) {
        _ret += (_half - i) * get_buffer(arr_x, idx_x - i, len_x);
    }

    return _ret;
}

図12 群遅延を考慮したAWKプログラム(dif_gd.awk)

#! /usr/bin/gawk -f

BEGIN {
    # define number of order
    num_ord = num_ord ? num_ord : 31;

    # define group delay
    val_gd = int((num_ord - 1) / 2);

    # define length of ring buffers
    len_data_raw = num_ord + 1;
    len_data_dif = 1;

    # initialize ring buffers
    for (i = 0; i < len_data_raw; i++) {
        arr_data_raw[i] = 0.0;
    }
    for (i = 0; i < len_data_dif; i++) {
        arr_data_dif[i] = 0.0;
    }

    # initialize index of ring buffers
    idx_data_raw = 0;
    idx_data_dif = 0;

    # initialize number of data
    num_data_raw = 0;
}

{
    # add number of data
    num_data_raw++;

    # update index of ring buffers (write pointers)
    idx_data_raw = num_data_raw % len_data_raw;
    idx_data_dif = num_data_raw % len_data_dif;

    # clear number of data
    if (idx_data_raw == 0 && idx_data_dif == 0) {
        num_data_raw = 0;
    }

    # store input raw data
    val_data_raw = $0;
    arr_data_raw[idx_data_raw] = val_data_raw;

    # apply differential filter
    arr_data_dif[idx_data_dif] = dif(arr_data_raw, idx_data_raw, num_ord, len_data_raw);

    # print results
    print get_buffer(arr_data_raw, idx_data_raw - val_gd, len_data_raw), arr_data_dif[idx_data_dif];
}

# get value of ring buffer
function get_buffer(arr, idx, len) {
    if (idx < 0) {
        return arr[idx + len];
    }

    return arr[idx];
}

# differential filter
function dif(arr_x, idx_x, ord, len_x,      _ret, _half, _gain i) {
    _ret = 0.0;
    _half = int((ord - 1) / 2);

    _gain = 0.0;
    for (i = 0; i < ord; i++) {
        _gain += (_half - i)^2;
    }

    for (i = 0; i < ord; i++) {
        _ret += (_half - i) * get_buffer(arr_x, idx_x - i, len_x);
    }

    return _ret / _gain;
}

図14 係数の補正を加えた関数dif()

# differential filter
function dif(arr_x, idx_x, ord, len_x,      _ret, _half, _gain i) {
    _ret = 0.0;
    _half = int((ord - 1) / 2);

    _gain = 0.0;
    for (i = 0; i < ord; i++) {
        _gain += (_half - i)^2;
    }

    for (i = 0; i < ord; i++) {
        _ret += (_half - i) * get_buffer(arr_x, idx_x - i, len_x);
    }

    return _ret / _gain;
}