真実の楽譜(フルスコア)

プログラム関係の忘備録になるはず

C# Fromで動画再生するには

WPFやWinRTならXAMLベースのMediaElementクラスを使うことが、
MSDNでも書かれているように鉄板だと思います。
http://msdn.microsoft.com/ja-jp/library/aa970915(v=vs.110).aspx

しかし現在自分が今行っている案件はWindows Form開発。
Formアプリケーションではどうするのって事になったので、
調べてみた。

WindowsMediaPlayerコントロールを使う

一番簡単に実装するならコレが手っ取り早い模様。
再生、停止、スクロール等のUI操作は、
全部このコントロールにおまかせできます。

コントロール追加方法
  1. VisualStudioから[ツール]→[ツールボックス アイテムの選択]をクリック。
  2. [COMコンポーネント]のタブを選択
  3. [Windows Media Player]にチェックを入れOKをクリック
  4. ツールボックスに追加された[Windows Media Player]をFormに貼り付け

f:id:s_sikisya:20140303095357p:plain
f:id:s_sikisya:20140303095857p:plain

これだけでプレイヤーが画面に追加できます。
再生時にはコントロールのURLプロパティに、
ファイルパスを指定するだけでOK。

axWindowsMediaPlayer1.URL = "moviefile.wmv";

ちょっと気になるところ
  • コマ送り再生ができない
  • WindowsMediaPlayerの外観使ってます感バリバリ
  • UI部分のカスタマイズができない
  • 一時停止中にシークしてもサムネイルが移動しない

これらの点が気に食わないので、
楽せずにやる方法で現在は実装中。
具体的にはC#でDirectShowを使ってます。
DirectShowについては今後まとめていく予定。

C#で離散ウェーブレット変換

Scilabで離散ウェーブレット変換
http://truthfullscore.hatenablog.com/entry/2014/01/17/172746

C#で実装してみた。

ドベシィウェーブレット変換プログラム

DaubechiesWavelet.cs
using System;

namespace Wavelet
{
  class DaubechiesWavelet
  {
    //Daubechies係数を定義
    public static double[][] DaubechiesCoefficients =
    { 
      new double[] {1.0/Math.Sqrt(2.0),1.0/Math.Sqrt(2.0)},
      new double[] {0.6830127/Math.Sqrt(2.0),1.1830127/Math.Sqrt(2.0),0.3169873/Math.Sqrt(2.0),-0.1830127/Math.Sqrt(2.0)},
      new double[] {0.47046721/Math.Sqrt(2.0),1.14111692/Math.Sqrt(2.0),0.650365/Math.Sqrt(2.0),-0.19093442/Math.Sqrt(2.0),-0.12083221/Math.Sqrt(2.0),0.0498175/Math.Sqrt(2.0)},
      new double[] {0.32580343/Math.Sqrt(2.0),1.01094572/Math.Sqrt(2.0),0.8922014/Math.Sqrt(2.0),-0.03957503/Math.Sqrt(2.0),
              -0.26450717/Math.Sqrt(2.0),0.0436163/Math.Sqrt(2.0),0.0465036/Math.Sqrt(2.0),-0.01498699/Math.Sqrt(2.0)},
      new double[] {0.22641898/Math.Sqrt(2.0),0.85394354/Math.Sqrt(2.0),1.02432694/Math.Sqrt(2.0),0.19576696/Math.Sqrt(2.0),
              -0.34265671/Math.Sqrt(2.0),-0.04560113/Math.Sqrt(2.0),0.10970265/Math.Sqrt(2.0),-0.0088268/Math.Sqrt(2.0),
              -0.01779187/Math.Sqrt(2.0),4.72E-03/Math.Sqrt(2.0)}
    };

