PyLAFではコンポーネント単位でプログラムを作成していきます。 どのようにコンポーネントを作成し、それぞれを連携させてゆけばよいのか、 振幅変調の学習プログラムを作成しながら説明してゆきます。

コンポーネントの実行方法

正弦波を生成するコンポーネントのコードを示します。 まずは、このコードを実行してみましょう。

  • 添付ファイルMODAM.pyをダウンロードして保存してください。下のソースコードの右肩のリンクをクリックするとダウンロードできます。
  • 保存したファイルを右クリックすると開くコンテキストメニュー中の<Edit with IDLE>を選択します。
  • PythonのインタプリタウィンドウとMODAM.pyの内容を表示したエディタウィンドウが開きます。エディタウィンドウ上で左クリックしてこれをアクティブにします。
  • <Run>→<Run Module>でMODAM.pyを実行すると図のようなGUIが立ち上がります。

FrequencyやPhase Offsetを変更してみてください。 エントリを書き換えて<Enter>を押すとグラフが更新されます。

MODAM.png

  1. from PyLAF import *
  2. class FGSIN(EasyComponent):
  3. PLOTTER = Oscilloscope
  4. def __init__(self,master=None):
  5. EasyComponent.__init__(self,master)
  6. self.mag = EasyPort(Variable(1.),'Magnitude [mV]').bind(self.trigger)
  7. self.freq = EasyPort(Variable(0.01),'Frequency [MHz]').bind(self.trigger)
  8. self.phase = EasyPort(Variable(0.),'Phase Offset [deg]').bind(self.trigger)
  9. self.bias = EasyPort(Variable(0.),'Bias Voltage [mV]').bind(self.trigger)
  10. self.dt = EasyPort(Variable(1.),'Time Step [us]').bind(self.trigger)
  11. self.tend = EasyPort(Variable(500.),'End [us]').bind(self.trigger)
  12. def trigger(self):
  13. t = arange(0.,self.tend.get(),self.dt.get())
  14. w = sin(2 * pi * self.freq.get() * t + self.phase.get() / 180. * pi)
  15. self.sig_out.set(self.mag.get() * w + self.bias.get())
  16. def test(master=None):
  17. o = App(master,FGSIN); o.pack()
  18. o.component.trigger()
  19. if __name__ == '__main__':
  20. test(Tkinter.Tk())
  21. Tkinter.mainloop()

コンポーネントの作成方法

新しくコンポーネントを作成してみましょう。

  • IDLEを立ち上げます。
  • <File>→<New Window>を選びます。
  • ダウンロードしたMODAM.pyと同じ内容をタイプします。

Pythonでは字下げもプログラム上の意味がありますので、 スペースの数などもまったく同じになるようにタイプします。

  • <File>→<Save>で任意の場所にスクリプトファイルを保存します。ここでは名前は"MODAM2.py"とします。拡張子は.pyです。
  • <Run>→<Run Module>でMODAM2.pyを実行してみます。MODAM.pyと同じ結果になりましたか。

コンポーネントの連携

FGSINの出力ポートにスペアナを接続してみます。 MODAM3.png test()関数を以下のように変更します。PyLAFにビルトインされているSpectrumコンポーネントはsig_inポートのデータが 更新されると、sig_inのデータをフーリエ変換して表示します。例題ではFGSINのsig_outとSpectrumのsig_inとがリンクされています。 FGSINで表示されている時間波形のフーリエ変換が表示されていることがわかります。

def test(master=None):
    o = App(master,FGSIN); o.pack()
   ↓
