【MATLAB】グラフに表示したデータと地図で同期がとれるようにしてみた

# あらすじ

移動体のログを取得して後で解析していると
「この現象は一体どこで発生したんだろう。。」
と思う時が度々ある。

移動体がGPSやQZSSを搭載していて緯度経度をロギング
している場合、現象が発生した時の緯度経度を調べて
google mapなどに入力すればその現象がどこで
発生したか分かるが、いかんせん面倒くさい、
面倒くさすぎる。

そこで今回は、時間軸上に表示したログのある地点と、
地図上の座標の同期をとって表示するような解析用の
GUIツールをmatlabで作成したい。

# 使用する技術

１．GUI

今回はmatlabでGUIを作るための機能「matlab GUIDE」を
用いてツールを作成する。

２．地図

OpenStreetMapなどがあるが、今回は航空写真を
使用したいためGoogle map APIから地図データを取得する。
そのための素晴らしいライブラリを作ってくれた方がいらしたので
そのライブラリ「get_google_map.m」を使用させていただきます。
（ただし、一部変更を加える必要がある。詳細は後述）

https://jp.mathworks.com/matlabcentral/fileexchange/24113-get_google_map

上記ライブラリにてGoogle map APIを使用するには、Googleにアカウントを作成して
APIキーを発行し、使用したいAPIを有効にする必要がある。

※ Googleのアカウント作成～API有効迄の手順は、下記ページなど
　 を参考にさせていただきました。
　 http://www.webdesignleaves.com/pr/plugins/googlemap_01.html

因みに.NETだとGMap.NETなる便利なライブラリをGCPに
登録することなく使用できるらしい…が、今回は.NETではなく
matlabなのであえなく断念。 

３．mf4ファイルの読み込み

matlabでmf4ファイルを解析するには
「Vehicle Network Toolbox Documentation」が必要となる。

https://jp.mathworks.com/help/vnt/examples/access-mdf-files.html

ただし有料であるため、別の方法を用いる。

pythonにはmdfファイルを読み込む為のライブラリ「asammdf」が
存在し、そのpythonの関数やライブラリを呼び出す機能がmatlabには
存在する。

今回はその機能を使用してmdfファイルを読み込むことにする。

といいつつ、今回はmdfを読み込む処理の部はソースに記載しない。
（知り合いが書いた部分であり、載せられないため）
なので、asammdfを使用している部分はその旨をコメントとして残しておく。

４．データ名のリストとパス
グラフにプロットするデータの名前とそのデータのパスは、xmlファイル上で紐付けて
matlabで読み込む形式とする。

# こんな感じのものを作りたい

以下のような流れで使用することを考える。

１．mf4ログを読み込む。
２．選択したデータをプロットする（横軸は時間）
３．２でプロットしたデータから、地図データと同期したい個所を選択する
４．地図データを表示する

# 実際に作ったもの

実行直後はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/a3e8f88d-bc34-bc2e-91d2-93c1014eafb0.png)

まず、「ファイル選択」ボタンを押してmf4ログを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/8126ba6e-02b2-2469-182a-f1585ea5362a.png)

「ファイル選択」の右側のテキストボックスにファイルのパスが入ったらロードされたということなので、グラフに表示したいデータをプルダウンメニューから選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/2d23e317-44ab-0381-601d-ac8b1a296306.png)

データがグラフに表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/9d34795d-44bc-7616-09b8-16c3291f3260.png)

グラフ上で地図に表示したい地点を、グラフをクリックすることで選択してマークを設置します。
※ クリックする場所は、プロットされたデータ（青い線）でも、白い部分でもどちらでもよいです。
今回は、値がピークになっている部分が一体どの場所で発生したのか知りたいため、ピークになっている部分を選択しました。（ということにします）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/69ab213c-0b8a-b56c-f0d6-1efabcc811c9.png)

