在......的最后如何使用定义类我暗示关于JSL类实例很难复制有一些有趣的事情。如果X引用实例,则Y = X使得Y和X 参考到相同实例。将实例传递给用户定义的函数时,也会发生同样的事情:该函数的值为不实例的副本;它指到相同实例。因此,在函数内部更改实例也会为调用方更改它。如果您曾经将矩阵传递给函数并在函数中对其进行了修改,请期待调用者的复制要进行更新,您知道JSL通过值将参数传递给用户函数。
JMP通过复制来传递参数,但是...
请注意,矩阵是复制的,因此对函数内部矩阵的更改是对副本的更改,而不是对原始内容的更改。请注意,黑色的大参考点也会被复制,但不会被复制。这使刚开始的JAVA程序员感到很多头痛,因为他们还没有看到这张照片。在函数中,您可以做两个非常不同的事情来变量一个 。
- 您可以调用一个方法,例如a:set(42);
- 您可以分配一个值,例如a = 42;
如果(1)您更改了亚皆老街对象的值,从3到42。这可能就是您的意思。在情况(2)中,您覆盖了旁边的大黑点一个与42。您可能并不打算这样做。
以下代码使用保留对其他对象的引用的对象。所有对象都有一个next()方法,因此可以用有趣的方式来组成对象。next()方法产生值序列中的下一个值。一些对象表示一个常数,并且始终产生相同的下一个值。其他对象(如添加对象)具有其他两个对象(+运算符的左侧和右侧)。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是类的名称,它包装了一个值,可以是数字或矩阵。它具有一个设置器,该设置器将拒绝它不喜欢的值,还有一个名为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个值的矩阵,并创建一个不可见的表,并运行Graph Builder,并在不再需要隐藏表时使用了一些魔术方法将其关闭。让我们尝试一下。
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_方法采用确定计数器递增速度的速率。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(...)。
两个计数器并行运行,从零开始五个步骤。
现在,换一种方式:让计数器的汇率成为另一个计数器。
// this variation begins to show the power of composition
gr( ctr(), ctr( ctr() ), "count up B (first step is 0)", 5 );
第一步是零,因为速率计数器的第一个结果是零。
该图的Y轴使用两个计数器的功能组合。让我们添加一个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 );
使用另一个正弦波的第一位来提高频率
并且可以绘制两个不同频率的正弦波。
gr( New Object( Sin( 4 * Pi() / 99, 3 ) ), New Object( Sin( 6 * Pi() / 99, 3 ) ), "2X3 sin()", 100 );
简单的整数比率构成了不错的模式
另一个类和辅助函数;该类将一个或多个其他类添加在一起,而偏移量帮助器添加了一个常量...或另一个函数,可能是...未经测试的。
// 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 );
现在所有步骤都比以前大了一个。
// 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 );
将两个频率相乘;较低的频率产生包络。
// 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/zh/15.1/index.shtml#page/jmp/classes.shtml