65.9K
CodeProject 正在变化。 阅读更多。
Home

SineSum:正弦和——在HTML5中

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.14/5 (7投票s)

2016 年 6 月 30 日

CPOL

11分钟阅读

viewsIcon

26376

downloadIcon

444

HTML5中的正弦和。

1. 引言

代码也可用 https://github.com/amarnaths0005/SineSum2

您可以在线使用 SineSum2

在电气工程的本科课程中,学生会遇到求正弦值和的问题。有些学生觉得这个概念容易理解,但有些学生则觉得没那么容易。SineSum 是一个程序,它通过可视化的辅助手段,帮助学生理解正弦和,查看叠加结果,以及观察改变不同幅度和相位时事物的变化。

斯坦福大学在线工程课程中有一个我很感兴趣的课程是 傅里叶变换 课程。在第二课中,教授就介绍了 SineSum 程序,这是一个用于可视化正弦和的 Matlab 程序。我最近开始了学习 HTML5 技术(HTML、CSS 和 Javascript)的旅程,我认为将基于 Matlab 的 SineSum 程序重写成 HTML5,使其能在浏览器中运行,是个好主意。这个应用就是我 HTML5 之旅的成果。

2. 正弦和

当许多不同幅度、不同相位的正弦函数叠加(也称为叠加)在一起时,结果就是正弦和。由于幅度为 A 的正弦值的范围是 -A 到 +A,叠加两个正弦值并不等同于简单地将它们的幅度相加。幅度和相位、频率会以一种不太直接的方式组合起来,形成最终的叠加结果。正是这种正弦和,该应用程序可以帮助用户进行可视化。正弦和定义为:

Sum of Sines

其中 Ak 是不同的幅度和 φk 是不同的相位。单个分量称为“谐波”;例如,涉及 A3 和 φ3 的分量构成了第三次谐波。此总和中的谐波总数为 N,t 是时间变量。在本例中,N 为 10,总和可以更明确地表示为:

Sum of Sines

换句话说,这个 HTML5 应用程序计算了前十次谐波的总和,允许用户改变各个幅度和相位。用户可以可视化单个谐波的波形,也可以可视化正弦和。此外,还显示了 3D 频谱图。下面是应用程序在 Chrome 上的截图。

Sum of Sines Screen

在屏幕顶部,用户选择需要指定幅度和相位的谐波编号,并通过顶部的滑块控件来改变幅度和相位。当这些幅度和相位值改变时,表格中对应的行也会相应改变,并且下面的三个图也会动态变化。频谱图以 3D 图的形式显示这些幅度和相位值。被修改的谐波的波形显示在表格下方中间的图表中。表格下方最右边的图表显示了正弦和,即十次谐波叠加的结果。点击顶部的“播放声音”按钮会播放与当前幅度相位设置相对应的声音。

在本文的其余部分,我们将描述实现此结果的软件方面。

3. 更详细的需求

在本文的这一部分,将更详细地介绍需求。下图列出了 HTML 中 GUI 元素的 ID,软件需求在图表后面的表格中给出。

Sum of Sines Screen

用户操作 应用程序功能
用户在 opHarmonic 选项框中更改谐波编号。
  1. 范围滑块 raAmplraPhase 应反映所选谐波对应的幅度和相位值。输出字段 opAmplopPhase 也应反映这些值。
  2. 表格 tblHarmonic 应以不同的颜色高亮显示当前谐波对应的行。
  3. canvas01 应更改以显示当前谐波对应的波形。
用户更改范围滑块 raAmpl 中的值。
  1. 输出字段 opAmpl 应相应地更改。
  2. 在表格 tblHarmonic 中,当前谐波对应的幅度应相应地更改。
  3. canvas01 中显示的幅度应动态更改。
  4. 显示正弦和的 Canvas canvas02 应动态更改。
  5. 在显示 3D 频谱图的 canvas canvas03 中,当前谐波的幅度线应动态更改。
用户更改范围滑块 raPhase 中的值。
  1. 与上面(raAmpl 的情况)类似,但针对相位。
