【MATLAB】plot表示時間短縮のためにデータを間引く

#はじめに
クソデカデータ[^1]を`plot`に渡すと，表示までにかなりの時間がかかる．
[^1]: https://anond.hatelabo.jp/20200611125508
音楽データなら1曲あたり5分間くらいなのでまぁまぁなのだが，業務で取り扱うデータだとサンプリング周波数が$200\rm{[kHz]}$で長さが数時間単位だったりしてそこそこ重たい．


解決方法の一つとして，データをあらかじめ間引いてデータサイズを削減してから`plot`に渡す処理が考えられる．
今回はまず`matlab`標準の関数を使って目的を達成出来るか検討して，次に間引き処理を手実装(車輪の再発明)して結果を確認する．

#matlab標準の関数(decimate)

間引き処理といえば`Signal Processing ToolBox`に`decimate`という関数がある．

[間引き — 整数係数単位でのサンプルレートの低減](https://jp.mathworks.com/help/signal/ref/decimate.html)


```matlab:
% 信号を生成
Fs = 44100;
T = 10;
N = Fs * T;
t = ((1:N)-1)/Fs;
y = 0.1 * rand(1, N);
y = y - mean(y);
% 1s及び5sにトランジェント成分がある信号
y(Fs:Fs+100) = 1;
y(Fs*5:Fs*5+100) = -0.5;


subplot 211
plot(t, y);
str = sprintf('Original Data(N=%d)', length(y));
title(str);
grid on
ylim([-1 1]);
xlabel('t[s]');

decimation = 100;% 間引き量
y2 = decimate(y,decimation);
t2 = ((1:length(y2))-1)/Fs*decimation;
subplot 212
plot(t2, y2);
str = sprintf('Decimated Data(N=%d)', length(y2));
title(str);
grid on
ylim([-1 1]);
xlabel('t[s]');
```

##decimateの結果
![plotwav001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/df7699a2-9378-3a30-afb4-4c91193321e8.png)

オリジナルデータと`decimate`した後のデータを比較すると，データ数は削減出来たものの，だいぶ見た目が変わっている．$1\rm{[s]}$と$5\rm{[s]}$にあるトランジェント成分の振幅が小さくなっている．今回の用途にはちょっと合わなかった感じ．


#間引き処理を手実装
見たいのは信号の最大値と最小値なので，それを抽出する処理を作る．

図にするとこんな感じ．スライド窓の最大値と最小値を抜き出す．
<img width="300" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/fb7d8c74-e0fb-6fd5-fa03-c3bb4b01a8d6.png">

こういう処理って何か名称があるんですかね？
たぶん世にある様々な描画処理はこれを行ってると思うのだけれど…

##実装

```matlab:DecimationProc
function y = DecimationProc(x, r)
r2 = r * 2;
% length(x)がr2の倍数となるようにxをゼロパディング
mod1 = mod(length(x), r2);
if(mod1 == 0)
    x2 = x;
else
    x2 = [x; zeros(r2 - mod1, 1)];
end

% N行1列の行列を、r2行(N/r2)列の行列に変換(max, min処理のため)
x2 = reshape(x2, [r2, length(x2)/r2]);
% 各列のmax/minを求めて、1行（N/r2)列のmax/min行列を取得
[x2_max, x2_max_ind] = max(x2);
[x2_min, x2_min_ind] = min(x2);


% 各列のmaxとminを順番を整列してyに格納
y = zeros(ceil(length(x)/r2), 1);
for n = 1:length(x2_max)
    if(x2_max_ind(n) > x2_min_ind(n))
        y(2 * n - 1) = x2_min(n);
        y(2 * n) = x2_max(n);
    else
        y(2 * n - 1) = x2_max(n);
        y(2 * n) = x2_min(n);        
    end
end
% r点から1点選ぶのではなく，2*r点から2点選ぶという処理になっているため，yは2*rの倍数となってしまう
% それを補正する処理
n1 = (ceil(length(x)/r));
if(length(y) > n1)
    y = y(1:n1);
end
end
```

全体的に汚いし，マルチチャネルとかには対応してないので改良の余地がでかすぎるわね…
`for`文の処理とかもっと`matlab`チックな書き方がありそうだけど，よく分からない．(よわよわプログラマ)
何となく動いているのでヨシ！

# 結果
手実装した間引き処理を使って処理した結果をグラフに描く．

```matlab:
decimatedData = DecimationProc(y, decimation);
subplot 313

t3 = ((1:length(decimatedData))-1)*decimation/Fs;
plot(t3, decimatedData);
grid on
ylim([-1 1]);
str = sprintf('Decimated Data2(N=%d)', length(decimatedData));
title(str);
xlabel('t[s]');
```

![plotwav010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/90a7b0e0-1739-ff89-a041-35997b9d967d.png)

オリジナルと波形の見た目が一致した．

## 結果2(拡大)
1[s]付近を拡大して`stem`関数でグラフを描いてみる．

![plotwav012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/c8c02d3e-5d1b-8da9-6931-ee044b8f563c.png)


## 結果3(音楽データ)
フリー音源を読み込んで，同様に間引き表示した．
![plotwav020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/b9761de0-c519-bae7-aee9-d2a31076b3e5.png)
こっちもいい感じに表示出来ている．