謹賀新年

(遅くなりましたが)あけましておめでとうございます

本年もよろしくお願いいたします。

今年の干支をウェーブレットで描かしてみました。
必要な環境は id:ikeuchihiroki:20090102 と同じです。

from pylab import *
import iwavelets.pycwt as w

#Generate Time series
Fs = 1024.0*4
time  = arange(0,3.0/4.0+1.0/8.0,1/Fs)

#horizontal lines
signal=sin(2*pi*200*time)+sin(2*pi*100*time)
signal[0:Fs/2+Fs/8]+=sin(2*pi*300*time[0:Fs/2+Fs/8])

win=zeros(signal.size)
win[Fs/8:Fs-Fs/4]=(ones(Fs-Fs/4-Fs/8))

signal=signal*win

#vertical lines
t0=time[0:Fs/8]
sig1=sin(2*pi*(100+t0*200*4)*t0)

signal[Fs/4:Fs/4+Fs/8]+=sig1*2
signal[Fs/2:Fs/2+Fs/8]+=sig1*2

#Frequency array
freqs=arange(1.0,400.0,1.0)

#Morlet fc
fc=5

#calc
r=w.cwt_f(signal,freqs,Fs,w.Morlet(fc))
rr=r.real**2+r.imag**2

#show
clf()
imshow(flipud(rr),aspect='auto',extent=(time[0],time[-1],freqs[0],freqs[-1]))

xlabel('Time[s]')
ylabel('Frequency[Hz]')

show()

#output Wave file
import wave
f=wave.open('test.wav','wb')
f.setnchannels(1)
f.setframerate(Fs)
f.setsampwidth(2)
f.writeframes(signal)
f.close()

Pythonで連続ウェーブレット解析

swanという連続ウェーブレット解析のモジュールがあった。
swan-0.5.4a.tar.gzを試してみる。

必要なモジュール

Gtkは最新版2.12.9を入れた。
PyGtkはバイナリからインストール。

swanはアーカイブを展開して、

python setup.py install

とする。ただし、Windowsの場合はそのままではインストールできないので、
setup.cfgを以下のように書き換えてから実行する。

# very basic config

[install]
prefix=C:\Python25
optimize=2

インストール後にC:\Python25\Scriptsに「swan」というファイルができるので

move swan swan.py

としておく。

試す

2. Simple usageを見ながら

まずは信号をつくる。「ipython -pylab」で起動して

import math,numpy,scipy,matplotlib

Fs = 65.0
time  = arange(0,16,1/Fs)
signal = sin(2*pi*1.2*time) + cos(2*pi*3.7*time)
save('signal.dat', signal)

実行はコマンドプロンプトから

swan.py -s 65 signal.dat

として、Apply CWTを押すと実行される。

pycwtのみを使ったプログラム

swan: some visible examplesにあるように、GUIなしでプログラムを書いてもよい。

import pylab as p
import iwavelets.pycwt as w

Fs = 65.0
time  = p.arange(0,16,1/Fs)
signal = p.sin(2*p.pi*1.2*time) + p.cos(2*p.pi*3.7*time)

freqs=p.arange(0.1,5,0.025)
fc=1.5

r=w.cwt_f(signal,freqs,Fs,w.Morlet(fc))
rr=r.real**2+r.imag**2

p.imshow(p.flipud(rr),aspect='auto',extent=(time[0],time[-1],freqs[0],freqs[-1]))

p.xlabel('Time[s]')
p.ylabel('Frequency[Hz]')

p.show()

つかえそうだ。

numpy、SciPy、matplotlib

ikeuchihiroki2009-01-02

Pythonは科学計算にもよくつかわれるようだ。

科学者に必要なpythonモジュールはなにか
科学者のための Python 入門


とりあえず、Python本体に加えて以下のモジュールをインストールしてみる。

準備

Pythonインストーラーで簡単にインストールできる。最新はPython 3.0だが使いたいモジュールが対応していないので、Python 2.5.2を選ぶ。

次に、SetupToolsをインストールする。同じくインストーラーでインストールする。SetupToolsは、easy_installというモジュールのダウンロードからインストールまでを自動でするコマンドが含まれる。
SetupToolsインストール後に、PATHを通しておく必要がある。マイコンピューター右クリック→プロパティ→詳細設定→環境変数→PATHに「C:\Python25\Scripts;C:\Python25;」を追加する。