    static void Main(string[] args)
    {
      int totalLength = 1024;  //データ数(2のべき乗)
      int maxLevel = 2;   //分解レベル
      int N = 1;          //次数
      int kMax = 2 * N;
      int daubechiesIndex = N - 1;

      double[] inputSignal = new double[totalLength];
      double[] outputSignal = new double[totalLength];

      //確認用に入力データをCSVファイル出力
      System.IO.StreamWriter swriter = new System.IO.StreamWriter("input.csv");
      //初期化
      for (int signalIndex = 0; signalIndex < totalLength; signalIndex++)
      {
        inputSignal[signalIndex] = 10.0 * Math.Sin(signalIndex * 2.0 * Math.PI / (totalLength / 2.0))
                      + 1.0 * Math.Sin(signalIndex * 2.0 * Math.PI / (totalLength / 200.0));
        outputSignal[signalIndex] = 0.0;
        swriter.WriteLine(inputSignal[signalIndex]);
      }
      swriter.Close();

      for (int level = 1; level <= maxLevel; level++)
      {
        int scale = 1;
        for (int i = 0; i < level; i++)
        {
          scale *= 2;
        }

        //ダウンサンプリング
        for (int index = 0; index < totalLength / scale; index++)
        {
          int setApproximationIndex = index;
          int setDetailIndex = index + totalLength / scale;

          outputSignal[setApproximationIndex] = 0.0;
          outputSignal[setDetailIndex] = 0.0;

          for (int k = 0; k < kMax; k++)
          {
            int getInputIndex = 2 * index + k;

            if (getInputIndex >= 2 * totalLength / scale)
            {
              //配列外にデータにアクセスする際に折り返しを行う
              int over = getInputIndex % (2 * totalLength / scale) + 1;
              getInputIndex = (2 * totalLength / scale) - over;
            }

            //フィルタリング
            outputSignal[setApproximationIndex] += inputSignal[getInputIndex] * DaubechiesCoefficients[daubechiesIndex][k];
            outputSignal[setDetailIndex] += inputSignal[getInputIndex] * Math.Pow(-1.0, k) * DaubechiesCoefficients[daubechiesIndex][kMax - 1 - k];
          }
        }

        //配列コピー
        Array.Copy(outputSignal, inputSignal, totalLength);

        //結果出力
        swriter = new System.IO.StreamWriter("signalLevel"+level.ToString()+".csv");
        for (int signalIndex = 0; signalIndex < totalLength / scale; signalIndex++)
        {
          swriter.WriteLine(outputSignal[signalIndex] + "," + outputSignal[signalIndex + totalLength / scale]);
        }
        swriter.Close();
      }
    }
  }
}

解説

入力信号作成

前回の記事同様に、
振幅10, 2Hzの正弦波と、
振幅1 , 100Hzの正弦波を足し合わせた信号を作成。

      System.IO.StreamWriter swriter = new System.IO.StreamWriter("input.csv");
      //初期化
      for (int signalIndex = 0; signalIndex < totalLength; signalIndex++)
      {
        inputSignal[signalIndex] = 10.0 * Math.Sin(signalIndex * 2.0 * Math.PI / (totalLength / 2.0))
                      + 1.0 * Math.Sin(signalIndex * 2.0 * Math.PI / (totalLength / 200.0));
        outputSignal[signalIndex] = 0.0;
        swriter.WriteLine(inputSignal[signalIndex]);
      }
      swriter.Close();
||
フィルタリングとダウンサンプリング

離散ウェーブレット変換は、元の信号x(n)を下の図のように、
ハイパスとローパスの線形フィルタリングを実行。
その後フィルタリング処理データを1点おきに取得して、
信号をダウンサンプリング。
f:id:s_sikisya:20140122131835p:plain
このときに表れた低周波信号をApproximation
もう一方の高周波信号をDetailと呼ぶ。

そして指定した分解レベルになるまで、
低周波信号に対して再帰的に
フィルタリングとダウンサンプリングを実行。
f:id:s_sikisya:20140122130900p:plain

最終的に得られた信号列

Approximation Level N, Detail Level Detail N, Level N-1, … , Detail Level 2, Detail Level 1

Scilabの以下の式で求めたウェーブレット係数Cに該当します。

[C,L]=wavedec(wave,2,"haar");

フィルタリング式

