FC2ブログ

初心者によるMATLABメモ

3次元形状やってんのになぜかMATLABを使わされることになった人のメモ。

 

検索エンジンから来た方は読みたい記事が表示されていない可能性があります。
その場合、左メニューのフォームでブログ内を検索すると見たい記事を見れると思います。
もしくは、カテゴリー名をクリックしていただくと各カテゴリーの記事のリストが見れます。

[数値解析] 数値積分2

数値積分を自分で実装してみた。
ケースバイケースだが,計算速度が向上するかも。
基本的には標準関数を用いた積分を推しますけど。
保証できないので。

今回は台形公式とシンプソンの公式を自力で実装してみます。
一応台形公式とシンプソンの公式はこれ。詳しくはググってください。
台形公式
ex001
シンプソンの公式
ex001

例の関数としては,標準関数を用いた積分のときと同じ下記の関数を0,1の範囲で定積分してみます。
ex001
>> func1 = @(x) x+x.^2;

まずは組み込み関数quadとquadlによる計算。
>> % 組み込み関数 quad
quad(func1,0,1,[],[])
ans =
    0.8333
>> % 組み込み関数 quadl
quadl(func1,0,1,[],[])
ans =
    0.8333
ここからが自力での実装になります。台形公式はこれ↓。
ex001
で,MATLABで書くとこんな感じでいけます。ddは刻み幅です。
>> % 台形公式
dd=1e-3;
vv=func1(0:dd:1);
(vv(1)+vv(end)+2*sum(vv(2:end-1)))*dd/2
ans =
    0.8333
とりあえず台形公式による計算は上手くできるようになりました。
続いてシンプソンの公式に行きます。
公式自体ははこれ↓です。
ex001
シンプソンの公式は,MATLABで書くとこんな感じ。ddは同じく刻み幅。こちらも問題なく計算できます。
>> % シンプソンの公式
dd=1e-3;
vv=func1(0:dd:1);
(vv(1)+vv(end)+4*sum(vv(2:2:end-1))+2*sum(vv(3:2:end-1)))*dd/3
ans =
    0.8333
で,最後に自分で実装してみたものと標準関数との計算時間の比較をしてみた。
あ,それと最後に自分で実装したものの精度をみていなかったので,quadlのときと比較してみました。
一応1e-6くらいの違いなので自分で実装したものでも問題ないかなぁと。
特にシンプソンの公式の方は。
>> func1 = @(x) x+x.^2;
>> % 組み込み関数 quad
>> tic;qq0=quad(func1,0,1,[],[]);toc;
経過時間は0.033797秒です
>> % 組み込み関数 quadl
>> tic;qq1=quadl(func1,0,1,[],[]);toc;
経過時間は0.037857秒です
>> % 台形公式
>> tic;dd=1e-3;vv=func1(0:dd:1);qq2=(vv(1)+vv(end)+2*sum(vv(2:end-1)))*dd/2;toc;
経過時間は0.001613秒です
>> % シンプソンの公式
>> tic;dd=1e-3;vv=func1(0:dd:1);qq3=(vv(1)+vv(end)+4*sum(vv(2:2:end-1))+2*sum(vv(3:2:end-1)))*dd/3;toc;
経過時間は0.001331秒です
>> disp(qq1*ones(1,4)-[qq0,qq1,qq2,qq3]);
  1.0e-006 *
         0         0   -0.1667   -0.0000
ちなみに上の例をみると明らかに僕が実装したコードの方が標準関数より早いですが,
例えば刻み幅を1e-6に変えてみると,相当遅くなります。
ちょっと今回計算してるのが簡単な式なのでよくわからないのですが,まぁ余裕あるなら自分の対称の関数に対して両方を精度と計算速度を比較してみて,いい感じなら標準関数でないコードで実装するのもよいのかもしれません。
>> % 台形公式
>> tic;dd=1e-6;vv=func1(0:dd:1);qq2=(vv(1)+vv(end)+2*sum(vv(2:end-1)))*dd/2;toc;
経過時間は0.077826秒です
>> % シンプソンの公式
>> tic;dd=1e-6;vv=func1(0:dd:1);qq3=(vv(1)+vv(end)+4*sum(vv(2:2:end-1))+2*sum(vv(3:2:end-1)))*dd/3;toc;
経過時間は0.135337秒です


