在......的最后如何使用定义类我暗示 JSL 类实例难以复制有一些有趣的地方。如果 X 引用一个实例,则 Y=X 使得 Y 和 X 都成立参考到相同的实例。 当您将实例传递给用户定义的函数时,也会发生同样的事情:该函数的值是不是实例的副本;它指的是到相同的实例。 因此,更改函数内部的实例也会改变调用者的实例。 如果您曾经将矩阵传递给函数并在函数中修改它,期望调用者的复制要更新的是,您知道 JSL 按值将参数传递给用户函数。
JMP passes arguments by making copies, but...JMP passes arguments by making copies, but...JMP passes arguments by making copies, but...JMP passes arguments by making copies, but...JMP 通过复制来传递参数,但是...
请注意,矩阵是复制的,因此函数内部矩阵的更改是针对副本而不是原始矩阵进行的。 请注意,黑色大参考点也被复制,但它所引用的对象未被复制。 这让初学JAVA的程序员很头疼,因为他们没有见过这张图。 在函数内,您可以对变量执行两种截然不同的操作A 。
- 你可以调用一个方法,比如 a:set(42);
- 您可以指定一个值,例如a=42;
如果 (1) 你改变了亚皆老街对象的值从 3 到 42。 这可能就是您想要做的。在情况(2)中,您覆盖旁边的大黑点A与 42. 你可能不是故意这样做的。
以下代码使用保留对其他对象的引用的对象。 所有对象都有一个 next() 方法,因此可以以有趣的方式组合对象。 next() 方法生成值序列中的下一个值。 有些对象代表一个常量,并且总是产生相同的下一个值。 其他对象(例如 add 对象)有两个其他对象(+ 运算符的左侧和右侧)。 Add:next() 调用 left:next() 和 right:next() 并将两个答案相加。
完整的 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 是类的名称,它包装一个值,可以是数字或矩阵。 它有一个 setter,将拒绝它不喜欢的值,还有一个名为 next() 的 getter,用于返回序列中的下一个值。 因为写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 );
A single point, at x=13, y=42A single point, at x=13, y=42A single point, at x=13, y=42A single point, at x=13, y=42单个点,x=13,y=42
等一下,它会变得更好...让我们创建一个计数器类,它将在连续调用 next() 时返回 0,1,2,3,...。
// 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_ 方法采用一个速率来确定计数器递增的速度。 Rate 可以是一个常量,通常为 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 轴的两个单独的计数器实例被传递给 gr(...)。
Two counters, running in parallel, for five steps starting at zero.Two counters, running in parallel, for five steps starting at zero.Two counters, running in parallel, for five steps starting at zero.Two counters, running in parallel, for five steps starting at zero.两个计数器并行运行,从零开始执行五个步骤。
现在,做一些不同的事情:让我们将计数器的速率设置为另一个计数器。
// this variation begins to show the power of composition
gr( ctr(), ctr( ctr() ), "count up B (first step is 0)", 5 );
The first step is zero because the rate counter's first result is zero.The first step is zero because the rate counter's first result is zero.The first step is zero because the rate counter's first result is zero.The first step is zero because the rate counter's first result is zero.第一步为零,因为速率计数器的第一个结果为零。
该图的 Y 轴使用两个计数器的功能组合。 让我们添加一个 sin() 类。
// sin() wrapper class
Define Class(
"sin",
m_rate = .; // 0<STEP><PI. m_amp=".;"> Sin( m_pos += m_rate:next() ) // return
);
);</PI.></STEP>
Sin 产生一个无限正弦波,其频率和幅度由常数或其他类实例确定。 它还保持内部地位。 您可以从评论中看出它可能需要更多思考,但它适用于这个演示。 这是一个单周期波形。
gr( ctr(), New Object( Sin( 2 * Pi() / 100, 3 ) ), "sin()", 101 );
Single cycle of sine waveSingle cycle of sine waveSingle cycle of sine waveSingle cycle of sine wave单周期正弦波
与具有另一个计数器增量的计数器类似,正弦波可以具有可变频率。
gr( ctr(), New Object( Sin( New Object( Sin( .0002, 1 ) ), 3 ) ), "variable frequency", 1000 );
Ramping up the frequency using the first bit of another sine waveRamping up the frequency using the first bit of another sine waveRamping up the frequency using the first bit of another sine waveRamping up the frequency using the first bit of another sine wave使用另一个正弦波的第一位来提高频率
两个不同频率的正弦波可以相互绘制。
gr( New Object( Sin( 4 * Pi() / 99, 3 ) ), New Object( Sin( 6 * Pi() / 99, 3 ) ), "2X3 sin()", 100 );
Simple integer ratios make nice patternsSimple integer ratios make nice patternsSimple integer ratios make nice patternsSimple integer ratios make nice patterns简单的整数比率可以创造出漂亮的图案
另一个类和辅助函数;该类将一个或多个其他类添加在一起,并且偏移量助手添加一个常量...或另一个函数,可能...未经测试。
// 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。
// compared to a previous example, this one increments earlier
gr( ctr(), ctr( offset(1,ctr( 1 )) ), "count up C (first step is 1)", 5 );
Now all the steps are one bigger than before.Now all the steps are one bigger than before.Now all the steps are one bigger than before.Now all the steps are one bigger than before.现在所有的台阶都比以前大了一步。
// 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 );
Summing odd harmonics at reduced amplitude approximates a square wave.Summing odd harmonics at reduced amplitude approximates a square wave.Summing odd harmonics at reduced amplitude approximates a square wave.Summing odd harmonics at reduced amplitude approximates a square wave.以减小的幅度求和奇次谐波近似于方波。
// 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 );
More harmonics help square it upMore harmonics help square it upMore harmonics help square it upMore harmonics help square it up更多谐波有助于调和
// 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 );
Multiply two frequencies; the lower frequency creates the envelope.Multiply two frequencies; the lower frequency creates the envelope.Multiply two frequencies; the lower frequency creates the envelope.Multiply two frequencies; the lower frequency creates the envelope.将两个频率相乘;较低的频率创建包络。
// 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 );
Alternatively, control the amplitude of the higher frequency using the lower frequency.Alternatively, control the amplitude of the higher frequency using the lower frequency.Alternatively, control the amplitude of the higher frequency using the lower frequency.Alternatively, control the amplitude of the higher frequency using the lower frequency.或者,使用较低频率控制较高频率的幅度。
最后,创建一个包含奇次谐波频率矩阵的 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 );
It will take a lot more harmonics to really reduce the over-shoot and the ripples.It will take a lot more harmonics to really reduce the over-shoot and the ripples.It will take a lot more harmonics to really reduce the over-shoot and the ripples.It will take a lot more harmonics to really reduce the over-shoot and the ripples.需要更多的谐波才能真正减少过冲和纹波。
好医生: https://www.jmp.com/support/help/en/15.1/index.shtml#page/jmp/classes.shtml