これで離散ウェーブレット変換は入力信号から、
ApproximationとDetailを求めるフィルタリング式さえあれば、
順次求めることができそう。

フィルタリング式は、
DaubechiesWaveletの場合それぞれ、

{ \displaystyle
g_n = \sum_{k=0}^{2N-1} a_k x(n-k)
}

{ \displaystyle
h_n = \sum_{m=0}^{2N-1} b_k x(n-k)
}

となります。

Daubechies係数

また係数には以下の関係式が成り立つ。

{ \displaystyle
b_k = {(-1)}^{m} a_{2N-1-k}
}

{ \displaystyle
\sum_{m=0}^{2N-1} a_k = \sqrt{2}
}

{ \displaystyle
\sum_{m=0}^{2N-1} a_k^2 = 1
}

このDaubechies係数を求める方法があるようですが、
一般的には既に求められているのを使う模様。
英語版Wikipediaに次数N=10の場合までの係数が用意されています。

a_k D2 (Haar) D4 D6 D8 D10
0 1 0.6830127 0.47046721 0.32580343 0.22641898
1 1 1.1830127 1.14111692 1.01094572 0.85394354
2 0.3169873 0.650365 0.8922014 1.02432694
3 -0.1830127 -0.19093442 -0.03957503 0.19576696
4 -0.12083221 -0.26450717 -0.34265671
5 0.0498175 0.0436163 -0.04560113
6 0.0465036 0.10970265
7 -0.01498699 -0.0088268
8 -0.01779187
9 0.004717428

Daubechies wavelet - Wikipedia, the free encyclopediaより一部(N=5まで)引用

注意
この表は係数の二乗和が2で正規化されているので、
全てルート2で割った値を使用すること。

結果出力

上記プログラムは分解レベル毎に
ApproximationとDetailをCSVファイルで保存しています。
ウェーブレット変換結果をExcelでプロットとした図。

レベル1
f:id:s_sikisya:20140205171527p:plain
レベル2
f:id:s_sikisya:20140205171546p:plain

以前行ったScilabで離散ウェーブレット変換
での結果同様にLevel2の段階でDetailに高周波成分が出てきています。
f:id:s_sikisya:20140117131947p:plain
サンプリングができない点の処理(プログラムでは折り返し)が、
異なるのかデータの端だけScilabと値が異なるけど今回は気にしない方向で。

参考
離散ウェーブレット変換 - Wikipedia
Daubechies wavelet - Wikipedia, the free encyclopedia
直交ウェーブレット変換について

AndroidはKitKat以降アプリからSDカードへの書き込み不可に?

2014/01/30 18:30 内容一部修正

KitKat端末では今後アプリからMicro SDカードへの書き込みができくなる模様 | juggly.cn
この記事もうちょっと詳しく調べてみた。

情報元ソース

元ソースはGoogle+Google社のTod Liebeck氏書いた内容

KitKat will make your SD Card completely useless: per the Android API specification, apps can no longer write files to your SD card. And Samsung is following it.

This only applies to dual-storage devices, i.e., devices with a user-writable internal flash storage AND a removable SD card.


From http://source.android.com/devices/tech/storage/index.html:

"The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions."


If your device has user-accessible internal flash storage, your SD Card is a "secondary external storage device".


What this means is that with KitKat, applications will no longer be able create, modify, or remove files and folders on your external SD card. As a for-instance, you can no longer use a file manager to copy files from your computer to the SD card over a network. This ability, which has existed since the beginning of Android, has been taken away.


The only stated reason for this removal of functionality is that, "Restricting writes in this way ensures the system can clean up files when applications are uninstalled." I do not pretend to understand this logic. Apps are still allowed to write in arbitrary directories on the primary storage (with the appropriate permission), but are denied the same access to external storage.


Samsung has implemented this feature with their KitKat OTA updates. Note3 users are now complaining that FX File Explorer can no longer write to their external SD cards. There are solutions to this problem for users with root access. Users without root access appear to be screwed.