「地図を表示」ボタンを押すと、地図が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/8265d070-f730-c69e-b608-199ceb9f98ee.png)
※ 写真はモルディブですが、残念ながら実際にモルディブでログをとったわけではありません。
　 モルディブ行きてえなあ。。

あとは、拡大・縮小ボタンを適宜使用して地図を調整します。

表示された地図は、右側のグラフに新たなマークを設置すると消えるようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/3f5251c5-f999-5145-d980-fd86f73b3eca.png)

# ソースファイル

## １．GUI
GUIDEで作成した画面を示す。青字のテキストボックスは各オブジェクトのタグ名を意味する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/5137e740-217e-988a-d9a3-55bbdc967c38.png)

```matlab:graph_and_google_map.m
function varargout = graph_and_google_map(varargin)
% GRAPH_WITH_GMAP MATLAB code for graph_with_GMAP.fig
%      GRAPH_WITH_GMAP, by itself, creates a new GRAPH_WITH_GMAP or raises the existing
%      singleton*.
%
%      H = GRAPH_WITH_GMAP returns the handle to a new GRAPH_WITH_GMAP or the handle to
%      the existing singleton*.
%
%      GRAPH_WITH_GMAP('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GRAPH_WITH_GMAP.M with the given input arguments.
%
%      GRAPH_WITH_GMAP('Property','Value',...) creates a new GRAPH_WITH_GMAP or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before graph_with_GMAP_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to graph_with_GMAP_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help graph_with_GMAP

% Last Modified by GUIDE v2.5 22-Dec-2019 18:33:53

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @graph_with_GMAP_OpeningFcn, ...
                   'gui_OutputFcn',  @graph_with_GMAP_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before graph_with_GMAP is made visible.
function graph_with_GMAP_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to graph_with_GMAP (see VARARGIN)
    
    dom = xmlread('datalist.xml');
    xmldata = dom.getElementsByTagName('name');

    i= 0;

    while(~(isempty(xmldata.item(i))))    
        i = i + 1;
        data(i) = xmldata.item(i-1);
    end

    for j = 1 : i

        datalist(j) = {char(getNodeValue(data(j).item(0)))};
%         maxlen = max(size(char(datalist(j)), 2), maxlen);
    end
    
    handles.select_data1.String = datalist; % ログのプルダウンメニューに表示するデータリスト
    handles.select_data2.String = datalist;
    handles.select_data3.String = datalist;
    handles.select_data1.UserData.num = 1;  % 各データ選択プルダウンメニューの番号
    handles.select_data2.UserData.num = 2;
    handles.select_data3.UserData.num = 3;
    handles.fig_data1.UserData.num = 1;     % 各グラフの番号
    handles.fig_data2.UserData.num = 2;
    handles.fig_data3.UserData.num = 3;
    handles.fig_data1.UserData.pointx = 0; % 各グラフにおけるマークの番号
    handles.fig_data2.UserData.pointx = 0;
    handles.fig_data3.UserData.pointx = 0;
    
    handles.graphnum = 3; % グラフの数
    handles.dt = 0.01; % ログのサンプリングタイム[sec]
    handles.pnum = zeros(handles.graphnum); % 各グラフにプロットしているデータの数
    handles.data_x = 0; % x軸の値
    
    %%%% asammdfを使用 %%%%%%%%%%%%%%%%%%%%%%%%
    %「handles.mf4obj」を初期化
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        
    % Choose default command line output for graph_with_GMAP
    handles.output = hObject;

    % Update handles structure
    guidata(hObject, handles);

    % UIWAIT makes graph_with_GMAP wait for user response (see UIRESUME)
    % uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = graph_with_GMAP_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

function select_file_Callback(hObject, eventdata, handles)
    
    if isempty(handles.edit_chosen_file.String)
        
        prepath = '';
    else
        
        LFnum = strfind(handles.edit_chosen_file.String, '\');   % 改行'\'がある順番を全て抜き出す
        tgtLFnum = LFnum(length(LFnum));                         % 最後の'\'の番号(つまり.mf4ファイルの前)のみ抜き出す
        prepath = handles.edit_chosen_file.String(1 : tgtLFnum); % ファイルパスのうち、ファイル名以外を抽出       
    end
    
    [tmpfile, tgtpath] = uigetfile(strcat(prepath, '*.mf4'));
    
    if ~(strcmp(num2str(tmpfile), '0')) && ~(strcmp(num2str(tgtpath), '0')) % 両方とも0ではない時(=何かしらの.mf4ファイルを選択した時)
        
        tgtfile = strcat(tgtpath, tmpfile);
        
        %%%%% asammdfを使用 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % 1.「mf4obj」に対象となる.mf4の情報を代入 
        % 2.「handles.data_x」にログの時間（x軸として使用）を代入
        % 3.「handles.edit_chosen_file.String」にファイルパスを代入
        
        handles.mf4obj = mf4obj;
        
        % 4.「handles.lat」にログの緯度情報を代入
        % 5.「handles.lon」にログの経度情報を代入
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    end

    % グラフにプロットしたデータをクリックしてButtonDownFcnを呼び出す際、データの線そのものをクリックすると
    % 何故か引数にhandlesがないため、fig_mapのハンドルをfig_data〇〇のUserDataに予め格納しておく
    handles.fig_data1.UserData.figmaphandle = handles.fig_map;
    handles.fig_data2.UserData.figmaphandle = handles.fig_map;
    handles.fig_data3.UserData.figmaphandle = handles.fig_map;
    
    guidata(hObject,handles);
   
    clear_data(handles); % プロットされていたデータを削除

function fig_map_CreateFcn(hObject, eventdata, handles)

function mark_plot(hObject, eventdata, tgtnum)
    
    if strcmp(hObject.Tag, '') % グラフのライン部分を直接クリックした場合
    
        plottedflg = ~(isempty(hObject));
    else  % グラフの余白(ラインではない部分)をクリックした場合
        plottedflg = ~(isempty(hObject.Children));
    end
    
    if plottedflg % グラフにデータをプロット済の場合
        
        x = get(gca, 'Currentpoint'); % クリックしたグラフ上の場所の座標を取得

        persistent cp

        if ~isempty(cp)

            delete(cp);
        end
        
        % グラフにマークをプロットし、古いマークは削除（因みに100はデータの周波数[Hz]）
        if strcmp(hObject.Tag, '') % グラフのライン部分を直接クリックした場合

            cp = plot(x(1, 1), hObject.YData(round(x(1, 1) * 100)), 'ro');
            cla(hObject.Parent.UserData.figmaphandle);
            hObject.Parent.UserData.pointx = round(x(1, 1) * 100);
            hObject.Parent.Parent.UserData.tgtnum = tgtnum;
        else % グラフの余白(ラインではない部分)をクリックした場合

            cp = plot(x(1, 1), hObject.UserData.pd(round(x(1, 1) * 100)), 'ro');
            cla(hObject.UserData.figmaphandle);
            hObject.UserData.pointx = round(x(1, 1) * 100);
            hObject.Parent.UserData.tgtnum = tgtnum;
        end
    end

function fig_data1_ButtonDownFcn(hObject, eventdata, handles)
    mark_plot(hObject, eventdata, 1);
    
function fig_data2_ButtonDownFcn(hObject, eventdata, handles)
    mark_plot(hObject, eventdata, 2);

function fig_data3_ButtonDownFcn(hObject, eventdata, handles)
    mark_plot(hObject, eventdata, 3);

function set_xminmax(hObject, handles) % データの範囲を設定
    
    xmin = str2double(handles.edit_xmin.String);
    xmax = str2double(handles.edit_xmax.String);
    
    persistent pmax;
    persistent pmin;
    
    if isempty(pmax)
        pmax = 0;
        pmin = 0;
    end
    
    for i = 1:3
        
        switch i
            case 1
                subplot(handles.fig_data1);
            case 2
                subplot(handles.fig_data2);
            case 3
                subplot(handles.fig_data3);
        end
        
        if xmin > xmax; % 最小値が最大値より大きい場合
            
            % maxとmin、どちらのオブジェクトを叩いたかで分岐
            if strcmp(hObject.Tag, 'edit_xmax')

                xlim([xmin  xmin + 1]);
            else
                xlim([xmax - 1  xmax]);
            end

        elseif xmin < 0

            xlim([0  xmax]);

        elseif xmax > handles.data_x(end)
            
            xlim([xmin  inf]);

        elseif xmin == -inf && xmax == inf

            xlim([-inf inf]);

        elseif xmin == -inf

            xlim([0  xmax]);

        elseif xmax == inf

            xlim([xmin  inf]);
            
        elseif isnan(xmax)
            
            xlim([xmin  pmax]);
            
        elseif isnan(xmin)
            
            xlim([pmin  xmax]);
            
        else
            xlim([xmin  xmax]);
        end     
    end
    
    pmin = xmin;
    pmax = xmax;
    
    
function edit_xmin_Callback(hObject, eventdata, handles)
    set_xminmax(hObject, handles);

function edit_xmin_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function edit_xmax_Callback(hObject, eventdata, handles)
    set_xminmax(hObject, handles);

function edit_xmax_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function edit_chosen_file_Callback(hObject, eventdata, handles)

function edit_chosen_file_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function zoom_in_Callback(hObject, eventdata, handles)

    if str2double(handles.edit_zoom_num.String) < 20
        
        handles.edit_zoom_num.String = num2str(str2double(handles.edit_zoom_num.String) + 1);
        show_map_Callback(hObject, eventdata, handles);
    else
        warndlg('これ以上拡大できません。');
    end

function zoom_out_Callback(hObject, eventdata, handles)

    if str2double(handles.edit_zoom_num.String) > 0
        
        handles.edit_zoom_num.String = num2str(str2double(handles.edit_zoom_num.String) - 1);
        show_map_Callback(hObject, eventdata, handles)
    else
        warndlg('これ以上縮小できません。');
    end

function edit_zoom_num_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function data_setting(hObject, eventdata, handles)

    if handles.edit_chosen_file.String

        analyze_data = eventdata.Source.String(eventdata.Source.Value, :);
        tnum = str2double(eventdata.Source.Tag(end));
           
        if cell2mat(analyze_data)
        
            %%%%%%%% asammdfを使用%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % 「data_y」に選択したデータ（analyze_data）の中身を代入する
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

            switch hObject.UserData.num

                case 1
                    subplot(handles.fig_data1)
                case 2
                    subplot(handles.fig_data2)
                case 3
                    subplot(handles.fig_data3)
            end                       

            handles.pnum(tnum) = handles.pnum(tnum) + 1; % プロットしたデータの数を加算

            hold on

            switch hObject.UserData.num

                case 1
                    plot(handles.data_x, data_y, 'ButtonDownFcn', @fig_data1_ButtonDownFcn);
                case 2
                    plot(handles.data_x, data_y, 'ButtonDownFcn', @fig_data2_ButtonDownFcn);
                case 3
                    plot(handles.data_x, data_y, 'ButtonDownFcn', @fig_data3_ButtonDownFcn);
            end
        end
        
        switch hObject.UserData.num

        case 1
            handles.fig_data1.UserData.pd = data_y;
        case 2
            handles.fig_data2.UserData.pd = data_y;
        case 3
            handles.fig_data3.UserData.pd = data_y;
        end
    else
        warndlg('最初にファイルボタンを押してファイルを選択して下さい。');
    end
    
    guidata(hObject,handles);

function select_data1_Callback(hObject, eventdata, handles)
    data_setting(hObject, eventdata, handles);

function select_data1_CreateFcn(hObject, eventdata, handles)
    
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function select_data2_Callback(hObject, eventdata, handles)
    data_setting(hObject, eventdata, handles)

function select_data2_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function select_data3_Callback(hObject, eventdata, handles)
    data_setting(hObject, eventdata, handles)

function select_data3_CreateFcn(hObject, eventdata, handles)

if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end    
    
function show_map_Callback(hObject, eventdata, handles)
    
    px_fig1 = handles.fig_data1.UserData.pointx;
    px_fig2 = handles.fig_data2.UserData.pointx;
    px_fig3 = handles.fig_data3.UserData.pointx;
    
    if px_fig1 || px_fig2 || px_fig3 % データをマークしていない時に地図を表示したら警告①
        
        switch hObject.Parent.UserData.tgtnum  % データをマークしていない時に地図を表示したら警告②

            case 1
                tgtpoint = handles.fig_data1.UserData.pointx;
            case 2
                tgtpoint = handles.fig_data2.UserData.pointx;
            case 3
                tgtpoint = handles.fig_data3.UserData.pointx;
        end

        if tgtpoint

            subplot(handles.fig_map);

            persistent mp;

            hold on

                switch hObject.Parent.UserData.tgtnum

                    case 1
                        lat = handles.lat(px_fig1);
                        lon = handles.lon(px_fig1);
                    case 2
                        lat = handles.lat(px_fig2);
                        lon = handles.lon(px_fig2);
                    case 3
                        lat = handles.lat(px_fig3);
                        lon = handles.lon(px_fig3);
                end

                [XX, YY, M, Mcolor] = get_google_map(lat, lon, 'Zoom', str2double(handles.edit_zoom_num.String));

                cla; % プロット済の地図を削除

                imagesc(XX,YY,M);

                shading flat;
                colormap(Mcolor);

                mp = plot(XX(length(XX)/2), YY(length(YY)/2), '*y');

            hold off
        else
            warndlg('地図を表示するには、グラフデータをクリックしてマークを打つ必要があります。');
        end
    else
        warndlg('地図を表示するには、グラフデータをクリックしてマークを打つ必要があります。');
    end
    
function clear_data(handles, hObject)

    if nargin == 2 % 削除ボタンから呼び出した場合
        
        switch hObject.Tag

            case 'clear_button1'
                cla(handles.fig_data1);
                if handles.fig_data1.UserData.pointx
                
                    cla(handles.fig_map)
                    handles.fig_data1.UserData.pointx = 0;
                end

            case 'clear_button2'
                cla(handles.fig_data2);
                if handles.fig_data2.UserData.pointx
                
                    cla(handles.fig_map)
                    handles.fig_data2.UserData.pointx = 0;
                end

            case 'clear_button3'
                cla(handles.fig_data3);
                if handles.fig_data3.UserData.pointx
                
                    cla(handles.fig_map)
                    handles.fig_data3.UserData.pointx = 0;
                end
        end
    else % 新しいファイルを選択した場合、プロットしている全データを削除
        
        cla(handles.fig_data1);
        cla(handles.fig_data2);
        cla(handles.fig_data3);
        cla(handles.fig_map);
    end

function clear_button1_Callback(hObject, eventdata, handles)
    clear_data(handles, hObject);

function clear_button2_Callback(hObject, eventdata, handles)
    clear_data(handles, hObject);

function clear_button3_Callback(hObject, eventdata, handles)
    clear_data(handles, hObject);

```

