#!/usr/local/bin/wish -f # # Convolution Training Software # # coded by Shigeki Sagayama, JAIST, 23 Sep 1998 # # 今後の追加内容案: 信号値のエディット (text widget)? # set Date "24 Oct 1998" puts stdout \ "< Convolution Training Software (S. Sagayama, JAIST, $Date) >" #------------------------------------------------------------------------------ # help #------------------------------------------------------------------------------ proc helpIntro {} { helpDisp {Help: Usage - Convolve の概要 北陸先端科学技術大学院大学 嵯峨山 茂樹 これは、北陸先端科学技術大学院大学の基幹科目講義 I212 情報解析学特論の受講者を 対象に、畳み込みの概念を復習するための自習用ソフトウェアとして作成したものです。 畳み込みの概念を感覚的に把握するためのもので、与えられた信号波形と線形系のイン パルス応答に対する畳み込み出力を表示します。ただし、これは離散点に関する計算に よりによっているので、細かい点では定義通りの積分とは若干の差があることは了解し ておいて下さい。 このプログラムは Tcl/Tk のスクリプトとして書いてあります。機種やOSに大きく依 存せず、普及している無償のソフトのみを用いて、画面表示に動きのある自習プログラ ムを作るには Tcl/Tk が適当であると考えたからです。しかし Tcl/Tk は数値計算や信 号処理などへの応用を想定していないので、実行速度が遅いのは仕方ありません。 作者は、教材作りを目的に Tcl/Tk を勉強し始めてから二週間ほどの時にこのプログ ラムを書いたので (後に若干の修正を行なっていますが)、プログラムの書き方が未 熟な箇所は随所に見られることと思います。しかし、作者に無断で改善・改造して、 再配布することは避けて下さい。再配布に関して詳しくは Help: Copyright をクリッ クして見て下さい。 以上。}} #------------------------------------------------------------------------------ proc helpUsage {} { helpDisp {Help: Usage - Convolve の使用法 使い方は簡単です。 (1) 画面の説明 ============== 最上段の画面は線形系のインパルス応答 h(t) です。中段の画面は入力信 号波形 x(t) です。下段の画面は、畳み込み、すなわち線形系の応答で、 y(t) = h(t) * x(t) です。時間軸は、左端が0に相当します。 下の方に、スペクトル表示のスケーリングと時間のスケーリングを変化さ せるためのスケール窓があります。 最下段には各種のボタンスイッチ類が配置されています。 (2) 線形系のインパルス応答入力、および信号入力 ============================================== 任意の線形系のインパルス応答入力、および信号入力を設定して、その畳 み込みを観察できます。インパルス応答と信号波形の入力の仕方は次のよ うに4通りあります。 1: マウスによりサンプル値を設定 時間領域画面の緑の小さい正方形(128個ある)を、マウスボタン1を押 しながらひきずって(drag する)上下方向に動かして行ないます。入力 中のサンプルは色が赤くなり、その値は中央の x(t)=... に表示されま す。 2: ファイルから読み込み ("load data" をクリック) 時間軸の順に一行ごとにサンプル値が ASCII コードで書かれた128行の ファイルから入力するものです。"load data" ボタンをクリックすると ファイル名を尋ねてくるので、まずファイル名窓でマウスボタン1をク リックしてからキーボードからファイル名を投入し、リターンキーを押 します。一行ずつ処理が進んで行くのが見られます。ファイル名投入を キャンセルするにはマウスボタン3をクリックします。 3: 信号関数を定義 ("def func" をクリック) ユーザ関数の式を与えて、それを信号として入力するものです。"def func" ボタンをクリックすると関数式を尋ねてくるので、まずマウスボ タン1をクリックしてから、キーボードから関数式を投入し、リターン キーを押します。一行ずつ処理が進んで行くのが見られます。ファイル 名投入をキャンセルするにはマウスボタン3をクリックします。数式の 与え方は help の別項目を見て下さい。要点は時刻を $t として与える ことです。(例: 100*exp(-$t) ) 4: クリアする ("clear" をクリック) 一挙に全零入力(最初の状態)に戻したい場合は、"clear" ボタンをクリッ クします。 (3) 信号表示 ============ 上のような方法で入力できる信号波形の表示について、以下のようなこと が可能です。 1: 時間スケールの調整 ("time scale" スケールを動かす) 信号波形に縦に引かれている時間軸の目盛間隔を変化させることができ ます。周波数軸の目盛も自動的に変化します。たとえば時間目盛を mS 単位と考えれば、周波数目盛の単位は kHz となる。時間スケールを調 整することで、信号波形形状はそのままで時間長さを変えてそのフーリ エ変換を考えます。 2: 入力用の小さい緑の正方形を消す ("hide pts" をクリック) 関数形をよく観察したり、印刷するなどの目的で、入力用の小さい緑 の正方形が邪魔な場合は、"hide pts" をクリックをします。もう一度 同じボタン("show pts" となっているはず)をクリックすると、表示が 復活します。もちろん、表示消去中は、マウスからの信号入力はでき ませんが、他の3種の入力方法は有効です。 3: 滑らかな曲線表示 ("smooth" ボタンをクリック) "smooth" ボタンをクリックすると、信号波形もスペクトル形状も滑ら かな曲線 (Bezier 曲線) で表示されます。表示の滑らかさが必要な時 に有用ですが、サンプル値が正確に表現されないことに注意する必要 があります。もう一度同じボタン("polyln" となっているはず)をクリッ クすると、もとの折れ線による表示モードに戻ります。 4: ファイルへ退避 ("save data" をクリック) 時間軸の順に一行ごとにサンプル値が ASCII コードで書かれた128行の ファイル形式でデータを退避します。"save data" ボタンをクリックす るとファイル名を尋ねてくるので、まずファイル名窓でマウスボタン1 をクリックしてからキーボードからファイル名を投入し、リターンキー を押します。一行ずつ処理が進んで行くのが見られます。ファイル名投 入をキャンセルするにはマウスボタン3をクリックします。 5: eps ファイル作成 ("save eps" ボタンをクリック) 信号の形の画面の eps (encapsulated PostScript) ファイルを作成す るものです。印刷に、あるいは TeX 文書への埋め込みなどの用途が考 えられます。"sig eps" ボタンをクリックすると eps ファイル名を尋 ねてくるので、まずマウスボタン1をクリックしてから、キーボードか らファイル名を投入し、リターンキーを押します。ファイル名投入をキャ ンセルするにはマウスボタン3をクリックします。 (3) 畳み込み出力表示 ==================== 畳み込み出力表示は、信号の入力に伴って逐次表示が変化します。 この表示に関して以下のことが可能です。 1: 畳み込み値スケールの調整 ("convolution scaling factor" スケール を動かす) "convolution scaling factor" スケールを動かすと、スペクトル値を スケーリング値で割って表示します。見やすい値に調整して下さい。 2: 周波数スケールの調整 ("time scale" スケールを動かす) "time scale" スケールを動かすと、すべての画面の時間軸の目盛間隔 が変化します。 3: 自動スケーリング on/off ("man scale"/"autoscale") "man scale" ボタンをクリックすると、自動スケーリングのモードを 抜けて、自分でスケールを設定するモードになり、表示は"autoscale" となります。再びクリックすると、畳み込みが最大値が画面の最大許 容幅になるように自動スケーリングした畳み込み波形が表示されます。 4: 滑らかな曲線表示 "smooth" ボタンをクリックすると、すべての曲線が滑らかな曲線 (Bezier 曲線) で表示されます。表示の滑らかさが必要な時 に有用ですが、サンプル値が正確に表現されないことに注意する必要 があります。 5: eps ファイル作成 ("save eps" ボタンをクリック) 畳み込み画面の eps (encapsulated PostScript) ファイルを作成す るものです。印刷に、あるいは TeX 文書への埋め込みなどの用途が考 えられます。"save eps" ボタンをクリックすると eps ファイル名を尋 ねてくるので、まずマウスボタン1をクリックしてから、キーボードか らファイル名を投入し、リターンキーを押します。ファイル名投入をキャ ンセルするにはマウスボタン3をクリックします。 以上。}} #------------------------------------------------------------------------------ proc helpCopyright {} { helpDisp {Help: Copyright ◆ このプログラムの著作権は、作者・嵯峨山茂樹 (sagayama@jaist.ac.jp) に属します。 このプログラムは、北陸先端科学技術大学院大学の専門科目講義 I212 情報解 析学特論の受講者を対象に、フーリエ変換を理解するための自習用ソフトウェ アとして嵯峨山が作成したものです。 作者は、教材作りを目的に、わずか二週間ほど前に Tcl/Tk を勉強し始めたば かりなので、プログラムの書き方が下手な箇所は随所に見られることと思いま す。また、フーリエ変換のような信号処理分野を Tcl/Tk のスクリプトで行な うという発想がそもそも特異なので、改善の余地は多くあることと思います。 しかし一つのプログラムの中で完結したかったので、C プログラムと組み合わ せるなどは行ないませんでした。皆様の暖かい改善の御意見を歓迎します。 このような不完全な代物ではありますが、しかし、作者に無断で改善・改造し て、他の人に配布することは避けて下さい。そこで、以下に使用条件を述べま す。 ◆ このソフトウェアを改変することなくそのまま全部を再配布することは許 可します。大いに使って頂いて結構です。ただし、改善・改変して再配布しな いで下さい。この著作権に関する宣言の部分も含め、一字一句変えずにこのま まならば再配布は自由です。但し、漢字コードの変換などは構いません。 ◆ 作者の許可なく改変(一部分のみの使用を含む)したものは、再配布するこ とを禁じます。 ◆ バグやプログラミングに関する御意見は、作者に御連絡下さい。バグ情報、 改善意見、改良の努力、利用経験、応用情報などは歓迎致します。 以上。}} #------------------------------------------------------------------------------ proc helpUserfunc {} { helpDisp {help: ユーザ定義関数 ◆ "user func" と表示されたボタンをクリックすると、ユーザ定義関数を尋 ねてきます。時刻は $t で表されます。そこで、Tcl の expr コマンドの文法 に従って、式を与えて下さい。 ◆ 例えば、 一次系: 10*exp(-$t/10) です。係数の 10 は、画面の中での表示の都合です。 ◆ Tcl の数式は、C の文法に近く、かなり自由に表現できます。一部を紹介 すると、 算術演算 -a, a*b, a/b, a%b, a+b, a-b 数学関数 abs(x), acos(x), asin(x), atan(x), atan2(x,y), ceil(x), cos(x), soch(x), double(i), exp(x), floor(x), fmod(x,y), hypot(x,y), int(x), log(x), log10(x), pow(x,y), round(x), sin(x), sinh(x), sqrt(x), tan(x), tanh(x) 論理式 !a, ab, a<=b, a>=b, a==b, a!=b, a&&b, a||b, 条件分岐 a?b:c (a は論理式、b と c は場合ごとの数式) ビット演算 ~a, a<>b, a&b, a~b, a|b, 以上。}} #------------------------------------------------------------------------------ proc helpSaveLoad {} { helpDisp {help: ファイル入出力 ファイルとのやりとりは、ごく簡単な以下の種類があります。help の操作説 明の部分にも説明してありますが、まとめると、 (1) ファイルへの信号データ出力 "save signal" ボタンをクリックすると、保存出力用のファイル名を尋ね て来ます。ファイル名投入の窓の中でマウスボタン 1 をクリックすると、キー ボードからの入力を受け付けるようになります。ファイル名を入れてリターン キーを押すと、指定されたファイルに、現在表示されている信号のサンプル値 系列が保存されます。保存の形式は、ASCII 数字のみで、一行ごとに1データ が書き込まれます。 ファイル名を尋ねてきたところでマウスボタン3をクリックすれば、キャン セルできます。 (2) ファイルからの信号データ入力 "load signal" ボタンをクリックすると、保存出力用のファイル名を尋ね て来ます。ファイル名投入の窓の中でマウスボタン 1 をクリックすると、キー ボードからの入力を受け付けるようになります。ファイル名を入れてリターン キーを押すと、指定されたファイルから信号のサンプル値系列を読み込み、フー リエ変換を計算して表示します。ファイルの形式は、ASCII 数字のみで一行ご とに1データが書き込まれている形式です。"save signal" で得られた退避デー タ形式がそのまま使われます。 ファイル名を尋ねてきたところでマウスボタン3をクリックすれば、キャン セルできます。 (3) 信号画面の eps データのファイルへの出力 (4) スペクトル画面の eps データのファイルへの出力 以上。}} #------------------------------------------------------------------------------ proc helpLearn {} { helpDisp {help: How to Learn - これを用いた学習法のヒント このソフトウェアを用いて畳み込みの学習をしましょう。たとえば、つぎのよ うな畳み込みの性質を実際に試してみるとよいでしょう。 (1) 遅れ 入力波形を時刻 t だけずらすと、出力も t だけずれる。 (2) 矩形関数 矩形関数どうしの畳み込みは三角形の関数になる。 (3) 正弦波 同じ周波数の正弦波どうしの畳み込みはやはり正弦波。 (4) 等間隔パルス列 等間隔パルス列どうしの畳み込みはやはり等間隔パルス列になる。 (5) 三角パルスどうしの畳み込みはどうなる? (6) ガウス波形どうしの畳み込みはどうなる? (7) 異なる周波数の正弦波どうしの畳み込みはどうなる? (8) 任意の与えられた波形に対して、応答が最も鋭くなるようにするには? 以上。}} #------------------------------------------------------------------------------ proc helpEnglish {} { helpDisp {Help: General information and usage in English Shigeki Sagayama, Professor, JAIST This is a visualization software for students taking Course I212 ("information analysis") at JAIST. Change the system impulse response by dragging the small blue boxes or the signal by dragging the small yellow boxes with mouse button 1. The resulted convolution output will be displayed immediately. The purpose is to provide a tool for intuitively understanding convolution. Given a system impluse response and a signal waveform, this tool displays the convolution output automatically. It is very easy to use. (1) Screens =========== The uppermost screen is the linear system impulse response. The second screen is the input signal. The third screen represents the convolution output. Both time and frequency axes has their origins at the centers of screens. Namely, the left half represents negative time or frequency, while the right half represents positive time or frequency. Time and frequency scaling can be changed by manupilating the "time scale" at the bottom of the screen. Buttons provided at the bottom are used for changing display modes, file I/O, and defining the user function. (2) System impulse response and signal input ============================================ The convolution can be observed for an arbitrary linear system impulse response and an input signal waveform. There are four ways of specifiying them. 1: Specify the signal sample sequence using the mouse Move as appropriate the small green squares (128 squares are shown) by dragging with mouse button 1. The sample point turns red and the sample value is displayd as "x(t)=..." in the box at the center. 2: Read a data file (click "load data") 128 ASCII code values of samples are read sequentially line by line from a data file. Click "load data" button and the program will ask for a file name entry. Activate the entry window by clicking mouse button 1. Enter the file name and terminate it by the key. Line-by-line input will be seen as Fourier transform calculation going on. In the case of cancelation of file name entry, click mouse button 3 instead. 3: Define the user function (click "def func") Provide a mathematical formula to define the user signal function of time $t. Click the "def func" button and the program will ask for a function. Activate the entry window by clicking mouse button 1. Enter the function and terminate it by the key. Signal samples will be generated one by one along with the Fourier transform calculation. In the case of cancelation of the function entry, click mouse button 3 instead. Note that the time is represented by "$t" witch must be included in the user function definition. For example, 100*exp(-$t)*cos(5*$t) Refer to the Tcl math syntax for more information. (Japanese version for the outline is available by choosing help : user function. 4: Clear the data (click "clear") Clear the signal into zero values by clicking the "clear" button. The response will be also cleared, consequently. (3) System and signal display ============================= System and signal display has several options as follows: 1: Adjusting the time scale (move "time scale") The time scale can be changed by dragging the nob of "time scale". The consequent frequency scale also changes automatically. For example, if the time is in msec, the frequency scale is in kHz. Preserving the waveform, changing the time scale gives the frequency scaled Fourier transform. 2: Hide the small squares (click "hide pts") Click "hide pts" to remove the small squares overlapping on the signal waveform if only the waveform is preffered for observing the shape or printing the waveform. Clicking the same button (appearing with the sign of "show pts") will restore the small squares. While the small squares are unseen, the manual input of signal is inhibited, but other three modes are still available. 3: Smooth curve display (click "smooth") Clicking the "smooth" button changes smooth the displayed waveform and the spectral shapes. Note that these Bezier curve may not be accurate in representing the sample sequences. Clicking the same button (appearing as "polyln") returns to the original polyline mode. 4: Save data in a file (click "save data") The data can be saved in a file by clicking the "save data" button. The program will ask for a file name to save the eps code. Activate the file name entry window by clicking mouse button 1 in the window. Enter the file name and terminate it with . Mouse button 3 cancels the file name entry on the way. This data can be loaded via "load data" 5: Creating an eps file (click "save eps") An eps (encapsulated PostScript) file can be generated from the signal waveform. Applications included printing the waveform and embeddeed figures in TeX documents. Click the "sig eps" button and the program will ask for a file name to save the eps code. Activate the file name entry window by clicking mouse button 1 in the window. Enter the file name and terminate it with . Mouse button 3 cancels the file name entry on the way. (4) Convolution display ======================= Convolution display changes simultaneously along with the system and signal input. The following options are available for the convolution display. 1: Scaling the convolution (move "convolution scaling factor") Moving the scale indicated "convolution scaling factor" changes the spectrum scaling. Adjust the scale so as to see the spectrum shape appropriately. 2: Creating an eps file (click "save eps") An eps (encapsulated PostScript) file for the displayed spectrum shapes can be obtained. Applications include printing and embbeding a figure in TeX documents. Click the "save eps" and the program will ask for a fiel name to save the eps code. Activate the window by clicking the button 1 and enter a file name terminated by . To cancel the entry before typing a , click mouse botton 3. (5) Command arguments ===================== This program accepts several optional arguments listed below: +length LEN specifies the number of time points [default 128] +width WID specifies the width of screens [default 800] +height HGT specifies the height of each screen [default 200] example: Convolve +length 64 +width 700 End.}} #------------------------------------------------------------------------------ ### Create a new message window to show the specified contents ### proc helpDisp { contents } { set w .basic catch {destroy $w} toplevel $w wm title $w "Fourier Transform" wm iconname $w "Fourier Transform" button $w.ok -text OK -command "destroy $w" -fg black -bg yellow text $w.t -relief raised -bd 2 -yscrollcommand "$w.s set" -setgrid true \ -fg black -bg white scrollbar $w.s -relief flat -command "$w.t yview" pack $w.ok -side bottom -fill x pack $w.s -side right -fill y pack $w.t -expand yes -fill both $w.t insert 0.0 $contents $w.t mark set insert 0.0 bind $w "focus $w.t" } #------------------------------------------------------------------------------ # initial settings #------------------------------------------------------------------------------ # constants (W=800, H=200, N=128) - can be changed by command arguments set W 800 set H 200 set N 128 ### check command arguments ### for { set i 0 } { $i < $argc } { incr i } { switch [lindex $argv $i] { "+length" { incr i; set N [lindex $argv $i] } "+width" { incr i; set W [lindex $argv $i] } "+height" { incr i; set H [lindex $argv $i] } default { puts stdout "options: +length L, +width W, +height H" exit } } } set DivT0 60 set Resol [expr floor($W/$N)] set X0 [expr ($W-($N-1)*$Resol)/2+10] set Y0 [expr $H/2] set Xorig $X0 set Yorig $Y0 # computation variables # initial values - Re, Im, Power Spec set Sig(0) 100 set Sys(0) 100 set Conv(0) 10000 for { set i 1 } { $i < $N } { incr i } { set Sig($i) 0 set Sys($i) 0 set Conv($i) 0 } set AutoScale 1 set Buff { } set PointList { } ### internal buffer variables # xy-coord list set Scale 100 set XYSig { } set XYConv { } set XYSys { } set ThisSigY "none" set ThisSysY "none" set Points(0) 0 set Points2(0) 0 set CurvSig 0 set CurvSys 0 set CurvCv 0 set ShapeSig { } set ThisSig "none" set ThisSys "none" set Seen 0 set Smooth 0 set ShowAbs 0 set ShowPnts 1 set GridShown 1 set DivT $DivT0 #------------------------------------------------------------------------------ # display setup #------------------------------------------------------------------------------ ### window title ### wm title . "Convolve (Sagayama)" ### title ### message .m -justify left -relief raised -bd 2 -width $W \ -fg #ffffff -bg #002d08 -text \ "Learn Convolution (sagayama@jaist.ac.jp, $Date)" #### canvas #### canvas .e -width [expr $W+10] -height $H -bg #dfffff canvas .c -width [expr $W+10] -height $H -bg #ffffbc canvas .d -width [expr $W+10] -height $H -bg #fff0ff #------------------------------------------------------------------------------ ### buttons: start, stop, quit, time, numb ### frame .f menubutton .f.help -text "help" -menu .f.help.m -relief raised \ -fg #ffffff -bg #ff1c35 menu .f.help.m -fg #000000 -bg #ff1c35 .f.help.m add command -label "English" -command helpEnglish .f.help.m add command -label "Introduction" -command helpIntro .f.help.m add command -label "How to use it" -command helpUsage .f.help.m add command -label "Copyright" -command helpCopyright .f.help.m add command -label "User function" -command helpUserfunc .f.help.m add command -label "Save/Load" -command helpSaveLoad .f.help.m add command -label "How to learn" -command helpLearn menubutton .f.smooth -text "style" -menu .f.smooth.m -relief raised \ -fg #ffffff -bg #b25f00 menu .f.smooth.m -fg #000000 -bg #ff1c35 .f.smooth.m add command -label "smooth curve" -command { swSmooth 1 } .f.smooth.m add command -label "polygon" -command { swSmooth 0 } button .f.pnt -text "hide pts" -fg #ffffff -bg #17714b -command { if { $ShowPnts == 1 } { .f.pnt configure -text "show pts" } else { .f.pnt configure -text "hide pts" } toggleShowPnts } frame .fe label .fe.ms -relief raised -width 40 \ -fg #b9faff -bg #000087 -text \ "Linear System h(t) : Impulse Response" button .fe.loadsys -text "load data" \ -command { loadSys } -fg #ffffff -bg #6c5f44 button .fe.sysfunc -text "def func" \ -fg #ffffff -bg #588a64 -command { sysFunc } button .fe.savesys -text "save data" \ -command { saveSys } -fg #ffffff -bg #a30a26 button .fe.epssys -text "save eps" \ -command { epsSys } -fg #ffffff -bg #ee0300 frame .fc label .fc.mt -relief raised -width 40 \ -fg #ffffdf -bg #7d4e00 -text \ "Input x(t) : Input Signal" button .fc.loadsig -text "load data" \ -command { loadSig } -fg #ffffff -bg #6c5f44 button .fc.sigfunc -text "def func" \ -fg #ffffff -bg #588a64 -command { sigFunc } button .fc.savesig -text "save data" \ -command { saveSig } -fg #ffffff -bg #a30a26 button .fc.epssig -text "save eps" \ -command { epsSig } -fg #ffffff -bg #ee0300 frame .fd label .fd.mf -relief raised -width 58 -fg #fff5ff -bg #b20000 -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" menubutton .fd.autoscale -text "scaling" \ -menu .fd.autoscale.m -relief raised -fg #ffffff -bg #622662 menu .fd.autoscale.m -fg #000000 -bg #ff1c35 .fd.autoscale.m add command -label "adaptive scaling" \ -command { swAutoScale 1 } .fd.autoscale.m add command -label "manual scaling" \ -command { swAutoScale 0 } button .fd.saveconv -text "save data" \ -command { saveConv } -fg #ffffff -bg #a30a26 button .fd.epsconv -text "save eps" \ -command { epsConv } -fg #ffffff -bg #ee0300 button .f.clear -text "clear" -fg #ffffff -bg #5f1280 \ -command { global N Sig Sys Conv Scale XYConv Resol X0 Y0 CurvCv set Sig(0) 100; set Sys(0) 100; set Conv(0) 10000; for { set i 1 } { $i < $N } { incr i } { set Sig($i) 0; set Sys($i) 0; set Conv($i) 0; } set Scale 100 eval .c delete [.c find withtag line] eval .c delete [.c find withtag point] eval .e delete [.e find withtag line] eval .e delete [.e find withtag point] eval .d delete [.d find withtag line] ### draw signal waveform and plot control points ### set XYSig [array2Coord Sig $N $Resol 1.0 $X0 $Y0] set CurvSig [eval .c create line $XYSig -tags line -fill black] drawPoints .c Sig $N $Resol 1.0 $X0 $Y0 ### draw system impulse response and plot control points ### set XYSys [array2Coord Sys $N $Resol 1.0 $X0 $Y0] set CurvSys [eval .e create line $XYSys -tags line -fill black] drawPoints2 .e Sys $N $Resol 1.0 $X0 $Y0 ### draw the convolution curve ### set Smooth 0 set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] set CurvCv [eval .d create line $XYConv -tags line -fill red -width 2] .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" } button .f.quit -text "quit" -command {exit} -fg #ffffff -bg #002332 #------------------------------------------------------------------------------ ### scales ### frame .s # grid delta scale .s.delta -label "time scale" -from 10 -to 400 \ -length [expr ($W+13)/2] \ -orient horizontal -command getDelta -bg seagreen -fg white pack .s.delta -side left -expand yes proc getDelta value { global Delta Xorig W H set DivT [expr [.s.delta get]] eval .c delete [.c find withtag grid] eval .d delete [.d find withtag grid] eval .e delete [.e find withtag grid] # drawGrid $DivT for { set x 0 } { $x < $W } { incr x $DivT } { set xx [expr $Xorig+$x] set id [.c create line $xx 0 $xx $H -fill grey50 -tags grid] .c lower $id set id [.d create line $xx 0 $xx $H -fill grey50 -tags grid] .d lower $id set id [.e create line $xx 0 $xx $H -fill grey50 -tags grid] .e lower $id } set GridShown 1 } .s.delta set $DivT # convolution display scaling factor (multiplied 1/Scale) scale .s.scale -label "convolution scaling factor * 10" \ -from 1 -to 100 -length [expr ($W+13)/2] \ -orient horizontal -command getScale -bg maroon -fg white pack .s.scale -side left -expand yes proc getScale value { global N Conv Scale XYConv Resol X0 Y0 CurvCv set Scale [expr [.s.scale get]*10] .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv } .s.scale set [expr $Scale/10] #------------------------------------------------------------------------------ # packing and binding #------------------------------------------------------------------------------ pack .fe.ms .fe.loadsys .fe.sysfunc .fe.savesys .fe.epssys \ -side left -fill both -expand yes pack .fc.mt .fc.loadsig .fc.sigfunc .fc.savesig .fc.epssig \ -side left -fill both -expand yes pack .fd.mf .fd.autoscale .fd.saveconv .fd.epsconv \ -side left -fill both -expand yes pack .f.clear .f.pnt .f.smooth .f.help .f.quit \ -side left -fill both -expand yes pack .m .f .fe .e .fc .c .fd .d .s -side top -fill both -expand yes # dangerous - for quick debugging only bind . {destroy .} bind . {destroy .} focus . #------------------------------------------------------------------------------ # point a point bind .c { global ThisSig ThisSigY N ShowN set tags [lindex [.c itemconfigure current -tags] 4] if { [lsearch $tags point] >= 0 && [lsearch $tags current] >=0 } { .c itemconfigure current -fill red set curr [.c find withtag current] if { $ThisSig != $curr } { .c itemconfigure $ThisSig -fill yellow } set ThisSig $curr set ThisSigY [expr [lindex [.c coords $ThisSig] 1]+2] } else { .c itemconfigure $ThisSig -fill yellow set ThisSig "none" # .f.value config -text "" .fc.mt config -text "Input x(t) : Input Signal" } } bind .e { global ThisSys ThisSysY N ShowN set tags [lindex [.e itemconfigure current -tags] 4] if { [lsearch $tags point] >= 0 && [lsearch $tags current] >=0 } { .e itemconfigure current -fill red set curr [.e find withtag current] if { $ThisSys != $curr } { .e itemconfigure $ThisSys -fill blue } set ThisSys $curr set ThisSysY [expr [lindex [.e coords $ThisSys] 1]+2] } else { .e itemconfigure $ThisSys -fill blue set ThisSys "none" # .f.value config -text "" .fe.ms config -text "Linear System h(t) : Impulse Response" } } # drag a point along the y-axis bind .c { global ThisSig N ShowN if { $ThisSig != "none" } { set yy [expr [lindex [.c coords $ThisSig] 1]+2] .c move $ThisSig 0 [expr %y-$yy] # .f.value config -text "x(t)=[expr $Yorig-%y]" .fc.mt config \ -text "Input x(t) : Input Signal \[[expr $Yorig-%y]\]" } } # drag a point along the y-axis bind .e { global ThisSys N ShowN if { $ThisSys != "none" } { set yy [expr [lindex [.e coords $ThisSys] 1]+2] .e move $ThisSys 0 [expr %y-$yy] # .f.value config -text "x(t)=[expr $Yorig-%y]" .fe.ms config \ -text "Linear System h(t) : Impulse Response \[[expr $Yorig-%y]\]" } } # release the button - convolution calculation bind .c { global ThisSig ThisSigY Sig Conv Scale N Resol \ X0 Y0 CurvSig XYSig CurvCv XYConv if { $ThisSig != "none" } { set yy [expr [lindex [.c coords $ThisSig] 1]+2] set i [lindex [lindex [.c itemconfigure $ThisSig -tags] 4] 1] set dsig [expr $ThisSigY-$yy] set Sig($i) [expr $Sig($i)+$dsig] # .f.value config -text "x(t)=$Sig($i)" .fc.mt config -text "Input x(t) : Input Signal \[$Sig($i)\]" set j [expr 2*$i+3] set XYSig [lreplace $XYSig $j $j [expr $Yorig-$Sig($i)]] eval .c coord $CurvSig $XYSig ### convolution incremental modification ### incrConv $dsig $i Sys Conv $N if { $AutoScale != 0 } { set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" } } # release the button - convolution calculation bind .e { global ThisSys ThisSysY Sys Conv Scale N Resol \ X0 Y0 CurvSig XYSys CurvCv XYConv if { $ThisSys != "none" } { set yy [expr [lindex [.e coords $ThisSys] 1]+2] set i [lindex [lindex [.e itemconfigure $ThisSys -tags] 4] 1] set dsig [expr $ThisSysY-$yy] set Sys($i) [expr $Sys($i)+$dsig] .fe.ms config -text "Linear System h(t) : Impulse Response \[$Sys($i)\]" set j [expr 2*$i+3] set XYSys [lreplace $XYSys $j $j [expr $Yorig-$Sys($i)]] eval .e coord $CurvSig $XYSys ### convolution incremental modification ### incrConv $dsig $i Sig Conv $N if { $AutoScale != 0 } { set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" } } bind .c { } bind .c { } #------------------------------------------------------------------------------ # Convolution #------------------------------------------------------------------------------ ### incremental convolution modification : when $sig($i) changed by $dsig proc incrConv { dsig i sys res n } { upvar $sys s upvar $res r for { set t $i } { $t < $n } { incr t } { set k [expr $t-$i] set r($t) [expr $r($t)+$dsig*$s($k)] } } proc peakmax { array n } { upvar $array a set min -1 set max 1 for { set t 0 } { $t < $n } { incr t } { if { $a($t) > $max } { set max $a($t) } if { $a($t) < $min } { set min $a($t) } } set rev [expr -$min] if { $max < $rev } { return $rev } return $max } #------------------------------------------------------------------------------ # drawing #------------------------------------------------------------------------------ ### create array points - returns the point id list ### proc drawPoints { wdw array n dx dy x y } { global Points upvar $array a for { set i 0 } { $i < $n } { incr i } { set xx [expr $i*$dx+$x] set yy [expr $y-$a($i)*$dy] set Points($i) \ [$wdw create rectangle \ [expr $xx-2] [expr $yy-2] [expr $xx+2] [expr $yy+2] \ -fill yellow -tags [list point $i]] } } ### create array points - returns the point id list ### proc drawPoints2 { wdw array n dx dy x y } { global Points2 upvar $array a for { set i 0 } { $i < $n } { incr i } { set xx [expr $i*$dx+$x] set yy [expr $y-$a($i)*$dy] set Points2($i) \ [$wdw create rectangle \ [expr $xx-2] [expr $yy-2] [expr $xx+2] [expr $yy+2] \ -fill blue -tags [list point $i]] } } ### convert an array into a coordinate list ### ## array2Coord -> List proc array2Coord { array n dx dy x y } { upvar $array a set xy { } ### add time t=-1 to show the first pulse ### lappend xy [expr $x-$dx] lappend xy [expr $y] for { set i 0 } { $i < $n } { incr i } { lappend xy [expr $i*$dx+$x] lappend xy [expr $y-$a($i)*$dy] } return $xy } proc swAutoScale { ind } { global AutoScale N CurvCv XYConv Conv Scale H X0 Y0 Resol if { $ind == 0 } { set AutoScale 0 } else { set AutoScale 1 set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" update idletasks } } proc swSmooth { ind } { global Smooth CurvCv CurvSig CurvSys if { $ind == 0 } { set Smooth 0 .c itemconfig $CurvSig -smooth off .d itemconfig $CurvCv -smooth off .e itemconfig $CurvSys -smooth off } else { set Smooth 1 .c itemconfig $CurvSig -smooth on .d itemconfig $CurvCv -smooth on .e itemconfig $CurvSys -smooth on } } proc toggleShowPnts { } { global Sig Sys N Resol X0 Y0 ShowPnts if { $ShowPnts == 1 } { set ShowPnts 0 eval .c delete [.c find withtag point] eval .e delete [.e find withtag point] } else { set ShowPnts 1 drawPoints .c Sig $N $Resol 1.0 $X0 $Y0 drawPoints2 .e Sys $N $Resol 1.0 $X0 $Y0 } } #------------------------------------------------------------------------------ # file I/O (save, load) #------------------------------------------------------------------------------ proc epsSig {} { catch {destroy .tmp} toplevel .tmp wm title .tmp "Save eps" wm iconname .tmp "Convolve: Save eps" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "eps file output - enter a filename for the input signal:" entry .tmp.entry -relief sunken -width 30 -textvariable fname message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Or click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { .c postscript -colormode color -file $fname destroy .tmp grab set . } } proc epsSys {} { catch {destroy .tmp} toplevel .tmp wm title .tmp "Save eps" wm iconname .tmp "Convolve: Save eps" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "eps file output - enter a filename for the system impulse response:" entry .tmp.entry -relief sunken -width 30 -textvariable fname message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Or click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { .e postscript -colormode color -file $fname destroy .tmp grab set . } } proc epsConv {} { catch {destroy .tmp} toplevel .tmp wm title .tmp "Save eps" wm iconname .tmp "Convolve: Save eps" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "eps file output - enter a filename for the convolution data:" entry .tmp.entry -relief sunken -width 30 -textvariable fname message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Or click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { .d postscript -colormode color -file $fname destroy .tmp grab set . } } proc saveSig {} { global Sig Conv Scale N Resol \ X0 Y0 CurvSig XYSig XYSys \ CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Save Signal Data" wm iconname .tmp "Convolve: Save Sig" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "save data - enter a filename for the input signal data:" entry .tmp.entry -relief sunken -width 30 -textvariable fname message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Or click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { set file [open $fname w] for { set i 0 } { $i < $N } { incr i } { puts $file $Sig($i) } close $file destroy .tmp grab set . } } proc saveSys {} { global Sig Conv Scale N Resol \ X0 Y0 CurvSig XYSig XYSys \ CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Save System Data" wm iconname .tmp "Convolve: Save Sys" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "save data - enter a filename for the system impulse response:" entry .tmp.entry -relief sunken -width 30 -textvariable fname message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Or click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { set file [open $fname w] for { set i 0 } { $i < $N } { incr i } { puts $file $Sys($i) } close $file destroy .tmp grab set . } } proc saveConv {} { global Sig Conv Scale N Resol \ X0 Y0 CurvSig XYSig XYSys \ CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Save Convolution Data" wm iconname .tmp "Convolve: Save Conv" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "save data - enter a filename for the convolution data:" entry .tmp.entry -relief sunken -width 30 -textvariable fname message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Or click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { set file [open $fname w] for { set i 0 } { $i < $N } { incr i } { puts $file $Conv($i) } close $file destroy .tmp grab set . } } proc loadSig {} { global Sig Conv Scale N Resol \ X0 Y0 CurvSig XYSig XYSys \ CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Load Data" wm iconname .tmp "Load Data" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -aspect 300 \ -text "load data - double click on the file name of the signal data. \ Or click the \"dismiss\" button to quit." frame .tmp.frame -borderwidth 10 button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top pack .tmp.ok -side bottom -fill x pack .tmp.frame -side top -expand yes -fill y scrollbar .tmp.frame.scroll -relief sunken -command ".tmp.frame.list yview" listbox .tmp.frame.list -yscroll ".tmp.frame.scroll set" -relief sunken \ -geometry 20x10 -setgrid 1 pack .tmp.frame.list .tmp.frame.scroll -side left -fill y set ls [ open |ls r] set i 0 while { [gets $ls newval] >= 0} { .tmp.frame.list insert 0 $newval } bind .tmp.frame.list { set fname [selection get] destroy .tmp set file [open $fname r] set i 0 while { [gets $file newval] >= 0} { .fc.mt config -text "Input x(t) : Input Signal \[$newval\]" .c itemconfig $Points($i) -fill red set dsig [expr $newval-$Sig($i)] if { $dsig != 0.0 } { .c move $Points($i) 0 [expr -($dsig)] set Sig($i) $newval set j [expr 2*$i+3] set XYSig [lreplace $XYSig $j $j [expr $Yorig-$Sig($i)]] eval .c coord $CurvSig $XYSig ### convolution incremental modification ### incrConv $dsig $i Sys Conv $N if { $AutoScale != 0 } { set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" update idletasks } incr i } close $file grab set . for { set i 0 } { $i < $N } { incr i } { .c itemconfig $Points($i) -fill yellow } .fc.mt config -text "Input x(t) : Input Signal" } } proc loadSys {} { global Sig Conv Scale N Resol X0 Y0 CurvSig XYSig XYSys CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Load Data" wm iconname .tmp "Load Data" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -aspect 300 \ -text "load data - double click on the file name of the signal data. \ Or click the \"dismiss\" button to quit." frame .tmp.frame -borderwidth 10 button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top pack .tmp.ok -side bottom -fill x pack .tmp.frame -side top -expand yes -fill y scrollbar .tmp.frame.scroll -relief sunken -command ".tmp.frame.list yview" listbox .tmp.frame.list -yscroll ".tmp.frame.scroll set" -relief sunken \ -geometry 20x10 -setgrid 1 pack .tmp.frame.list .tmp.frame.scroll -side left -fill y set ls [ open |ls r] set i 0 while { [gets $ls newval] >= 0} { .tmp.frame.list insert 0 $newval } bind .tmp.frame.list { set fname [selection get] destroy .tmp set file [open $fname r] set i 0 while { [gets $file newval] >= 0} { .fe.ms config -text "Linear System h(t)=$newval : Impulse Response" .e itemconfig $Points2($i) -fill red set dsys [expr $newval-$Sys($i)] if { $dsys != 0.0 } { .e move $Points2($i) 0 [expr -($dsys)] set Sys($i) $newval set j [expr 2*$i+3] set XYSys [lreplace $XYSys $j $j [expr $Yorig-$Sys($i)]] eval .e coord $CurvSys $XYSys ### convolution incremental modification ### incrConv $dsys $i Sig Conv $N if { $AutoScale != 0 } { set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" update idletasks } incr i } close $file grab set . for { set i 0 } { $i < $N } { incr i } { .e itemconfig $Points2($i) -fill blue } .fe.ms config -text "Linear System h(t) : Impulse Response" } } #------------------------------------------------------------------------------ # user-defined function #------------------------------------------------------------------------------ proc sigFunc {} { global Sig Conv Scale N Resol X0 Y0 CurvSig XYSig XYSys CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Signal Function" wm iconname .tmp "Convolve: Sig Func" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "signal function definition - define the signal function \ (use \$t to represent time):" entry .tmp.entry -relief sunken -width 30 -textvariable userfunc message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { destroy .tmp set funcshow [.c create text 300 10 -text "$userfunc" -anchor nw] for { set i 0 } { $i < $N } { incr i } { set t [expr $i*$Resol/$DivT] eval set newval [expr $userfunc] .c itemconfig $Points($i) -fill red .fc.mt config -text "Input x(t) : Input Signal \[$newval\]" set dsig [expr $newval-$Sig($i)] if { $dsig != 0.0 } { .c move $Points($i) 0 [expr -($dsig)] set Sig($i) $newval set j [expr 2*$i+3] set XYSig [lreplace $XYSig $j $j [expr $Yorig-$Sig($i)]] eval .c coord $CurvSig $XYSig ### convolution incremental modification ### incrConv $dsig $i Sys Conv $N if { $AutoScale != 0 } { set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" update idletasks } } .c delete $funcshow grab set . for { set i 0 } { $i < $N } { incr i } { .c itemconfig $Points($i) -fill yellow } .fc.mt config -text "Input x(t) : Input Signal" } } proc sysFunc {} { global Sig Conv Scale N Resol X0 Y0 CurvSig XYSig XYSys CurvCv XYConv catch {destroy .tmp} toplevel .tmp wm title .tmp "Signal Function" wm iconname .tmp "Convolve: Sig Func" wm minsize .tmp 1 1 message .tmp.msg -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "system function definition - define the system impulse response \ (use \$t to represent time):" entry .tmp.entry -relief sunken -width 30 -textvariable userfunc message .tmp.msg2 -font -Adobe-times-medium-r-normal--*-180* -width 320 \ -text "Click the \"dismiss\" button to quit." button .tmp.ok -text dismiss -command "destroy .tmp" pack .tmp.msg -side top frame .tmp.frame -borderwidth 10 pack .tmp.frame -side top -expand yes -fill y pack .tmp.entry -side top -expand yes -fill y pack .tmp.msg2 -side top pack .tmp.ok -side bottom -fill x bind .tmp.entry { destroy .tmp set funcshow [.e create text 300 10 -text "$userfunc" -anchor nw] for { set i 0 } { $i < $N } { incr i } { set t [expr $i*$Resol/$DivT] eval set newval [expr $userfunc] .e itemconfig $Points2($i) -fill red .fe.ms config -text "Linear System h(t) : Impluse Response \[$newval\]" set dsys [expr $newval-$Sys($i)] if { $dsys != 0.0 } { .e move $Points2($i) 0 [expr -($dsys)] set Sys($i) $newval set j [expr 2*$i+3] set XYSys [lreplace $XYSys $j $j [expr $Yorig-$Sys($i)]] eval .e coord $CurvSys $XYSys ### convolution incremental modification ### incrConv $dsys $i Sig Conv $N if { $AutoScale != 0 } { set Scale [expr [peakmax Conv $N]*2/$H] if { $Scale == 0 } { set Scale 1 } } set XYConv [array2Coord Conv $N $Resol [expr 1.0/$Scale] $X0 $Y0] eval .d coord $CurvCv $XYConv .fd.mf config -text \ "Output y(t) : Convolution y(t) = h(t) * x(t) \[scale $Scale\]" update idletasks } } .e delete $funcshow grab set . for { set i 0 } { $i < $N } { incr i } { .e itemconfig $Points2($i) -fill blue } .fe.ms config -text "Linear System h(t) : Impluse Response" } } #------------------------------------------------------------------------------ # main program #------------------------------------------------------------------------------ ### draw axes ### .c create line 0 $Yorig [expr $W+10] $Yorig -tags axis -fill grey20 .c create line $Xorig 0 $Xorig $H -tags axis -fill grey20 .e create line 0 $Yorig [expr $W+10] $Yorig -tags axis -fill grey20 .e create line $Xorig 0 $Xorig $H -tags axis -fill grey20 .d create line 0 $Yorig [expr $W+10] $Yorig -tags axis -fill grey20 .d create line $Xorig 0 $Xorig $H -tags axis -fill grey20 ### draw signal waveform and plot control points ### set XYSig [array2Coord Sig $N $Resol 1.0 $X0 $Y0] set CurvSig [eval .c create line $XYSig -tags line -fill black -width 2] set XYSys [array2Coord Sys $N $Resol 1.0 $X0 $Y0] set CurvSys [eval .e create line $XYSys -tags line -fill black -width 2] drawPoints .c Sig $N $Resol 1.0 $X0 $Y0 drawPoints2 .e Sig $N $Resol 1.0 $X0 $Y0 set XYConv [array2Coord Conv $N $Resol 1.0 $X0 $Y0] set CurvCv [eval .d create line $XYConv -tags line -fill red -width 2] #------------------------------------------------------------------------------ # end of the "wish" (tcl/tk) script: Convolve #------------------------------------------------------------------------------