用户点击表格 tblHarmonic 的某一行。
  1. 点击的行应以不同的颜色高亮显示。
  2. 选项框 opHarmonic 应更改为当前谐波值。
  3. UI 元素 raAmplraPhaseopAmplopPhase 应更改为与当前谐波对应的那些值。
  4. Canvas canvas01 应更改以反映当前谐波。
用户点击“播放声音”按钮。
  1. 应播放对应于正弦和波形的音频。
用户点击“重置值”按钮。
  1. 幅度和相位值应重置为应用程序启动时存在的值。

4. 编码方面

与大多数 HTML5 应用程序一样,该软件包含三个部分——HTML 部分、CSS 部分和 JavaScript 部分。此应用程序中的 HTML 和 CSS 部分相当直接;检查这些文件是一项简单的任务。我们在下面对 JavaScript 部分进行更多解释。代码的一小部分也使用了 JQuery。

4a. 重要变量

十次谐波的幅度和相位值存储在以下几个数组中:

// Ten amplitudes and ten phases
var amplitudeArray = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
var phaseArray =     [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]; 

有一个内部变量 currentHarmonic,用于存储用户正在更改参数的当前谐波的值。上面两个数组中的二十个值被组合成另一个名为 sineSumValues 的数组,该数组用于生成显示正弦和的图。对于时间变量 tVal 的特定值,正弦和的计算如下面的代码片段所示:

var sineSum = 0.0;
for (var j = 0; j < numberOfHarmonics; ++j){
    var val1 = 2 * Math.PI * (j + 1) * tVal + phaseArray[j];
    var val2 = amplitudeArray[j] * Math.sin(val1);
    sineSum += val2;
}

4b. 在显示 2D 图形的 Canvas 上绘图

此应用程序中有两个显示 2D 图形的 Canvas;它们是 canvas01canvas02。在这些 Canvas 中,图表的 x 轴代表时间。在这两个 Canvas 上绘图的方法如下:

  1. 绘制图的外框和网格。这在一个名为 drawGraphBox() 的函数中完成。此函数还在这两个 Canvas 中绘制一些文本内容。
  2. 然后是绘制实际曲线的部分。为此,时间维度(持续 2 秒)被划分为 400 个时间点。对于这些时间点中的每一个,计算纵坐标值,并通过一系列 lineTo() Canvas 函数调用,在单个 moveTo() 调用之后绘制图形。要确保绘制的图形是直立的,请注意 Canvas 坐标系 y 轴向下。
  3. 为了模拟动画效果,在每次绘图调用之前使用 context.clearRect() 清除 Canvas。
  4. 向 Canvas 添加一些特定于正在绘制的 Canvas 的更多标签。

例如,线条的绘制在此代码片段中完成:

xPoint0 = xMarginLeft;
yPoint0 = (sineVals[0] - yMin) * yFactor + yLim1;
context01.moveTo(xPoint0, yPoint0);

for( var i = 1; i < sineSumValues.length; ++i) {
	xPoint1 = xMarginLeft + i * xStep;
	yPoint1 = (sineVals[i] - yMin) * yFactor + yLim1; 
	context01.lineTo(xPoint1, yPoint1);
}

4c. 在显示 3D 图形的 Canvas 上绘图

这与 canvas canvas03 中的绘图有关。最初,我考虑使用 WebGL 来绘制 3D 图形;并开始学习 WebGL。然而,在仔细查看斯坦福大学在线工程 - 傅里叶变换网站上提供的 SineSum2 Matlab 应用程序中的图形后,我认为巧妙地使用简单的 2D 图形调用可以创建 3D 效果。

  • 外边界框只是一个线框,它由一组八条线绘制而成,使用 Canvas 的 moveTo()lineTo() 函数调用。此外,还绘制了网格以增强 3D 效果。
  • 在频谱图中,每个谐波由一个表示其幅度和相位的点来表征。利用我基本的向量代数知识,我定义了三个向量,或者说三个方向——分别代表谐波、相位和幅度。一旦定义了这些方向,绘制每个频谱点的线条就成了一项直接的任务。
  • 为了给频谱线“位于”盒子内部的感觉,外边界框的一些线条在绘制频谱线之前绘制,而另一些则随后绘制;这样就定义了一个 z 顺序,从而产生了 3D 的感觉。
  • 与之前一样,为了模拟动画效果,在绘制之前使用 context.clearRect() 清除 Canvas 区域。