モジュールをインストール

  • numpy
  • SciPy
  • pyreadline

は、EXEのインストーラーでインストールする。easy_installの場合コンパイルが必要になるからだ。
pyreadlineはIPythonのサイトからダウンロードできる。

  • matplotlib
  • Python Image Library
  • IPython

は、easy_installでバイナリをダウンロード、インストールできた。
コマンドシェルにて

easy_install matplotlib
easy_install PIL
easy_install IPython

と入力する。

試してみる

コマンドシェルにて

ipython -pylab
import math,numpy,matplotlib,scipy
t=linspace(0,1,1024);
y=sin(2*pi*10*t);
plot(t,y)

title 'Sin Plot'
xlabel 'Time[s]'
ylabel 'Amplitude'

けっこう使えそうだ。
ScilabMatlabも)は、言語仕様が独特すぎてプログラムが読みにくい書きにくい印象があったが、Pythonならば可読性がよいプログラムが書けそうだ。

追記

http://www.enthought.com/に、科学計算に使うモジュール一式がある。必要に応じてサポート付きのライセンスもあるようだ。プロユースにも使えそう。

Scilabで連続ウェーブレット解析

id:ikeuchihiroki:20070222 で書いたように、連続ウェーブレット解析ができるフリーの環境というのはなかなか良いものがない。
Scilab上で動作するTOOLBOXでは以下のものがある。

  • Wavelab
  • Fraclab
  • Scilab Wavelet Toolbox

Scilab Wavelet Toolbox http://scwt.sourceforge.net/ は、小規模なウェーブレットツールボックスなのだが、地味に更新が続けられている。
連続ウェーブレット変換のコードはCで書かれていて、なかなか速い。

テストプログラム

fs=512;

x=[0:2047]/fs;
y=sin(2*%pi.*x.*(x/max(x)*64));

//        increase memory size
stacksize(10000000);

//        continous wavelet transform
scal=2^[1:1/32:6];
coef=cwt(y,scal,'cmor');

//        colormap obtaining
cmap=jetcolormap(512);
//        matrix normalization
n=wcodemat(abs(coef),512);

scf(0);
clf;
f=gcf();f.color_map=cmap;
xlabel Time[s]
ylabel Frequency[Hz]

getf scal2freq.sci

a=gca();

Matplot(n);


なかなかいい感じ。
でも、このままだと縦軸の意味がわからないので、スケールを周波数に変えて表示するようにしたい。
MATLABには、スケールを周波数に変換する関数が存在したので、同じような機能をする関数を書いてみる。

function [frq]=scal2freq(A,wname,fs)

  y=zeros(512,1);
  y($/2)=1;
  
  coef=cwt(y,A,wname);
  
  frq=[];
  for k=1:length(A)
    fftcoef=abs(fft(coef(k,:)));
    [m ind]=max(fftcoef,'c');
    
    tmp=ind-1;
    if tmp > length(y)/2
      tmp=length(y)-tmp;
    end
    frq=[frq;tmp/length(y)*fs];
  end
    
    
endfunction

Aがスケール、wnameがウェーブレットの名前、fsはサンプリング周波数。
理屈は簡単で、インパルスをウェーブレット変換して、各スケールの中心周波数を見ているだけだ。たぶん理屈はあっているはずだ。CWTの関数の制約上、スケールは長さ2以上のベクトルを入れないといけないので注意。

次に、縦軸横軸を調整する関数。

function coefs=cwt_plot(data,scal,wname,fs)
//plot settings
y_ticks_distance=16;

//        increase memory size
stacksize(10000000);

coef=cwt(data,scal,'cmor');

//        colormap obtaining
cmap=jetcolormap(512);
//        matrix normalization
n=wcodemat(abs(coef),512);

scf;
clf;
f=gcf();f.color_map=cmap;
xlabel Time[s]
ylabel Frequency[Hz]

getf scal2freq.sci

a=gca();