スポンサーサイト



このエントリに付けられたタグ|MATLAB積分台形公式シンプソンの公式

[ファイル操作] Excelファイル(.xls)を読み込む

[2006/12/11] 内容修正

前にCSV形式のデータの読み書きについて書きましたが,
さらに欲張って「エクセルファイルを読み込ませたい!」場合もあるかなぁと思ってこちらも掲載。

ExcelファイルをMATLABに読み込むには基本的には下記だけで十分です。
data = xlsread('filename')
[data, text] = xlsread('filename')
[data, text] = xlsread('filename',シート番号)
[...] = xlsread('filename','sheetname')

要は基本は下記です。
[数値データ, テキストデータ] = xlsread(ファイルの名前,シート番号orシートの名前)

以下,これらについて実際に実行例を。
ここでは下記のような3つのシートを持つExcelファイルを読み込ませるとします。

1枚目のシート(TEST)
EXCEL 003

2枚目のシート(Sheet2)
EXCEL 003

3枚目のシート(Sheet3) = 縦もテキストデータです。
EXCEL 003

まず簡単にエクセルファイルのデータと項目を読み込んでみます。
ちなみにここで左辺をただ単にdataだけにすると1行目のヘッダは削除されデータだけが取り出せます。
>> [data, header] = xlsread('test.xls')
data =
    1.0000    0.5000
    2.0000    0.2400
    3.0000    0.6000
    4.0000    0.7000
    5.0000    0.5000

header = 
    'column1'    'column2'

続いて2枚目だけを読み込ませたいときはこうします。
この例から先程のxlsread('test.xls')はxlsread('test.xls',1)の省略形だということがわかります。
>> [data, header] = xlsread('test.xls',2)
data =
    1.0000    0.5000    1.5000
    2.0000    0.2400    2.2400
    3.0000    0.6000    3.6000
    4.0000    0.7000    4.7000
    5.0000    0.5000    5.5000

header = 
    'column1'    'column2'    'sum'

こちらは2枚目だけを読み込む他の例。もちろん結果は同じです。
>> [data, header] = xlsread('test.xls','Sheet2')
data =
    1.0000    0.5000    1.5000
    2.0000    0.2400    2.2400
    3.0000    0.6000    3.6000
    4.0000    0.7000    4.7000
    5.0000    0.5000    5.5000

header = 
    'column1'    'column2'    'sum'

ここで,関数xlsfinfoというMicrosoft Excel(.xls)のファイルであるかを調べ,そうであればシートの名前をセル配列を返す関数を紹介しておきます。
こちらはこちら読めばすぐ分かると思います。
>> [a,sheets] = xlsfinfo('test.xls')
a =
Microsoft Excel Spreadsheet

sheets = 
    'TEST'    'Sheet2'    'Sheet3'

今度は,xlsreadとxlsfinfoを利用して,Excelファイルの全てのシートを操作する簡単なコードを紹介しておきます。
こんな感じで処理すれば全部をシートを処理できます。
ここで注目してもらいたいのはシート3です。
シート3を見ると分かると思いますが,xlsreadによって返されたデータは,綺麗に数値データとテキストとに分けて返されます。
2つをマージすれば元通りというか,まぁそんな感じです。
ちなみに,ここではテキストデータは外周だけなのでxlsreadが勝手に削除しているので数値データ内にテキストデータを含みませんでしたが,
数値データ内にテキストデータが含まれる場合は,ここにもあるとおり,テキストデータ部分はNaNに置換されて出力されます.
>> [a,sheets] = xlsfinfo('test.xls');
>> for ind=1:length(sheets)
    disp('---');
    disp(sheets(ind));
    [data, header] = xlsread('test.xls',ind)
end; 
---
    'TEST'
data =
    1.0000    0.5000
    2.0000    0.2400
    3.0000    0.6000
    4.0000    0.7000
    5.0000    0.5000

header = 
    'column1'    'column2'

---
    'Sheet2'
data =
    1.0000    0.5000    1.5000
    2.0000    0.2400    2.2400
    3.0000    0.6000    3.6000
    4.0000    0.7000    4.7000
    5.0000    0.5000    5.5000

header = 
    'column1'    'column2'    'sum'

---
    'Sheet3'
data =
    11    12    13
    21    22    23
    31    32    33

