编程科学/Auld Lang Sine
你很可能之前已经接触过正弦和余弦。正弦曲线(包括正弦和余弦)是周期函数。周期函数具有以下性质
对于所有x 和p 的某些值。满足上述等式的p 的最小值被称为该函数的周期。
如果你不熟悉正弦和余弦函数,这就是正弦波的样子
请注意,对于没有相位和频率偏移的正弦波(如上所示),当x 为零时,正弦波的振幅(y 值)为零(具有上升斜率)。该波在x = 2 再次达到零(具有上升斜率)π. 对比余弦波
与正弦波不同,正弦波在p 的倍数处具有零交叉点π,余弦波在p 的倍数处具有峰值和谷值π. 与正弦波一样,周期或峰值到峰值长度为 2π.
如果你仔细观察这两个波,你会发现余弦只是正弦波向左移动了 个单位。因此,我们可以用正弦来定义余弦
请注意,数学家通常将正弦缩写为sin,将余弦缩写为cos。以上说明了修改正弦波的常见方法之一:移动波的相位,通常使用符号
另一种修改是改变正弦波的振幅,或者换句话说,改变峰值的高低范围。变量a 用于表示振幅,因此允许振幅修改的正弦波公式为
最后,通常会改变正弦波的频率,或者在给定区域内有多少个峰值(或谷值)。变量通常用于此任务
如果我们将 设置为 2,我们将获得给定区域内两倍的峰值(或谷值)。频率的倒数是周期,因此将 设置为 2 将使峰值到峰值距离缩短一半。在频率为 2 的特定情况下,正弦波的周期将为π.
这里有一个巧妙的技巧。如果你想找到这种形式的一般符号波的“第一个”零交叉点的位置,请更改相移和将它与x 相结合的运算符的符号,然后将 提取出来。对于余弦,具有单位振幅和频率加倍,我们有
此版本的余弦在 处具有第一个零交叉点。[1] 换句话说,要找到第一个零交叉点,请将相移除以频率并取反(假设相移被添加进去)。
Sway 内置了sin 和cos 函数,但这些函数假设振幅 = 1,频率 = 1 且相移 = 0。[2] 为了实现sine 和cosine,我们将采用我们通常的对象方法
function sine(amp,freq,shift) { function value(x) { amp * sin(freq * x + shift); } this; } function cosine(amp,freq,shift) { sine(amp,freq,shift + (pi() / 2)); }
请注意,我们如何将余弦包装为正弦,因为余弦只是具有相移的正弦。
让我们利用我们在上一节中学习的关于查找“第一个”零交叉点的技巧,并将其实现
function sine(amp,freq,shift) { function value(x) { ... } function firstZero() { // phase shift is added in so just divide and negate -(real(shift) / freq); } this; }
让我们看看它是否适用于频率为 2 的余弦
var w = cose(1,2,0); sway> -(pi() / 4); REAL_NUMBER: -0.7853981634 sway> w . firstZero(); REAL_NUMBER: -0.7853981634
不错。让我们也检查一下正弦波的值在该点确实为零
sway> var fz = w . firstZero(); REAL_NUMBER: -0.7853981634 sway> w . value(fz); w . value(fz) is 0.000000e+00
bingo!
正如 SPT 在 CMT 的第 XV 章中指出的那样,正弦的导数是余弦,余弦的导数是正弦的负数。
使用第一个规则,我们可以将diff 函数添加到sine 构造函数中。当然,为了符合我们谦逊的微分系统,我们需要根据需要传入自变量和关于变量
function sine(amp,freq,shift) { function value(x) { ... } function firstZero() { ... } function diff() { cosine(amp,freq,shift); } this; }
当然,此实现假定自变量和关于变量是一样的。它还假定自变量只是一个符号。因此,我们无法构造形式为;
为此,我们将不得不像处理项一样,允许自变量成为可微分对象。回想一下项构造函数
function term(a,iv,n) { function value(x) { ... } function toString() { ... } function diff(wrtv) { if (n == 0) { constant(0); } else { term(a * n,iv,n - 1) times iv . diff(wrtv); } } if (iv is :SYMBOL) { iv = variable(iv); } this; }
还记得diff 函数如何实现链式法则。我们将需要对sine 构造函数采用相同的策略
function sine(amp,freq,iv,shift) { function value(x) { ... } function firstZero() { ... } function diff(wrtv) { cosine(amp,freq,iv,shift) times iv . diff(wrtv); } if (iv is :SYMBOL,iv = variable(iv)); this; }
我们剩下要做的就是实现sine 的可视化(当然还有测试)
function toString() { "" + amp + " sin(" + freq + "(" + iv . toString() + ")" + shift + ")"; }
根据 CMT,正弦函数的导数是余弦函数,余弦函数的导数是负正弦函数。因此,正弦函数的二阶导数是负正弦函数。
1. 函数 和函数 之间有什么区别?
2. 为什么我们不能将 正弦 和 余弦 构造函数命名为 sin 和 cos?
3. 在 正弦 构造函数中添加以下简化。如果相移等于或大于 2π,减去 2π.
4. 解释为什么之前的简化在数学上是有效的。
5. 简化正弦对象的构造,以便如果幅度为零,则生成零对象。
6. 简化正弦对象的构造,以便如果频率为零,则生成常数项对象。
7. 简化正弦对象的可视化,以便如果幅度、频率和相移分别为 1、1 和 0,则省略它们。
8. 查找并添加其他可视化调整。提示:如果频率 ≠ 1 但自变量是系数 ≠ 1 的项,你的可视化应该是什么样子?