ay=a.y_ticks;
ay.locations=[0:y_ticks_distance:length(scal)]';
frq=scal2freq(scal($:-y_ticks_distance:1),'cmor',fs);
ay.labels=string(frq);
a.y_ticks=ay;


Matplot(n);

ax=a.x_ticks;
ax.labels=string(ax.locations/fs);
a.x_ticks=ax;
endfunction

dataは解析対象信号,scalはスケール,wnameはウェーブレット関数の名前,fsはサンプリング周波数。
ウェーブレット関数の名前は、cwt.cを見るとわかる。今のところ以下の関数が使える。

sinus,poisson,mexh,morl,DOG,
gaus1,gaus2,gaus3,gaus4,gaus5,gaus6,gaus7,gaus8,
cmor,shan,fbsp,cauchy,
cgau1,cgau2,cgau3,cgau4,cgau5,cgau6,cgau7,cgau8

使用例:

fs=512;

x=[0:2047]/fs;
y=sin(2*%pi.*x.*(x/max(x)*64));

cwt_plot(y,2^[1:1/32:8],'cmor',fs);


縦軸、横軸がサンプリング周波数に合わせて適正な表示になった。

意外にScilab Wavelet Toolboxが良い感じだ。

[Scilab] Scilabの変数スコープについて

Scilabは、変数のスコープの扱いが独特だ。
関数を作るときには、注意しないとややこしいことになるので、知っておかないとまずいと思い、ドキュメントを訳してみた。

http://wiki.scilab.org/howto/global_and_local_variables
より

In what follows level_0 is the level of the interactive shell; level_1 is that of functions called from level_0, level_2 that of subfunctions of level_1, and so on.

local variables and scoping

  1. local variables, which are not defined at level_N, are inherited from upper levels
  2. local variables defined at level_N remain local at that level. If a level_N variable has the same name of an upper level variable, a transient duplicate variable is created at level_N
  3. local variables inherited from upper levels can be read with no overhead; but if they are written, a transient local with the same name is created (not returned back unless specifically required). Note that the transient variable is first initialized to []; thus if this variable is implicitly grown (by assigning array elements beyond the current size), the local transient overrides over the outer variable.
  4. the appearance of the variable on an empty line of a function (which would cause immediate display at level_0) is sufficient to create the local duplicate
  5. input values of the function are assigned to the corresponding local variables of the function
  6. output arguments of a function are assigned upon return, at the upper level, to those variables specified in the function call
  7. argument passing is thus by value, in common programming terms; however, as in 3., the value is not really copied unless needed; for reading only, passing is by reference. So to say, it is a "lazy" passing by value, as copying the value is delayed to when really needed in the progam flow.
  8. only for adequately written primitives and interfaces of primitives, there is an option of by value/by reference (see intppty)
  9. local variables can be returned to their immediate upper level with resume. The difference between resume and output arguments is that resume specifies the name of the upper variable which is assigned, output values are assigned to whatever name choosen at the caller level.
  10. the command for undefining local variables is clear

Global variables

  1. global variables can have the same name of local variables, and coexist (the two namespaces are separate)
  2. global variables are shared by all scopes in which they are declared global, respectless of their calling depth
  3. declaring a variable global in a function does not help in making an upper local variable with the same name visible in the function: the upper local is already visible, and a global declaration can have unexpected side effects
  4. only when a variable is declared global, assignments affect its global version
  5. if a variable is declared global, and a local variable with the same name already exists, the value of the local is copied to the newly created global
  6. if a variable is declared global, and a local variable with the same name does not exist, an empty matrix [] is created in the global namespace and a pointer to it is created in the local namespace.
  7. the command for undefining global variables is clearglobal

適当に訳してみた。よくわからないところは意訳になっているので、内容は保障しません。

level_0はインタラクティブシェルのレベルである。
level_1はlevel_0から呼び出された関数であり、level_2はlevel_1から呼び出されたサブ関数である。それ以降も同様。