header = 
         ''    'COLUMN1'    'COLUMN2'    'COLUMN3'
    'LINE1'           ''           ''           ''
    'LINE2'           ''           ''           ''
    'LINE3'           ''           ''           ''

気が向いたらもう少し複雑な例を載せたいと思います。グラフ化するとかそんなのを。

xlsread (MATLAB Function Reference)
xlsfinfo (MATLAB Function Reference)

[2006/12/13] もう少し複雑な例を載せました→Excelファイル(.xls)を読み込む2
このエントリに付けられたタグ|MATLABファイル操作Excelエクセル

[その他] おすすめの1冊:MATLAB数値解析

MATLABを始めるに当たって本を見る方など多いかと思いますが,いろいろ出ているMATLABの初心者向けの本を読むと結局
「MATLABは動くようになったけど結局やりたいことができない…」
みたいな状況に陥りやすいと思います。

一応MATLABを初めて2ヶ月ちょっとで6,7冊ほど読みましたが,
その中で実用で一番役に立ってる日本語の本がこれ↓です。
MATLAB 数値解析Amazon.co.jp: MATLAB数値解析: 本: G.J.Borse,臼田 昭司

この本は,MATLAB的な内容としてはちょっと古いですが,数値解析で使う基本的な手法をいろいろ網羅しつつ,その理論の説明とMATLABのサンプルプログラムが載っています。
サンプルプログラムはオマケのCD-ROMにも入ってるんで,簡単なことならそのままコードを弄れば使いまわせたりすると思います。
内容としては,厚い本なので中身を網羅して書けませんが,だいたいこの辺りがカバーされていています。
  1. 線形解析と行列
  2. 行列方程式
  3. 最小化,最大化
  4. 微分,積分
  5. モンテカルロ積分
  6. フーリエ解析
  7. 微分方程式
上記の目次の内容などは工学系の学生なら普通に使うところであると思うんで,工学系の学生でMATLABを使うなら,かなり役に立つと思います。

と,思ったのですが…
しかし,なぜかこの本、オーム社で
このような方におすすめ
・制御系を中心のした工学者・技術者
・数値を扱う理学・社会学の研究者および院生レベルの学生
オーム社:MATLAB数値解析

と紹介されてます。
制御系の話とかほとんど触れてないのに…

むしろ工学系の卒論生とかこそ,この本を見るだけで卒論の理論の部分も書けますし,サンプルプログラムとかも使えるので役立つ気がするんですけどねぇ。
オーム社売る気ないのか?…

あ,ちなみにお値段は結構高いので卒論生とかなら研究室で買ってもらった方が良いと思います。
このエントリに付けられたタグ|MATLAB数値解析

[ファイル操作] Excelファイル(.xls)を読み込む2

先日MATLABでExcelファイル(.xls)を読み込む簡単な例を紹介しましたが,そこで予告したとおりpart.2としてもう少し複雑なエクセルファイルを読み取り,グラフとして表示してみます。

ここで,データとしては総務省 統計局・統計研修所HP内の世界人口の推移のデータのExcelファイルを利用しました。
実際に試して見たい人は下記URLよりダウンロードできます。
実際に使ったExcelファイルは「2-1 世界人口の推移(1950~2050年)」って項目のやつです。
総務省 統計局・統計研修所HP内>世界の統計-第2章 人 口

以下,このExcelファイルを基に世界全体と各地域ごとの人口推移を折れ線グラフとして表示するMファイルを作成してみます。
実際に上記のURLからExcelファイルをDLして見ながらこのエントリを読んだほうが分かりやすいかと思います。

今までのサンプルよりは多少長いソースですが,やってることはすごく簡単なのでソース全体は個々で見てもらうとして,流れとしてはまず,先日のエントリでも説明したとおりxlsreadによってEXCELのファイルを読み込みます。
% EXCELファイルからのデータ読み込み
[data, tdata] = xlsread(EXCELFILE,1);

続いて,数値データdataの処理部分ですが,ここで肝になっているのは下記部分でしょうか。
標準関数isnanとfindを組み合わせて1行全部が数値データでない行を削除しています。
rows = find(isnan(data(:,1)));
data(rows,:) = [];

また,文字列データtdataの処理部分では,下記で空のデータ行を削除しています。
標準関数strcmpについてはコマンドウインドウでhelp strcmpとして確認してください。
rows = strcmp(tdata(:,2),'');
tdata(rows,:)=[];