4d. 播放声音

我们使用 Web Audio API 来生成声音。这涉及到创建一个音频上下文,然后创建对应于幅度和相位数组的周期波。感谢 CP 会员 M. R. van Mourik 的建议,并且也包括了本文评论中的相关代码。

之前,我曾使用 GitHub 上的 Riffwave 项目。此项目在此项目中已被 Web Audio API 取代。

您可能会注意到 Matlab 生成的声音与此应用程序生成的声音不同。Matlab 如何产生声音我不得而知。您会发现使用不同的幅度和相位会产生不同类型的声音,这是预期的行为。

4e. 代码的其他方面

  • 我没有为此应用程序使用任何框架(我还在学习中),您可能会发现代码非常基础。除了 JQuery,我只用了它来处理应用程序的一小部分——用于在点击表格行时高亮显示。为此,我将 JQuery 3.0.0 的最小化版本与代码一起打包。
  • 我使用了 IIFE(立即调用的函数表达式),所以您会发现我所有的 JavaScript 代码都以 (function() { /* 我的代码 */ } ()) 的形式使用。
  • 要启动应用程序,只需在浏览器中打开文件 sineSum.html

5. 值得关注的要点

虽然我已从事编程工作近三十年,但对于 HTML5 我相对较新。因此,代码中很可能存在一些非最优之处。我恳请您指出代码中的任何不足之处,以便我能从中学习并改进后续版本。

有一点是肯定的——我非常享受开发这个应用程序时的狂喜与痛苦。学习 JavaScript 编程很有趣。我希望您也能喜欢玩这个应用程序。如果您在移动滑块时看到图形舞动,请告诉我。如果您觉得有需要改进的地方,请不要犹豫告诉我。如果您觉得缺少任何功能,请写信给我。

我使用 Visual Studio Code 开发了这个应用程序。非常享受使用它——这是 Microsoft 的一款优秀工具。

6. 浏览器兼容性

我在 Windows 7 机器上的 Chrome(版本 51.0.2704.103 m)和 Firefox(版本 47.0)上进行了测试。以及我的 Macbook Pro 上的 Safari 8.0.8。在所有这三者上运行都正常。

7. 验证

我通过为两个程序——Matlab 程序和这个 JavaScript 应用程序——提供接近相同的幅度和相位值进行了测试。两个程序生成的图表都非常相似。

还有一点需要验证。如果两个或多个谐波的相位为零,并将它们叠加,则曲线必须通过点 (0, 0)、(1, 0)、(2, 0),其中 0 是时间为 0 秒、1 秒和 2 秒时的结果总和。这在此 JavaScript 应用程序中也得到了验证。如果您发现任何问题,请写信给我。

我已采取措施确保用户的操作非常有限。这是使软件防错的一种方法。

8. 结语

本文介绍了一个用于可视化正弦和的简单应用程序。这是我的第一个 HTML5 应用程序,它让我真正学习了三个部分——HTML、CSS、JavaScript,以及一点 JQuery。该应用程序旨在帮助学生学习正弦和的各个方面。如果这个目标能在某个地方至少帮助到一个学生,我将感到荣幸。

代码也可用 https://github.com/amarnaths0005/SineSum2

历史

  • 2016 年 6 月 30 日:版本 1.0
  • 2016 年 7 月 5 日:版本 1.1 - 修改了声音生成方式
  • 2016 年 7 月 8 日:版本 1.2 - 修复了 ccdsystems 报告的声音播放 bug
  • 2023 年 1 月 24 日:添加了 GitHub Pages 链接

致谢

我想感谢以下人员

  • Brad Osgood 教授,通过斯坦福大学在线工程课程向我介绍了 SineSum 程序。
  • Michel Buffa 教授,通过 edX 平台提供了 HTML 课程。这极大地加速了我对 HTML5 的学习。
  • CodeProject 会员 M. R. van Mourik,他建议使用 Web Audio API 方法生成声音,并提供了相关的代码片段。
  • CodeProject 会员 ccdsystems,他指出了一个声音播放相关的 bug
© . All rights reserved.