の終わりにクラスの定義を使用する方法 JSLクラスのインスタンスをコピーするのが難しいという興味深い点があることをほのめかしました。Xがインスタンスを参照する場合、Y = XはYとXの両方を作成します紹介するへ同じインスタンス。インスタンスをユーザー定義関数に渡す場合も同じことが起こります。関数の値はないインスタンスのコピー。それ参照するへ同じインスタンス。したがって、関数内のインスタンスを変更すると、呼び出し元のインスタンスも変更されます。マトリックスを関数に渡して関数で変更したことがある場合、呼び出し元の写す JSLは値によってユーザー関数に引数を渡します。
JMPはコピーを作成して引数を渡しますが、...
マトリックスがコピーされることに注意してください。関数内のマトリックスに対する変更は、元のマトリックスではなく、コピーに対して行われます。大きな黒い参照ドットもコピーされますが、参照するオブジェクトはコピーされないことに注意してください。彼らがこの絵を見たことがないので、これは最初のJAVAプログラマーに多くの頭痛を引き起こします。関数内では、変数に対して2つの非常に異なることを行うことができます a 。
- a:set(42);のようなメソッドを呼び出すことができます。
- a = 42などの値を割り当てることができます。
(1)の場合、アーガイル 3から42までのオブジェクトの値。これはおそらくあなたがやろうとしていることです。(2)の場合、隣の大きな黒いドットを上書きします a 42で。あなたはおそらくそうするつもりはありませんでした。
次のコードは、他のオブジェクトへの参照を保持するオブジェクトを使用しています。すべてのオブジェクトにnext()メソッドがあるため、オブジェクトを興味深い方法で構成できます。next()メソッドは、一連の値の次の値を生成します。一部のオブジェクトは定数を表し、常に同じ次の値を生成します。addオブジェクトのような他のオブジェクトには、2つのオブジェクト(+演算子の左側と右側)があります。Add:next()は、left:next()およびright:next()を呼び出し、2つの回答を追加します。
完全なJSLが添付されています。ここでは、インターリーブされた画像を使用しています。最も単純なクラスから始めましょう。
// number/matrix wrapper class
Define Class(
"vwrap",
m_v = .; // holds the number or matrix
_init_ = Method( {v},
If( Type( v ) == "Class",
Throw( "vwrap is for number or matrix, not class " || Char( v << getname ) )
);
m_v = v;
);
set = Method( {v},
If( Type( v ) == "Class",
Throw( "vwrap is for number or matrix, not class " || Char( v << getname ) )
);
m_v = v;
);
next = Method( {},
m_v; // return
);
);Vwrapはクラスの名前であり、数値または行列のいずれかの値をラップします。これには、適切でない値を拒否するセッターと、シーケンス内の次の値を返すnext()という名前のゲッターがあります。NewObject(Vwrap(42))を書くのは少し醜いので、Vwrapsを作成するヘルパー関数も作成しましょう。
// helper function v(...) converts a scalar or matrix to a vwrap, or returns an instance unchanged
v = Function( {x},
If( Type( x ) == "Class",
If( !(x << Contains( "next" )),
Throw( "v expects number, matrix, or one of the classes it supports, not class " || (x << getname) )
);
x; // x supports a next function, it is probably OK
, // else
If( !Is Number( x ) & !Is Matrix( x ),
Throw( "v expects number or matrix, not " || Type( x ) )
);
New Object( vwrap( x ) ); // wrap the number or matrix
)
);v(...)は、多くの場合、クラスインスタンスを使用して、場合によってはスカラーまたは行列を使用して呼び出され、取得したときにクラスインスタンスを変更せずに返す必要があります。混同される可能性のある他のクラスがある場合に備えて、クラス内に同時にnext()があることを確認することもできます。
次に、大部分がボイラープレート関数でグラフを作成します。
// global function gr(...) makes a graph
gr = Function( {Xvar, Yvar, title, n},
{Xs, Ys, dt}, // locals
Yvar = v( Yvar );
Xvar = v( Xvar );
Ys = J( n, 1, Yvar:next() );
Xs = J( n, 1, Xvar:next() );
dt = As Table( Ys || Xs, <<INVISIBLE></INVISIBLE>XおよびYパラメーターのv()への呼び出しを確認できます。これらは、ラップされる単純な数値、またはnext()メソッドで他のクラスにすることができます。次に、J()関数がN値の行列を作成し、非表示のテーブルが作成されて、グラフビルダーが実行され、隠されたテーブルが不要になったときに少し非表示にすることができます。試してみよう。
gr( 13, 42, "Value 13,42", 1 );
x = 13、y = 42の単一の点
ちょっと待ってください、それは良くなります... 0、1、2、3を返すカウンタークラスを作ってみましょう... next()への連続した呼び出し。
// counter class
Define Class(
"counter",
m_rate = .; // non zero increment
m_pos = empty(); // internal position
_init_ = Method( {rate},
m_rate = v( rate );
);
next = Method( {},
rate = m_rate:next();
// see peek() comment in "sin" class
If( Is Empty( m_pos ),
result = 0 * rate; // get scalar or matrix dimension on first call
m_pos = rate; // for next time
, // else
result = m_pos; // from last tim
m_pos += rate; // for next time
);
result; // return
);
);_init_メソッドは、カウンターがインクリメントする速度を決定するレートを取ります。レートは、定数(通常は1)にすることも、別のクラスインスタンスにすることもできます。これは、カウンターを作成するヘルパー関数と最初のグラフです。
// global function to make a counter
ctr = Function( {rate = 1},
New Object( counter( rate ) )
);
gr( ctr(), ctr() , "count up A (equal steps)", 5 );X軸とY軸の2つの個別のカウンターインスタンスがgr(...)に渡されたことに注意してください。
ゼロから始まる5つのステップのための、並行して実行される2つのカウンター。
さて、別の何かのために:カウンターのレートを別のカウンターにしましょう。
// this variation begins to show the power of composition
gr( ctr(), ctr( ctr() ), "count up B (first step is 0)", 5 );
レートカウンターの最初の結果がゼロであるため、最初のステップはゼロです。
このグラフのY軸は、2つのカウンターの関数構成を使用しています。sin()クラスを追加しましょう。
// sin() wrapper class
Define Class(
"sin",
m_rate = .; // 0<STEP><PI. m_amp=".;"></PI.></STEP>
正弦は、定数または他のクラスインスタンスによって決定される周波数と振幅で無限の正弦波を生成します。また、内部の位置を保持します。コメントから、もっと考える必要があるかもしれませんが、このデモでは機能します。これが単一サイクルの波形です。
gr( ctr(), New Object( Sin( 2 * Pi() / 100, 3 ) ), "sin()", 101 );
正弦波の単一サイクル
別のカウンターの増分があるカウンターと同様に、正弦波は可変周波数を持つことができます。
gr( ctr(), New Object( Sin( New Object( Sin( .0002, 1 ) ), 3 ) ), "variable frequency", 1000 );
別の正弦波の最初のビットを使用して周波数を上げる
また、2つの異なる周波数の正弦波を互いにプロットできます。
gr( New Object( Sin( 4 * Pi() / 99, 3 ) ), New Object( Sin( 6 * Pi() / 99, 3 ) ), "2X3 sin()", 100 );
単純な整数比は素晴らしいパターンを作る
別のクラスとヘルパー関数。クラスは1つ以上の他のクラスを一緒に追加し、オフセットヘルパーは定数...または別の関数を追加します...おそらくテストされません。
// add class
Define Class(
"add",
m_a = {};
//m_b = .;
_init_ = Method( {a, b = Empty()},
If( Is Empty( b ),
For( i = 1, i <= N Items( a ), i += 1,
Insert Into( m_a, v( a[i] ) )
),
m_a[1] = v( a );
m_a[2] = v( b );
)
);
next = Method( {},
result = m_a[1]:next();
For( i = 2, i <= N Items( m_a ), i += 1,
result = result + m_a[i]:next()
);
result;
);
);
// helper function uses add to offset another value by off
offset = function({off,x},
newobject(add(off,x))
);オフセットヘルパーを使用すると、初期のゼロステップがあった初期のグラフの1つを再加工して、初期ステップを1にすることができます。
// compared to a previous example, this one increments earlier
gr( ctr(), ctr( offset(1,ctr( 1 )) ), "count up C (first step is 1)", 5 );
すべてのステップが以前よりも1つ大きくなりました。
// building a square wave by summing odd harmonics
n = 100;
basefreq = 2 * Pi() / n;
freq1 = New Object( Sin( 1 * basefreq, 1 / 1 ) );
freq2 = New Object( Sin( 3 * basefreq, 1 / 3 ) );
freq3 = New Object( Sin( 5 * basefreq, 1 / 5 ) );
freq4 = New Object( Sin( 7 * basefreq, 1 / 7 ) );
sum = New Object( Add( {freq1, freq2, freq3, freq4} ) );
gr( ctr(), sum, "4 Odd Harmonics", n + 1 );
減少した振幅で奇数次高調波を合計すると、方形波に近似します。
// same square wave, a lot more odd harmonics
n = 200;
basefreq = 2 * Pi() / n;
freqs = {};
For( i = 1, i <= 23, i += 2,
Insert Into( freqs, New Object( Sin( i * basefreq, 1 / i ) ) )
);
gr( ctr(), New Object( Add( freqs ) ), "12 Odd Harmonics", n + 1 );
より多くの高調波はそれを二乗するのに役立ちます
// multiply class
Define Class(
"multiply",
m_a = {};
_init_ = Method( {a, b = Empty()},
If( Is Empty( b ),
For( i = 1, i <= N Items( a ), i += 1,
Insert Into( m_a, v( a[i] ) )
),
m_a[1] = v( a );
m_a[2] = v( b );
)
);
next = Method( {},
result = m_a[1]:next();
For( i = 2, i <= N Items( m_a ), i += 1,
result = result :*</img> m_a[i]:next()
);
result;
);
);
// multiply two waveforms
n = 1000;
freq1 = New Object( Sin( .1, 1 ) );
freq2 = New Object( Sin( 2 * Pi() / n, 1 ) );
prod = New Object( Multiply( freq1, freq2 ) );
gr( ctr(), prod, "multiply", n + 1 );
2つの周波数を乗算します。低い周波数はエンベロープを作成します。
// similar, but control amplitude of freq1 using another sin wave
n = 1000;
freq2 = New Object( Sin( 2 * Pi() / n, 1 ) ); // lo freq
freq1 = New Object( Sin( .1, freq2 ) ); // hi freq, control amplitude with freq2
gr( ctr(), freq1, "amp is sin", n + 1 );
または、低い周波数を使用して高い周波数の振幅を制御します。
最後に、奇数の調和周波数の行列を保持するvwrapを作成し、行列をスカラーに合計する新しいクラスを作成します。
// try a matrix...use v(...) to make a vwrap to hold the matrix
n = 200;
mat = v( ((1 :: 49 :: 2) * (2 * Pi() / n)) );
// add the sin wrapper. sinmat:next() returns a row vector of 5 sin values
sinmat = New Object( Sin( mat, 1 / (1 :: 49 :: 2) ) );
// matrixSum assumes the argument class is returning a matrix and returns the scalar sum
Define Class(
"matrixSum",
m_mat = .;
_init_ = Method( {mat},
m_mat = v( mat )
);
next = Method( {},
Sum( m_mat:next() )
);
);
gr( ctr(), New Object( matrixSum( sinmat ) ), "25 Odd Harmonics", n + 1 );
オーバーシュートとリップルを本当に減らすには、より多くの高調波が必要になります。
良いドキュメント: https://www.jmp.com/support/help/en/15.1/index.shtml#page/jmp/classes.shtml