最後にグラフ化の部分ですが,そういえばこのブログでグラフとかの説明は未だしてないなぁとか思いました。
グラフ化の部分はちょっとまた別の話になるのでまたの機会にということで,
ここではこうしたらグラフが表示されるんで…
と逃げておきます。

以下に,実際に実行したMファイルのソース全体を載せます。
ちなみにダウンロードした0201.xlsは下記のMファイルと同じディレクトリにあるとします。
(一応デモのMファイルをUPしてあります。(拡張子を.txtから.mに変更してください))
% 総務省 統計局・統計研修所HP内>世界の統計-第2章 人 口
% http://www.stat.go.jp/data/sekai/02.htmのエクセルファイルより,
% 人口推移を折れ線グラフとして表示する.
clear all;
close all;

% 読み込ませるEXCELファイル
EXCELFILE = '0201.xls';

% EXCELファイルのチェック
[a,sheets] = xlsfinfo(EXCELFILE);
if ~strcmp(a,'Microsoft Excel Spreadsheet') error('0201.xlsはMicrosoft Excelのシートを含まないファイルです.'); end;

% EXCELファイルからのデータ読み込み
[data, tdata] = xlsread(EXCELFILE,1);

%===================  数値データの処理
% 数値データの不要なデータ削除
data = data(:,1:8);
rows = find(isnan(data(:,1)));
data(rows,:) = [];

% 年度ラベルの抽出と数値データからの削除
years = int16(data(:,1));
data(:,1) = [];

%===================  テキストデータの処理
% グラフタイトルの抽出
graph_title = tdata(1,1);

% 不要データ削除
tdata = tdata(:,1:8);
rows = strcmp(tdata(:,2),'');
tdata(rows,:)=[];
tdata(3,:)=[];  % 「将来推計」の文字の削除

% グラフの凡例用テキストと軸ラベルの抽出
tdata(strcmp(tdata,'')) = [];
labelX = tdata(1);
labelY = strcat('人口 ',tdata(3));
tdata([1,3]) = [];
legends = regexprep(tdata,'n','');  % なぜか'アフnリカ'となっているので改行を削除

%===================  グラフ化の処理
nowind=find(years==2004);
ind1=1:nowind;  % 2004度までのインデクス
ind2=nowind:length(years);  % 2004度以降のインデクス

% FIGURE ハンドルの生成
scrsz = get(0,'ScreenSize');
figH = figure('PaperSize', [20 10],'InvertHardcopy', 'off', ...
'Color', [1 1 1], 'Position', [200 scrsz(4)-620 560 520]);
figsz = get(figH,'Position');

% 軸作成
ax = axes('Parent', figH, 'PlotBoxAspectRatio', [1 1 1]);
box('on');
hold('all');

% 世界全体の変化グラフ -----
grH1 = subplot(1,2,1);
subplot(grH1), plot(years(ind1), data(ind1,1), 'b-' ...
    ,years(ind2), data(ind2,1), 'b:' ...
);
set(grH1,'Position',[60/figsz(3) 35/figsz(4) 200/figsz(3) 430/figsz(4)]);

% グラフタイトル
title('世界全体の人口変化','FontSize',10);

% 軸ラベル
xlabel(labelX,'FontSize',9);
ylabel(labelY,'FontSize',9);

% 凡例の表示
lh = legend(legends(1), 'Location', 'NorthWest', ...
'FontSize',8, 'Box', 'off', 'Color', 'none', 'EdgeColor', [1 1 1]);

% 地域ごとの人口変化のグラフ -----
grH2 = subplot(1,2,2);
subplot(grH2), plot(years(ind1), data(ind1,2), 'm-' ...
    ,years(ind1), data(ind1,3), 'k-' ...
    ,years(ind1), data(ind1,4), 'b-' ...
    ,years(ind1), data(ind1,5), 'r-' ...
    ,years(ind1), data(ind1,6), 'g-' ...
    ,years(ind1), data(ind1,7), 'c-' ...
    ,years(ind2), data(ind2,2), 'm:' ...
    ,years(ind2), data(ind2,3), 'k:' ...
    ,years(ind2), data(ind2,4), 'b:' ...
    ,years(ind2), data(ind2,5), 'r:' ...
    ,years(ind2), data(ind2,6), 'g:' ...
    ,years(ind2), data(ind2,7), 'c:' ...
);
set(grH2,'Position',[340/figsz(3) 35/figsz(4) 200/figsz(3) 430/figsz(4)]);