def test(master=None):
    o = App(master,FGSIN); o.pack()
    v = App(Tkinter.Toplevel(master),Spectrum); v.pack()
    o.component.sig_out.link(v.component.sig_in)

  1. from PyLAF import *
  2. class FGSIN(EasyComponent):
  3. PLOTTER = Oscilloscope
  4. def __init__(self,master=None):
  5. EasyComponent.__init__(self,master)
  6. self.mag = EasyPort(Variable(1.),'Magnitude [mV]').bind(self.trigger)
  7. self.freq = EasyPort(Variable(0.01),'Frequency [MHz]').bind(self.trigger)
  8. self.phase = EasyPort(Variable(0.),'Phase Offset [deg]').bind(self.trigger)
  9. self.bias = EasyPort(Variable(0.),'Bias Voltage [mV]').bind(self.trigger)
  10. self.dt = EasyPort(Variable(1.),'Time Step [us]').bind(self.trigger)
  11. self.tend = EasyPort(Variable(500.),'End [us]').bind(self.trigger)
  12. def trigger(self):
  13. t = arange(0.,self.tend.get(),self.dt.get())
  14. w = sin(2 * pi * self.freq.get() * t + self.phase.get() / 180. * pi)
  15. self.sig_out.set(self.mag.get() * w + self.bias.get())
  16. def test(master=None):
  17. o = App(master,FGSIN); o.pack()
  18. v = App(Tkinter.Toplevel(master),Spectrum); v.pack()
  19. o.component.sig_out.link(v.component.sig_in)
  20. if __name__ == '__main__':
  21. test(Tkinter.Tk())
  22. Tkinter.mainloop()

コンポーネントの変更

プロッタの変更

FGSINのプロッタを変更してみましょう。

  • 4行目:PLOTTER = Oscillator → PLOTTER=Spectrum に変更します。

実行すると、スペクトルが表示されますが、周波数範囲が広くてよくわかりません。 スペクトルの表示部分で右クリックするとポップアップメニューが開きます。 Consoleを選ぶと横軸設定が開くので、XMIN,XMAXを0,0.2程度にしてみましょう。

Plugin Error: attach file not found: MODAM4.png

Plugin Error: attach file not found: MODAM4.py

ミキサーコンポーネントの作成

コンポーネントの説明

1プロット1エントリーパネルという基本的なプログラムはEasyComponentを継承して作ります。 クラス変数PLOTTERでプロットの種別を設定します。いまのところ、XYPlot、Oscilloscope、Spectrum、Constellationを設定できます。 PLOTTERをSpectrumに変更して実行してみてください。ビューがスペクトル表示に変更されます。

GUIのEntryから操作したいパラメータを以下の書式で与えます。

self.変数名 = EasyPort(Variable(初期値),ラベル).bind(self.trigger)

例えば、以下のコードは「初期値が浮動小数点型1.のmagという変数を定義せよ。GUIに表示する際のラベルは'Magnitude mV'とする。 エントリが更新された際にはtrigger()メソッドを起動する。」という意味です。 定義された順番にGUIに配置されてゆきます。

self.mag   = EasyPort(Variable(1.),'Magnitude [mV]').bind(self.trigger)

コンポーネントを実行する際には、AppまたはEmbedというイクイップメントクラスでラップします。 イクイップメントクラスはコンポーネントが保持するGUIやメニュー、コンポーネントをGUIツールキットの 適切な場所に配置して実行可能な状態にします。

o = App(master,FGSIN); o.pack()

ロジックは慣習的にtrigger()メソッドに記述します。TkitnerのDoubleVarなどと同様に、GUIのエントリーパネルに保持されている内容を取得するには、 get()メソッドを、設定するにはset()メソッドを使用します。 コンポーネントの出力はsig_outメンバに対してset()するようにしてください。

t = arange(0.,self.tend.get(),self.dt.get()) # 0からtendまで増分dtで増加する数列をtに代入する
w = sin(2 * pi * self.freq.get() * t + self.phase.get() / 180. * pi) # 周波数freq(MHz)、位相phase(度)の正弦波をwに代入する
self.sig_out.set(self.mag.get() * w + self.bias.get()) # 振幅をmag倍、バイアスをbias分だけ加算してsig_outに代入する
sig_outはエントリーパネルに表示するのではなく、 他のコンポーネントとの連携をとるためのインスタンス変数です。 EasyComponent中で以下のように定義されています。
self.sig_out  = Port(Variable(array([])))
EasyComponentではsig_outポートはPLOTTERコンポーネントのsig_inポートにリンクしています。 sig_outにsetしたデータがPLOTTERコンポーネントに表示されます。
frm = Frame(master)
if not self.PLOTTER == None:
    v = self.__class__.PLOTTER(frm,pltcnf); v.plot(); v.show(); v.pack()
    setattr(frm,'plotter',v)
    self.sig_out.insertlink(0,v.sig_in)