I'm not quite certain how Google intends for you to place files on your SD card. Perhaps you have to use proprietary Google apps that contain permissions unavailable to the rest of the developer world. Perhaps you're supposed to put everything on the cloud and pay carrier data fees to get it there. Perhaps you're supposed to use some kind of WIRE to attach your WIRELESS device to your computer and have the computer do that work for you.


In my opinion this is a horrible misstep by Google and the Android Open Source Project. Functionality has been removed without reason, to the severe detriment of users and developers alike.


I apologize for not bringing this to everyone's attention when KitKat 4.4 was released, but it was not mentioned in the Android 4.4 changes document: http://developer.android.com/about/versions/android-4.4.html. It's only mentioned in the article on source.android.com. I was only made aware of its existence from user reports as a result of Samsung implementing this change in its KitKat OTA updates.

https://plus.google.com/+TodLiebeck/posts/gjnmuaDM8sn

要約

翻訳ミスがあるかもしれないので注意してね。

KitKatから仕様変更
  • アプリはSDカードへの書き込みが完全にできなくなる
  • (例)ファイルマネージャーアプリでファイルをSDカードに保存できなくなる
  • サムスンはGALAXY Note3のアップデートで追従した
デュアルストレージデバイスが対象
  • 対象はフラッシュストレージと取り外し可能なSDカードを持つデバイス
  • WRITE_EXTERNAL_STORAGEパーミッションでは、主要なストレージのパッケージ固有ディレクトリにしか書き込めない
  • WRITE_EXTERNAL_STORAGEパーミッションがあれば主要なストレージ内のどこにでも書き込みが可能 (2014/01/30 18:30 修正)
  • SDカードは2番目の外部ストレージになり書込みが許可されない
  • SDカードは2番目の外部ストレージになりパッケージ固有ディレクトリにしか書込みが許可されない (2014/01/30 18:30 修正)
  • root権限がないと回避できない
仕様決定理由
  • 書込みを制限させ、アプリのアンインストール時に完全にクリーンアップできるから
Tod Liebeck氏は不満
  • 今後Googleがどうしたいかはわからない
  • でも代価としてクラウドサービスとかを用意して金取るかも
  • オープンソースプロジェクトとして失策
  • 変更内容に書かれてなくてサムスンのアップデートで知ったごめん

修正について

完全に書き込みができないのではなく、
SD内のアプリケーションのパッケージ固有ディレクトリ[SD\Android\data\パッケージ名\]
なら保存できるってのが正確な仕様のようです。

The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.

External Storage Technical Information | Android Developers

Tod Liebeck氏が

KitKat will make your SD Card completely useless

KitKatではSDカードが完全に使えなくなる」
って書いていて矛盾してるのは記述ミスなんだろうか?

ILSpyを使ってC#プログラムをリバースエンジニアリング

C#の実行プログラムやDLLはそのままだと、
リバースエンジニアリングし放題ってことの確認。

シーザー暗号プログラムテスト

今回はテストとして、入力文字列をシーザー暗号で
暗号化と復号化を行うプログラムを作成しました。
その後リバースエンジニアリングで、
プログラムがどう見えるのか確認してみます。

シーザー暗号とは

シーザー暗号(シーザーあんごう、英語:Caesar cipher)は、単一換字式暗号の一種で、平文の各文字を辞書順に3文字だけシフトして暗号文をつくる暗号である。カエサル暗号とも呼ばれる。文字のシフト数は固定であるが、3に限る必要はなく、シフト数を3以外にした方式もシーザー暗号(あるいはシフト暗号)と呼ぶことがある。

参考:シーザー暗号 - Wikipedia

シーザー暗号プログラム

CaesarTest.cs
using System;

namespace Encryption
{
  static class CaesarTest
  {
    private static int rool = 3;

    private static string Encryption(string input)
    {
      string ret = "";
      foreach (char c in input)
      {
        ret += ((char)(c + rool)).ToString();
      }
      return ret;
    }

    private static string Decryption(string input)
    {
      string ret = "";
      foreach (char c in input)
      {
        ret += ((char)(c - rool)).ToString();
      }
      return ret;
    }