% グラフタイトル
title('地域ごとの人口変化','FontSize',10);

% 軸ラベル
xlabel(labelX,'FontSize',9);
ylabel(labelY,'FontSize',9);

% 凡例の表示
lh = legend(legends(2:end), 'Location', 'NorthWest', ...
'FontSize',8, 'Box', 'off', 'Color', 'none', 'EdgeColor', [1 1 1]);

% グラフ全体のタイトル追加
annotation(figH,'textbox','String',graph_title,'HorizontalAlignment','center', ...
'FontSize',12, 'EdgeColor','none', 'Position',[0 1-20/figsz(4) 1 20/figsz(4)], 'FitHeightToText', 'on');

上記,Mファイルを実行してみると,下記のようなグラフが表示されると思います。
EXCELから書いたグラフ

まぁ,こんな感じでテキスト交じりのExcelのデータを処理することができます。
ちなみにそのままExcelでグラフ書いた方が早いじゃん!
ってツッコミはなしで。あくまでも例ですので。
このエントリに付けられたタグ|MATLABファイル操作Excelエクセルグラフ

[ファイル操作] ファイルの拡張子を調べる

まさにブログのタイトル通り完全にこのエントリはメモ…
MATLABでファイルの拡張子を調べる方法。
これは,標準関数のfilepartsとstrcmpiを組み合わせることで実現できます。

まず単純にファイルの拡張子が欲しいときは,下記を実行するとextに'.拡張子'とドット付きの拡張子が返って来ます。
[pathstr,name,ext,versn] = fileparts(ファイルのパス);

これは説明するよりサイバネットのサイトを見てもらったほうが早いかと思います。

で,本題ですが例えばこんな感じの関数を作れば,指定したファイルが指定した拡張子であるか判別することができます。
ここで,一応拡張子は大文字だったり,小文字だったりするのでstrcmpiで比較してみます。
function boo = CheckFileFromExtension(filepath, fext) 
% CheckFileFromExtension : ファイルの拡張子が指定した拡張子であるか判別する関数
% CheckFileFromExtension(ファイルのパス, 指定した拡張子)
[pathstr,name,ext,versn] = fileparts(filepath);
boo = strcmpi(ext,strcat('.',fext));

実際にこれを使ってみるとこんな感じになります。
test.csvがcsvファイルかを調べてみるとこんな感じで関数CheckFileFromExtensionによって判定できることがわかります。
>> if CheckFileFromExtension('test.csv','csv') 
    disp('CSVファイルです。');
else
    disp('CSVファイルではありません。');
end;
CSVファイルです。

で,続いて拡張子が大文字の場合。
この場合ももちろん同じ結果が返ります。
>> if CheckFileFromExtension('TEST2.CSV','csv') 
    disp('CSVファイルです。');
else
    disp('CSVファイルではありません。');
end;
CSVファイルです。

で,一応xlsファイルを指定して,わざと失敗してみた例がこれ。
>> if CheckFileFromExtension('test.xls','csv') 
    disp('CSVファイルです。');
else
    disp('CSVファイルではありません。');
end;
CSVファイルではありません。