ローカル変数とスコープ

  1. level_Nで定義されていないローカル変数は、上位のレベルから引き継がれる
  2. level_Nで定義されているローカル変数は、そのレベルに留まる。もし、level_Nの変数が上位レベルの変数と同じ名前である場合、一次的な複製がlevel_Nで作成される
  3. 上位レベルから引き継がれた変数は、オーバーヘッド無しに読み込むことができる。しかし、書き込みがある場合、一時的に同じ名前を持つ変数が作成される(特に指定されることがない限り上位レベルの値は更新されない)。この際に作成される一時的な変数の初期値は[]である点に注意すべきである。もし、この変数の領域が拡大する場合(配列の要素サイズが再定義されるような場合)、上位レベルの値は引き継がれない。
  4. 変数単体を記述したライン(level_0に内容が表示される)は、ローカルに複製を生成する
  5. 関数の引数は、ローカル変数になる
  6. 関数の戻り値は、関数を呼び出した上位レベルの変数になる
  7. 引数は値渡しでおこなわれるが、「3.」のような読み込みのみで複製の必要がない値は、参照渡しで行われる。値の複製が行われる「のろのろ」した値渡しは、プログラムを遅くする原因であるからである。
  8. 基本的には、値渡し・参照私のオプションは存在しない(intpptyを見よ)
  9. resumeを使うとローカル変数は上位レベルに戻すことができる。resumeと戻り値の違いは、resumeは上位レベルでの変数名を指定できるのに対し、戻り値は呼び出し側で名前を指定する
  10. ローカル変数を消去するコマンドはclearである

グローバル変数

  1. グローバル変数は、ローカル変数と同じ名前を持つことができ、同時に存在できる(2つの名前空間は分けられている)
  2. グローバル変数は、コールの深さによらず、すべてのスコープで共有される
  3. 関数内でグローバル変数を定義しても、上位レベルで同じ名前のローカル変数は生成されない。上位レベルに同名のローカル変数が存在する場合に予期せぬ影響が考えられるからである。
  4. 値がグローバルのみで定義される場合、値の割り当てはグローバルにのみ影響をあたえる
  5. グローバル変数を定義する時、同じ名前のローカル変数がすでにある場合には、ローカル変数の値がグローバル変数にコピーされる
  6. グローバル変数を定義する時、同じ名前のローカル変数がない場合には、空行列[]がグローバル名前空間に生成され、そこへのポインターがローカル名前空間に生成される
  7. グローバル変数を消去するコマンドはclearglobalである

え?そうだったの?ってところがいくつもある。

  • ローカル変数はサブ関数内にもスコープを持つ
    • ただし読み込み専用
    • 書き込むと同じ名前のローカル変数が作られる
      • その際空行列[]で初期化されるため、行列の一部を書き換えるような書き方はできない
      • 書き換えたとしても、上位レベルの値は変わらない


これを知らないと、変に悩むことがあるだろう。注意が必要だ。

  • 追記

後で気がついたが、これらのルールはFortran風のルールのようだ。Fortranは使ったことがないので気がつかなかった。MATLABも同様なのだろうか。

遺伝的アルゴリズム in Scilab

遺伝的アルゴリズム(Genetic Algorithm)を勉強中。
Scilab 5から、遺伝的アルゴリズムのライブラリが標準で付いてくるようになった。

http://wiki.scilab.org/Genetic_algorithms

ネット上に情報はほとんどないので、Scilabのヘルプ

help optim_ga

と、サンプルプログラム(\modules\genetic_algorithms\examples)を参考にする。