```xml:datalist.xml
<rows>
	<row id='0'> 
		<path>simulinkmodel/subsystem1</path>
		<name>data1</name> 
	</row> 
	<row id='1'>
		<path>simulinkmodel/subsystem2</path>
		<name>data2</data>
	</row>	
	<row id='2'>
		<path>simulinkmodel/subsystem3</path>
		<name>data3</name>
	</row>
</rows>
```

## ２．get_google_map.mとその他

前述の通り、「get_google_map.m」は一部変更を加える。
199行目で使用している相互相関を算出するための関数「xcorr」は
有償の「Signal Processing Toolbox」が必要となる。

「Signal Processing Toolbox」を持っていなかったため、
相互相関を算出するための関数「cross_correlation.m」を自作し、
以下のように置き換えた。

```matlab:get_google_map(変更前).m
comparecol = floor(width/2);
c = xcorr(M(20:end,comparecol),Mcal(20:end,comparecol)); % skip first 20 pixels
c = fftshift(c);
```

```matlab:get_google_map(変更後).m
ts = 0.001; % 積分のサンプリング周期
comparecol = floor(width/2);
c = cross_correlation(0:ts:(length(M(20:(end - 1),comparecol))*ts), M(20:end,comparecol), Mcal(20:end,comparecol), ts); % skip first 20 pixels
c = fftshift(c);
```

