声场 | 音频波形显示探究

图1 封面

引言

本文将持续研究隐藏在电音合成软件背后的数学问题:线性代数、信号与系统、和声学基础。以上的数学知识与游戏开发、计算机音频、计算机图像联系紧密。正因为拥有强大的数学基础,计算机模拟的音像世界才可以像今天这样逼真。数学在音频编辑器的开发中占有重要的位置。对此数学单独进行研究,由此显得非常重要。本文将对声音和合成和显示进行探究,进而使用这一些专业知识编写音频编辑器或图形程序。

一.线性代数

1.点乘

我们知道点乘在数学中,又称数量积。只需要记住,向量点乘就是对应分量乘积的和,其结果是一个标量。在平面中,两个向量的点乘可表示为:

a = \begin{bmatrix} x_1\\ y_1\\ \end{bmatrix} ,b = \begin{bmatrix} x_2\\ y_2\\ \end{bmatrix}
a \cdot b = [x_1*y_1 + x_2*y_2]

一般来说,点乘的结果描述了两个向量的相似程度,点乘结果越大,两向量越接近。点乘等于向量的大小与向量夹角cos值的积。其公式为:

a \cdot b =||a||*||b||cos\theta \tag{1}

实际上,我们在计算中,更重要的是求出两个向量的之间的夹角。对上述的公式(1)稍作变换,可得:

\theta = arccos(\frac{a \cdot b}{||a||*||b||})

值得注意的是,此公式十分重要。在本文中被用于Unity仿真中的向量夹角计算。

2.线性空间变换

方阵能描述任意的线性变换。其中,线性变换,从感性上讲,指的是对图片或函数图像等其所在空间的,拉伸、旋转、仿射等变换。
想象任意一个2维空间的向量,比如说:a = \begin{bmatrix}3\\5\\\end{bmatrix}。那么,向量a其实可以表示为:a = 3*\begin{bmatrix}1\\0\\ \end{bmatrix} + 5*\begin{bmatrix}0\\1\\ \end{bmatrix}。由于向量可视为空间中的一个点,向量a表示从原点向x走3个单位后,再向y5个单位。更进一步地,对于任意一个向量:b = \begin{bmatrix}x_1\\y_1\\\end{bmatrix},可以表示为:从原点出发,向x轴走x_1个单位后,再向y轴方向走y_1个单位,即到达向量b的所在地。那么,任意一个二维空间中的向量,可以表示为基向量的线性组合

一个任意的向量a,被描述为了两个基向量x= \begin{bmatrix}1\\0\\ \end{bmatrix} , y = \begin{bmatrix}0\\1\\ \end{bmatrix}的线性组合。但实际上,基向量不一定要相互垂直(讲人话:x轴和y轴不一定要相互垂直)。只要两个向量不在一条直线上,就可以构成一组基向量来描述二维空间中的任意一个点。

以下是几个不同基向量所张成的空间。为了方便观察,我在其中放置一样的y=3.5sin(5x)函数。可以观察到,随着选取的基向量的不同,空间可以发生放大、缩小、切变等线性变换。存在于里面的函数图像,虽然位置没有发生改变,但是由于函数所处空间的改变,函数“被迫”发生了改变。

图2 空间变换

设基向量X = \begin{bmatrix}x_1\\y_1\\\end{bmatrix},Y = \begin{bmatrix}x_2\\y_2\\\end{bmatrix}张成了一个二维平面空间。使用基向量X,Y构成一个2\times2的矩阵M:
M = \begin{bmatrix} x_1 & y_1 \\ x_2 & y_2 \\ \end{bmatrix} \tag{2}
用一个向量a = \begin{bmatrix}x&y\end{bmatrix}乘以该矩阵M,则称为对向量a的一次“变换”。
a*M = \begin{bmatrix}x&y\end{bmatrix} \begin{bmatrix} x_1 & y_1 \\ x_2 & y_2 \\ \end{bmatrix} \tag{2} = \begin{bmatrix}x*x_1 + y*x_2 & x*y_1 + y*y_2\end{bmatrix}

3. 旋转

问题的提出
将一个函数图像逆时针旋转30°

具体求解步骤
Step 1:随机生成一个函数序列
Step 2:构造方阵M
Step 3:函数序列每一点的坐标,乘以方阵M
Step 4:显示该函数图像

函数序列生成
使用matlab自带的rand()函数生成随机离散序列X(n),使用smooth()函数对X(n)进行数据平滑。
其代码如下:

clc;
clear;
%%
%%随机生成一个起点和终点都在0附近,均值为0的函数波形
n = 300;
x = 0.5*rand(1,n);
x = x - mean(x);
x(1:10) = 0;
x(n-10:n) = 0;
for i = 1:10
    x = smooth(x,10);
end

x(1) = 0;
x(length(x)) = 0;
X = zeros(n,2);
X(:,1) = linspace(0,1,n);
X(:,2) = x;
plot(X(:,1),X(:,2),'.')

构造方阵M
在笛卡尔坐标系中,基向量X = \begin{bmatrix}1&0\\\end{bmatrix},Y = \begin{bmatrix}0&1\\\end{bmatrix}.使得向量X、Y向逆时针旋转30°,可得:
X = \begin{bmatrix}cos30°&sin30°\\\end{bmatrix}
Y = \begin{bmatrix}cos(30° + 90°)&sin(30° + 90°)\\\end{bmatrix}
则,M = \begin{bmatrix} cos30° & sin30° \\ cos(30° + 90°) & sin(30° + 90°) \\ \end{bmatrix} \tag{2}

结果演示
根据上文求解步骤编写代码,实现函数旋转算法。代码运行结果如下所示。

图3 函数旋转

稳定性测试
使用Matlab,随机生成一个函数序列,使用开发的旋转算法持续旋转函数图像,并将结果打印出来,观察算法的稳定性。由结果可见,代码对函数图像的旋转稳定可靠。

核心代码

for angle = 1:10:360
%目标向量
pos1 = [cosd(angle);sind(angle)];
pos2 = [0;0];
pos3 = pos1 - pos2;
pos0 = [1;0];
%%
if(pos3(2)>=0)
    alpha = acos(sum(pos3.*pos0)/(norm(pos3)*norm(pos0)));
else
    alpha = -1*acos(sum(pos3.*pos0)/(norm(pos3)*norm(pos0)));
end

%(alpha/pi)*180
temp = [cos(alpha) sin(alpha);...
        cos(alpha + pi/2) sin(alpha+ pi/2);];
A = norm(pos3)/1;
result = X*(A*temp) + pos2';
plot(result(:,1),result(:,2),'.');
hold on
end

其结果如下:

图4 算法稳定性测试

模型的改进
令人兴奋的是,将图片放置在空间中,使用方阵M对空间进行线性变换,可以很方便实现图片的放大缩小旋转操作。只需写一点点matlab代码。便可得到以下结果:
图5 图像放大、缩小、旋转代码实现结果

Unity仿真

在matlab完成算法探究以后,在游戏开发引擎Unity上实现该算法,完成算法的落地。

具体求解步骤
Step 1:使用Unity搭建参加场景,创建地面(Plane)、圆柱(Cylinder)等物体
Step 2:编写脚本,绑定组件。脚本逻辑是:当用户按下鼠标时,摄像头坐标系中发出的射线与地面相互碰撞。根据此来确定基向量以及方阵M
Step 3:根据方阵M计算组件线段渲染器(LineRender)应该所处的位置
Step 4:显示该函数图像

稳定性测试
多次地、随机地点击游戏画面,测试算法的稳定性和性能。实验结果表明,算法稳定可靠地运行,完成了对算法的落地。.

图6 Unity仿真测试1

图7 Unity仿真测试2

代码

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LineTest : MonoBehaviour
{
    public float length = 0;
    public float height = 0;//线段的高度
    public float w = 0;    //角频率
    public float A = 0;     //震动幅度
    private Vector3 Vec;  //用于存储每一点的坐标
    private LineRenderer lineRenderer;

    // Start is called before the first frame update
    void Start()
    {
        Vec = new Vector3();
        //设置长度
        GetComponent<LineRenderer>().positionCount = (int)length;
    }
    public void Run(float x,float y){
        float l = (float)Math.Sqrt(x*x + y*y);//模长,假设0为原点
        float alpha = 0;                      //用于求向量夹角
        for (int i=0;i<length;i++){
            
            float posX = (float)(i/length);
            float posY = A*(float)Math.Sin(w*posX);

            alpha = 0;
            if(y>=0){
                alpha = (float)Math.Acos(x/l);
            }
            else{
                alpha = -1*(float)Math.Acos(x/l);
            }
            Vec.x = 0.1f*(float)(posX*l*Math.Cos(alpha) + posY*l*Math.Cos(alpha + Math.PI/2));
            Vec.y = height;
            Vec.z = 0.1f*(float)(posX*l*Math.Sin(alpha) + posY*l*Math.Sin(alpha + Math.PI/2));

            GetComponent<LineRenderer>().SetPosition(i,Vec);
        }
    }

    // Update is called once per frame
    void Update()
    {

    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容