    public static void Main()
    {
      string input;
      string encrypted;
      string decrypted;

      //復号化
      Console.WriteLine("入力した文字を暗号化します。");
      input = Console.ReadLine();
      encrypted = Encryption(input);
      Console.WriteLine("暗号化データ:" + encrypted);

      //復号化
      Console.WriteLine("入力した文字を復号化します。");
      input = Console.ReadLine();
      decrypted = Decryption(input);
      Console.WriteLine("復号化データ:" + decrypted);

      Console.ReadLine();
    }
  }
}
実行例

入力した文字を暗号化します。
password
暗号化データ:ufxx|twi
入力した文字を復号化します。
ufxx|twi
復号化データ:password

Encryption(暗号化)で「password」が「sdvvzrug」に、
Decryption(復号化)で「sdvvzrug」が「password」として出力されました。

ILSpyでリバースエンジニアリング

ILSpyのダウンロード

http://ilspy.netから画面上部のDownload Binariesを選択し、
ILSpyをダウンロード。

2013/01/29時点 最新 Version 2.1.0.1603

ILSpyの実行

ダウンロードしたファイルを解凍し、
「ILSpy.exe」を起動。

メニューバーの[File]→[開く]から、
今回作成したプログラムの実行ファイルを選択。

左側のツリービューに追加された
「Encryption」を展開していくと…

f:id:s_sikisya:20140129201156p:plain

ソースの中身がほぼ丸見え!
このままではアルゴリズムがバレバレで暗号化の意味が無い。

三角形ボタンの作り方(C# Form)

C# Formアプリケーションで、
上下左右や、進む・戻る等を指定するときに便利な三角形ボタンの作り方。

雑なやり方(非推奨)

標準のボタンをFormに貼り付けて、
テキストに三角形の記号文字を指定。

public Form1()
{
  InitializeComponent();
  button1.Text = "▲";
}

しかしこれだと右向きや左向きの三角形の場合特殊文字を使うため、
表示されない可能性もあります。

ボタン内に三角形を描画するやり方

System.Windows.Forms.Buttonクラスを継承し、
ボタン内に三角形を描画するように拡張を行います。

Button継承クラスの作成

Buttonクラスを継承した以下のクラスを作成します。

ButtonBGTriangle.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace ButtonTriangleTest
{
  public partial class ButtonBGTriangle : System.Windows.Forms.Button
  {
    //三角形の方向指定用列挙体
    public enum TriangleDirection
    {
      Up = 1,
      Down = 2,
      Left = 4,
      Right = 8,
    }

    //三角形の方向指定プロパティ
    private TriangleDirection TRIANGLE_DIRECTION = TriangleDirection.Left;
    public TriangleDirection Direction
    {
      get { return this.TRIANGLE_DIRECTION; }
      set
      {
        this.TRIANGLE_DIRECTION = value;
        this.Invalidate();
      }
    }

    //三角形の塗りつぶし色プロパティ
    private Color TRIANGLE_COLOR = System.Drawing.SystemColors.ControlText;
    public Color TriangleColor
    {
      get { return this.TRIANGLE_COLOR; }
      set
      {
        this.TRIANGLE_COLOR = value;
        this.Invalidate();
      }
    }

    public ButtonBGTriangle()
    {
      this.Text = "";
    }

    protected override void OnTextChanged(EventArgs e)
    {
      base.OnTextChanged(e);
      //テキストを空に変更し無効化
      this.Text = "";
    }

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
      base.OnPaint(e);

      Graphics g = e.Graphics;
      g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
      PointF[] drawPoint = new PointF[3];

      //TRIANGLE_DIRECTIONに応じて三角形を描画
      switch (TRIANGLE_DIRECTION)
      {
        case TriangleDirection.Up:
          drawPoint[0] = new PointF((this.ClientSize.Width - 1.0f) / 2.0f, (this.ClientSize.Height - 1.0f) / 4.0f);
          drawPoint[1] = new PointF((this.ClientSize.Width - 1.0f) / 6.0f, (this.ClientSize.Height - 1.0f) * 3.0f / 4.0f);
          drawPoint[2] = new PointF((this.ClientSize.Width - 1.0f) * 5.0f / 6.0f, (this.ClientSize.Height - 1.0f) * 3.0f / 4.0f);
          g.FillPolygon(new SolidBrush(TRIANGLE_COLOR), drawPoint);
          break;
        case TriangleDirection.Down:
          drawPoint[0] = new PointF((this.ClientSize.Width - 1.0f) / 2.0f, (this.ClientSize.Height - 1.0f) * 3.0f / 4.0f);
          drawPoint[1] = new PointF((this.ClientSize.Width - 1.0f) / 6.0f, (this.ClientSize.Height - 1.0f) / 4.0f);
          drawPoint[2] = new PointF((this.ClientSize.Width - 1.0f) * 5.0f / 6.0f, (this.ClientSize.Height - 1.0f) / 4.0f);
          g.FillPolygon(new SolidBrush(TRIANGLE_COLOR), drawPoint);
          break;
        case TriangleDirection.Left:
          drawPoint[0] = new PointF((this.ClientSize.Width - 1.0f) * 3.0f / 4.0f, (this.ClientSize.Height - 1.0f) / 6.0f);
          drawPoint[1] = new PointF((this.ClientSize.Width - 1.0f) * 3.0f / 4.0f, (this.ClientSize.Height - 1.0f) * 5.0f / 6.0f);
          drawPoint[2] = new PointF((this.ClientSize.Width - 1.0f) / 4.0f, (this.ClientSize.Height - 1.0f) / 2.0f);
          g.FillPolygon(new SolidBrush(TRIANGLE_COLOR), drawPoint);
          break;
        case TriangleDirection.Right:
          drawPoint[0] = new PointF((this.ClientSize.Width - 1.0f) / 4.0f, (this.ClientSize.Height - 1.0f) / 6.0f);
          drawPoint[1] = new PointF((this.ClientSize.Width - 1.0f) / 4.0f, (this.ClientSize.Height - 1.0f) * 5.0f / 6.0f);
          drawPoint[2] = new PointF((this.ClientSize.Width - 1.0f) * 3.0f / 4.0f, (this.ClientSize.Height - 1.0f) / 2.0f);
          g.FillPolygon(new SolidBrush(TRIANGLE_COLOR), drawPoint);
          break;
      }
    }
  }
}