cross_correlation.mの中身は、以下：

```matlab:cross_correlation.m
function yout = cross_correlation(xin, y1in, y2in, sampletime)

T = length(xin);

if nargin == 3 % サンプリング周期の指定がなかった場合、自動的に1に設定
   
    ts = 1;
else
    ts = sampletime;
end

    % τを少しずつずらしていく
    for a = 1 : T % a = τ のつもり

        s = 0; % τをずらす度に前回分の積算値をリセット

        for t = 1 : (T - a) % τを一定値ずらした状態で、2つの波形の積を求める（t = time）

            s = s + (y1in(t) * y2in(t + a) * ts); % 右の式を±2/Tの範囲で定積分：x(t)x(t+τ)dt
        end

        yout(a) = s; % x(t)をτの分だけずらした時の積算値を格納
    end
end
```

# 注意点

ソース上では表現しきれない、GUIの設定に関する注意点に関して、以下に述べる。


１．以下を実施すると、表示したGUIのサイズが変更できる。
ツール -> GUIオプションより、「リサイズの動作」を「比例（プロポーショナル）」に変更

２．「fig_map」（地図を表示するためのオブジェクト）のプロパティ「YDir」をreverseに変更しないと、地図が上下反転した状態で表示されるので注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271833/9626895f-753c-ab46-0628-e57f5bb23ba0.png)


