LoginSignup
8
4

More than 5 years have passed since last update.

信号処理やるならD言語

Last updated at Posted at 2016-12-18

はじめに

大学で無線通信の信号処理に関する研究をしていまして,
今年1年間でD言語で無線機のシミュレータを開発しました.

今回は,シミュレータを開発するにあたって,すごく便利だったD言語の機能だったり,知見を共有できたらなと思います.

Range

信号処理は,

  • ソース: 信号の源(正弦波,ランダムなビット列,白色雑音)
  • シンク: 信号の出力先(信号のスペクトルの描画)
  • 処理ブロック: 信号処理ブロック(アンプ,ミキサ,フィルタ)

というような基本的な3つの要素で構成できます.

ソースや処理ブロックはInputRangeで簡単に記述でき,シンクはOutputRangeで表現できます.

Rangeのわかりやすい説明やその他の応用については,同じく今年のD言語 Advent Calendarでumariderさんとlempijiさんの記事があります.

Rangeを利用することによって,標準ライブラリで提供されている機能をそのまま利用することができます.

たとえば,信号を定数倍するだけのアンプであればstd.algorithm.mapを使えばいいですし,
信号をあるサンプル数だけ進めるのであればstd.range.popFrontNstd.range.dropを使えば簡単です.

終わりのない無限の長さを持つ信号も表現でき,std.range.takeでその長さを制限することもできます.

また,UFCSによって信号処理の流れが非常にわかりやすくなります.

immutable real freq = 1e6,          // sin波の周波数1MHz
               ts = 1.0/(20e6),     // サンプリング周波数 20MHz
               amp = 2.0;           // 増幅率

// sin波の生成, InfiniteRange
auto sinsig = sequence!"n * a[0]"(2 * PI * freq * ts)
             .map!(a => sin(a) * amp);

FFT

無線通信の信号処理では,いたるところにFFTが出現します.
たとえば,WiFiなどの無線通信で使われているOFDMという変調方式は,FFTを用いて信号を生成しています.
D言語では標準ライブラリのstd.numericというモジュールにFFTが用意されています!!
もちろん,Rangeインターフェイスに対応しています.

Traits(Concepts)

正式名称は良くわかりませんが,D言語ではよく次のようにisXXXXというテンプレートを定義して,型の分類を行います.

たとえば,RangeにもisInputRangeだったりisForwardRangeなどがあります.

無線通信の信号処理では,変復調器のように,インターフェイスが決まっているものがあります.
例の変復調器では,modulatedemodulateというメンバ関数だったりを要求するisModulatorを定義しています.

enum bool isModulator(T) = is(typeof((T mod){
    // 変調器への入力の型,ubyte(ビット列), Complex!floatなど
    alias IType = T.InputElementType;

    // 変調器からの出力の型,Complex!floatなど
    alias OType = T.OutputElementType;

    IType[] inputs;
    OType[] outputs;
    outputs = mod.modulate(inputs);     // IType -> OType
    inputs = mod.demodulate(outputs);   // OType -> IType
}));

std.parallelism

複数のパラメータでのシミュレーションを並列して実行したくなったときに,D言語であれば標準ライブラリのstd.parallelismモジュールを使えば簡単に並列化できます.
たとえば,送信電力を10mW(10dBm)から100mW(20dBm)まで掃引してシミュレーションしたい時,並列化は次のように行えます.

import std.parallelism : parallel;

// 内部が並列実行される
foreach(power; iota(10, 22, 2).parallel)
{
    runSimulator(power);
}

単体テスト

最初の方に述べた通り,無線通信信号処理では,ブロック単位でプログラムが独立します.

そのため,必然的にモジュール間や関数間で高い直交性を持ったプログラムとなり,単体テストによる各関数のテストが容易です.

D言語では,次のようにいろいろな場所に単体テストを書くことができます.

もし,パッケージマネージャのDUBを使っていれば,dub testだけで単体テストを走らせることができます.

// 増幅器
auto amplified(R, F)(R input, F amp)
{
    return input.map!(a => a * amp);
}

unittest
{
    assert(iota(3).amplified(2).equal([0, 2, 4]));
}

C言語のライブラリが簡単に使える

無線通信の信号処理といえど,よく行列やベクトルの計算(固有値問題とか)が出現します.
そういうときに,BLASやLAPACKを触れるとすごく便利です.
D言語では,C言語のライブラリを簡単に使うことができるので,BLASやLAPACKも使えます.

また,私の在籍する大学には,小規模ながらクラスタ計算機が設置されており,MPIを用いて超並列計算もできます.
各ノードはIntelのXeonを搭載しているので,D言語も環境を構築すれば動かすことができます.
そこで,実際にOpenMPIを用いたライブラリも作成しました -> TUT-HPCLIB4D

まとめ

信号処理するならD言語しかない!!

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4