と,まぁこんな感じで拡張子を取り出せます。
今回は関数化してみましたが,この程度なら関数化しなくて,いいんじゃないかともちろん思います(w

fileparts (MATLAB Function Reference)
strcmpi (MATLAB Function Reference)
このエントリに付けられたタグ|MATLABファイル操作拡張子

[ファイル操作] 相対パスから絶対パスに変換する

2007/02/06 これだと指定したパスのファイルが存在しないとコケるので修正版がこっちに↓
初心者によるMATLABメモ| 相対パスから絶対パスに変換する2


またメモ的エントリですが,相対パスから絶対パスを知る方法。
僕は結構使うこと多いので,メモっておく。
これは標準関数fileattribを使えばできます。
fileattribについてはこちらを参照してください。絶対パスだけでなくディレクトリかどうか?とかの他の情報も取得できます.
で,相対パスから絶対パスを知るにはこうすればよいです。
>> pwd
ans =
C:Program FilesMATLABR2006bwork
>> [num,pathinfo] = fileattrib('../');
>> pathinfo.Name
ans =
C:Program FilesMATLABR2006b

頻繁にそういった機会があるという人はこんな感じの関数を用意しておいてもいいかもしれません。
コレ↓適当に書いてますけど
function apath = relative2absolute_path(rpath);
% 相対パスから絶対パスに変換する関数
[num,pathinfo] = fileattrib(rpath);
apath = pathinfo.Name;

使うとこんな感じで相対パスから絶対パスに変換されます。
>> pwd
ans =
C:Program FilesMATLABR2006bwork
>> relative2absolute_path('../bin')
ans =
C:Program FilesMATLABR2006bbin

というかそもそもこういった感じの標準関数はないのかしら?

fileattrib (MATLAB Function Reference)
このエントリに付けられたタグ|MATLABファイル操作相対パス絶対パスディレクトリフォルダ

[基本] 計算時間の表示

とりあえず,結論から先に言うと経過時間を表示する標準関数のetime()だけは使わない方がよいです。
なぜならこのetime。
月をまたいだり,年越しをまたいだりするとコケるらしいので。
実際にドキュメントにも明示されてます。なんでこんなのが標準関数としてあるのやら…
Limitations

As currently implemented, the etime function fails across month and year boundaries. Since etime is an M-file, you can modify the code to work across these boundaries if needed.
etime :: Functions (MATLAB Function Reference)

制限

関数etimeは、現状では月や年が変わる場合は使えません。etimeはM-ファイルなので、必要な場合、コードを書き換えてください。
etime (MATLAB Function Reference)

で,なんでこんなの書いたかというと最初本で見てetimeで計算時間を僕は表示させてたので。
こんな感じ↓で。
% 計算所要時間の表示
startT = clock();

% 自分の計算

endT = clock();
ntime = etime(endT,startT);
nhour = floor(ntime/60/60);
nmin = floor((ntime-nhour*3600)/60);
nsec = ntime-nhour*3600-nmin*60;
disp(sprintf('%s%s', '開始時間:',datestr(startT,31)));
disp(sprintf('%s%s', '終了時間:',datestr(endT,31)));
disp(sprintf('%s%d%s%02d%s%04.1f%s', '計算所要時間:',nhour,'時間',nmin,'分',nsec,'秒'));

で,こんな感じに書き換え。結局tic;toc;で書くことにしました。
% 計算所要時間の表示
startT = now();
tic;

% 自分の計算

ntime=toc;
nhour = floor(ntime/60/60);
nmin = floor((ntime-nhour*3600)/60);
nsec = ntime-nhour*3600-nmin*60;
disp(sprintf('%s%s', '開始時間:',datestr(startT,31)));
disp(sprintf('%s%s', '終了時間:',datestr(now,31)));
disp(sprintf('%s%d%s%02d%s%04.1f%s', '計算所要時間:',nhour,'時間',nmin,'分',nsec,'秒'));

まぁこんな↓のでもいいと思いますが。
あ、いやむしろこっちの方が同時にいろいろ使えていいのか?よく考えると。
あぁいや、それも違うや。tic;toc;もtoc何回も呼び出せば同じか。
% 計算所要時間の表示 
startT = clock();
startCpuT = cputime;

% 自分の計算

ntime=cputime-startCpuT;
nhour = floor(ntime/60/60);
nmin = floor((ntime-nhour*3600)/60);
nsec = ntime-nhour*3600-nmin*60;
disp(sprintf('%s%s', '開始時間:',datestr(startT,31)));
disp(sprintf('%s%s', '終了時間:',datestr(clock,31)));
disp(sprintf('%s%d%s%02d%s%04.1f%s', '計算所要時間:',nhour,'時間',nmin,'分',nsec,'秒'));

しかし,機を見てetime()をオーバーライトしておかないと今に忘れて使うな。絶対。

と,己がそれを忘れないためのエントリ。

関数 - カテゴリ別 (MATLAB Function Reference)日付と時間演算
etime (MATLAB Function Reference)
clock (MATLAB Function Reference)
cputime (MATLAB Function Reference)
tic, toc (MATLAB Function Reference)
このエントリに付けられたタグ|MATLAB時間計算時間tictocetime