ヘルプにのっているサンプルプログラムには些細なバグがある。
修正したうえで、グラフを表示させてみた。
Scilab 5.0.1で確認)

    deff('y=f(x)','y = sum(x.^2)');

    PopSize     = 100;
    Proba_cross = 0.7;
    Proba_mut   = 0.1;
    NbGen       = 10;
    NbCouples   = 110;
    Log         = %T;
    nb_disp     = 10; // Nb point to display from the optimal population
    pressure    = 0.05;

    ga_params = init_param();
    // Parameters to adapt to the shape of the optimization problem
    ga_params = add_param(ga_params,'minbound',[-2; -2]);
    ga_params = add_param(ga_params,'maxbound',[2; 2]);
    ga_params = add_param(ga_params,'dimension',2);
    ga_params = add_param(ga_params,'beta',0);
    ga_params = add_param(ga_params,'delta',0.1);
    // Parameters to fine tune the Genetic algorithm. All these parameters are optional for continuous optimization
    // If you need to adapt the GA to a special problem, you 
    ga_params = add_param(ga_params,'init_func',init_ga_default);
    ga_params = add_param(ga_params,'crossover_func',crossover_ga_default);
    ga_params = add_param(ga_params,'mutation_func',mutation_ga_default);
    ga_params = add_param(ga_params,'codage_func',coding_ga_identity);
    ga_params = add_param(ga_params,'selection_func',selection_ga_elitist);
    //ga_params = add_param(ga_params,'selection_func',selection_ga_random);
    ga_params = add_param(ga_params,'nb_couples',NbCouples);
    ga_params = add_param(ga_params,'pressure',pressure);

    Min = get_param(ga_params,'minbound');
    Max = get_param(ga_params,'maxbound');
    x0  = (Max - Min) .* rand(size(Min,1),size(Min,2)) + Min;

    [pop_opt, fobj_pop_opt, pop_init, fobj_pop_init] = optim_ga(f, PopSize, NbGen, Proba_mut, Proba_cross, Log, ga_params);
  
    disp(pop_opt(1));
 
    // Plot 3D Surface and Optimized Point
    x=Min(1):0.1:Max(1);
    y=Min(2):0.1:Max(2);
    z=[];
    for k=1:length(x)
      for m=1:length(y)
        z(m,k)=f([x(k);y(m)]);
      end
    end
  
    clf
    plot3d(x,y,z);
    
    p=pop_opt(1);
    param3d(p(1),p(2),f(p));

    e=gce(); //the handle on the 3D polyline
    e.mark_mode='on';
    e.mark_size=3;
    e.mark_foreground=color('red');

実行結果

optim_ga: Initialization of the population
optim_ga: iteration 1 / 10 - min / max value found = 0.005286 / 0.842114
optim_ga: iteration 2 / 10 - min / max value found = 0.000859 / 0.189952
optim_ga: iteration 3 / 10 - min / max value found = 0.000115 / 0.043110
optim_ga: iteration 4 / 10 - min / max value found = 0.000076 / 0.014128
optim_ga: iteration 5 / 10 - min / max value found = 0.000020 / 0.003757
optim_ga: iteration 6 / 10 - min / max value found = 0.000011 / 0.001156
optim_ga: iteration 7 / 10 - min / max value found = 0.000000 / 0.000396
optim_ga: iteration 8 / 10 - min / max value found = 0.000000 / 0.000134
optim_ga: iteration 9 / 10 - min / max value found = 0.000000 / 0.000041
optim_ga: iteration 10 / 10 - min / max value found = 0.000000 / 0.000011
 
    0.0001984  
    0.0000989  

ちなみに解析解は[0 0]。

Wavelab for scilab

WaveLabをScilabで試してみた。

インストールは特に必要ない。

Wavelab for scilab
http://www.scilab.org/contrib/index_contrib.php?page=displayContribution&fileID=934
をダウンロードし、展開。
Scilabを実行し、

exec loader.sce

とすると、Wavelabが組み込まれる。

実行例

//デモ用信号生成
sig = MakeSignal('Doppler',256);

//CWT実行
nvoice=12;
oct = 2;
scale = 4;
obj1 = CWT( sig, nvoice, 'Morlet',oct,scale);


//軸のラベルを生成
[n nscale] = size(obj1);
xtix   = linspace(0,n,n);
ytix   = linspace(1+(oct-floor(log2(scale))),log2(n)-oct,nscale);
skipx = floor(length(xtix)/8);
skipy = floor(length(ytix)/nvoice);

ha = gca();
ha.axes_visible="on";

def=format();
format('v',5);
ha.x_ticks=tlist(['ticks' 'locations' 'labels'],1:skipx:length(xtix),string(xtix(1:skipx:$))); 
ha.y_ticks=tlist(['ticks' 'locations' 'labels'],1:skipy:length(ytix),string(ytix(1:skipy:$))); 

tmp=['v','e'];
format(tmp(def(1)),def(2));

//画像化
subplot(211);
ImageCWT(obj1, 'Overall', 'jetcolormap(256)')

subplot(212)
plot2d(sig);

ImageCWTがあまり良くないので、いずれ自作しようと思う。