これを作成すると、
こんな感じ↓のボタンコンポーネントが作れます。

f:id:s_sikisya:20140129114952p:plain

プロパティ

三角形の方向と塗りつぶし色はプロパティで設定します。

Direction:三角形の向き(Up,Down,Left,Right)
TriangleColor:三角形のカラー

Scilabで離散ウェーブレット変換

最近ウェーブレット変換を勉強していますが、
雰囲気が掴みきれていないので実際にやってみることにした。
前回書いたライブラリ実装は理解や実装に時間がかかりそうなので、
別の方法としてScilabのWavelet Toolboxを使ったら結構楽にできました。
今回使用したOSはWindows 7 64BitですがMacUnixでも動く模様。

Scilabとは

Scilabは、 INRIA (フランス国立 コンピュータ科学・制御研究所)と ENPC で 開発された高機能な科学技術ソフトウエアです。 2003年にScilab の開発は Scilab コンソーシアムに移管され、 現在は更にDigiteoに統合されて、 その1部門として Scilab コンソーシアムの活動を行っています。 2008年以降、Scilabは、GPL互換の FLOSS ライセンスに基づく オープンソースソフトウエアとして配布が行われています。

引用元"SCILAB 日本語ページ"

環境構築

Scilabのインストール

"http://www.scilab.org"から、
インストーラ(2014/01/16 時点 Ver5.4.1)をダウンロード。

ダウンロードしたインストーラをインストール。

ScilabWaveletToolboxのインストール

Scilab起動後
「アプリケーション」→「モジュール管理」をクリック。

新たに表示されたウインドウから
「Signal Processing」→「ScilabWaveletToolbox」を選択し、
「インストール」ボタンをクリック。