# 追記：より正確性に優れる「plot_google​_map」について

「get_google_map.m」であると実際の座標よりも少しずれてしまう、しかし
「plot_google​_map.m」を使用することで正確にプロットできると、との
ご指摘をいただきました。

https://jp.mathworks.com/matlabcentral/fileexchange/27627-zoharby-plot_google_map?s_tid=mwa_osa_a

因みに get_google_map.m のダウンロードページにも、下記の記載があります。

The algorithm was determined by trial and error (as the API provides no way to query for the spacial bounds of an image), and therefore will likely produce poor results for some locations.

plot_google​_map.m は縮尺レベルが自動で設定されるなど get_google​_map.m と
比較して若干使い勝手が異なりますが、より正確にプロットする必要がある場合は
是非試してみて下さい。


# 課題
・なんか地図が汚い。。もっときれいに表示したい
・オフラインでも使用できるようにしたい

# その他の参考にさせていただいた情報

大変お世話になりました。誠にありがとうございます


|内容|リンク先|
|---|---|
|ライブラリ「get_google_map」|https://jp.mathworks.com/matlabcentral/fileexchange/24113-get_google_map|
|Googleのアカウント作成～API有効迄の手順|http://www.webdesignleaves.com/pr/plugins/googlemap_01.html|
|asammdfの情報|https://pypi.org/project/asammdf/ https://netchira.github.io/blog/python_utility/HowToStartAsammdf.html|
　 


# 最後に
ここはこうしたほうがいいぞ！ここ間違っているぞ！等あれば、お手数ですがご指摘いただけますと泣いて喜びます。