インストール後Scilabを再起動すれば、環境構築完了。

データ処理

データの読込

振幅10, 2Hzの正弦波と、
振幅1 , 100Hzの正弦波を足し合わせた信号を作成。

Fs=1024;
t=soundsec(1,Fs);
wave=10*(sin(2*%pi*t*2))+(sin(2*%pi*t*100));
離散ウェーブレット変換の実行
[C,L]=wavedec(wave,2,"haar");

・戻り値
 C:ウェーブレット係数列
 L:分割レベル毎のウェーブレット係数のデータ数
・引数
 第1引数:離散ウェーブレット変換をしたい信号。
 第2引数:レベル(分解数)
 第3引数:マザーウェーブレット
  "haar": ハールウェーブレット
  "db1":ドベシ―ウェーブレット(N=1)
  "db2":ドベシ―ウェーブレット(N=2)

haar( "haar"), daubechies ("db1" to "db20"), coiflets ("coif1" to "coif5"), symlets ("sym2" to "sym20"), legendre ("leg1" to "leg9"), bathlets("bath4.0" to "bath4.15" and "bath6.0" to "bath6.15"), dmey ("dmey"), beyklin ("beylkin"), vaidyanathan ("vaidyanathan"), biorthogonal B-spline wavelets ("bior1.1" to "bior6.8"), "rbior1.1" to "rbior6.8"

引用元:help wavedec

結果出力

パラメータの取得

ウェーブレット変換を行うと、
信号はApproximation(低周波成分)と、Detail(高周波成分)に分かれるので、
ウェーブレット係数列Cからそれぞれのパラメータを取得する。

・Approximation
変換時に指定したレベルのApproximationを取得。

Ap2 = appcoef(C,L,"haar",2);

 第1引数:ウェーブレット係数列
 第2引数:分割レベル毎のウェーブレット係数のデータ数
 第3引数:マザーウェーブレット
 第4引数:レベル(分解数)
・Detail
分割数が2以上のときは、
レベル毎にDetailを取得。

De1 = detcoef(C,L,1);
De2 = detcoef(C,L,2);

 第1引数:ウェーブレット係数列
 第2引数:分割レベル毎のウェーブレット係数のデータ数
 第3引数:レベル(分解数)

パラメータのプロット

上から順に
 元信号
 Approximation(低周波成分 level2)
 Detail(高周波成分 level1)
 Detail(高周波成分 level2)
を並べてグラフ描画

subplot(411)
plot(wave)
plot(Ap2)
subplot(411)
plot(wave)
subplot(412)
plot(Ap2)
subplot(413)
plot(De1)
subplot(414)
plot(De2)

元信号が離散ウェーブレット変換により分解され、
高周波(200Hz)と低周波(2Hz)に信号が分かれているはず。
f:id:s_sikisya:20140117131947p:plain

参考
MATLAB-Wavelet Toolbox-
http://www.mathworks.com/tagteam/58032_TT031_Wavelet_Tlbx_Manual.pdf

オープンソースのウェーブレット変換ライブラリ

C言語系でウェーブレット変換を行うライブラリを調査。
GPLライセンスのライブラリなので、
組み込んだ際の配布時にはご注意を。

Geophysical Wavelet Library

http://users.math.uni-potsdam.de/~gwl/

blitzwave C++ Wavelet Library

http://oschulz.github.io/blitzwave/

Signal Processing Library in C++

https://code.google.com/p/tspl/

GNU Scientific Library

http://www.gnu.org/software/gsl/manual/html_node/Wavelet-Transforms.html

GPLに接触したくないなら、
1次元連続ウェーブレット変換限定になりますが、
以下を参考にするとよさげ。

C/C++言語でガボールウェーブレット変換により時間周波数解析を行うサンプルプログラム
http://hp.vector.co.jp/authors/VA046927/gabor_wavelet/gabor_wavelet.html
FFTを使った連続ウェーブレット変換の高速化
http://r9y9.github.io/blog/2013/10/20/continuous-wavelet-tranform/