资讯详情

Matlab三角函数实用指南:从弧度制到向量化的核心技巧

📅 2026/10/7 22:43:49 | 华诺云谱 👁 阅读
Matlab三角函数实用指南:从弧度制到向量化的核心技巧
1. 三角函数在Matlab中的核心用武之地1.1 为什么三角函数是Matlab的常客Matlab里三角函数这个家族说大不大说小也真不小。你要是去查文档会发现sin、cos、tan、asin、acos、atan、sinh、cosh、atan2再加上它们的“带d版本”sind、cosd、tand、atand……一眼望过去至少有二十来个。很多刚接触Matlab的同学会觉得不就是高中学过的sin和cos嘛键盘敲一下就出来了还能有什么花样。但实际用下来你会发现三角函数的坑远比你想象的多角度制还是弧度制输入的是数组怎么办结果里的微小误差要不要处理反三角函数的值域为什么和手算对不上这篇速成笔记就是为了把这些事情一次讲透。我会从最基本的sin、cos开始一路讲到双曲函数、复数域上的三角函数、矩阵批量计算、绘图实战最后再把我自己踩过的一些坑整理成排查清单。无论你是刚安装好Matlab准备做信号处理课设的新手还是已经写了不少脚本但从来没系统性整理过三角函数用法的老手这篇笔记都可以随手翻一翻。1.2 速成之前先分清角度制与弧度制很多人第一次在Matlab里算三角函数就翻车根子在于角度制和弧度制没分清。Matlab的默认三角函数sin、cos、tan输入输出都是弧度制。也就是说sin(30)算的不是“30度”的正弦而是“30弧度”的正弦结果约为-0.988。如果你拿计算器按sin30得到0.5然后来Matlab里一验算发现对不上那不是Matlab坏了是单位搞混了。这里我建议大家把弧度制当成Matlab的“母语”——毕竟sin、cos、tan这类核心函数在数学定义上就是以弧度为标准的。而如果你习惯用角度思考比如算一个30度角的对边长度那么有两种做法第一种是自己手动转弧度sin(30 * pi / 180)第二种是直接用Matlab专门提供的角度版本sind(30)结果就是0.5。同理还有cosd、tand、atand、atan2d这些带d的函数都是把单位固定在“度”上省去了每次乘以pi/180的麻烦。提示sind这类角度版本函数在做角度制几何计算时非常好用但要注意它们和弧度制版本在输入为数组时行为完全一致不用担心批量计算时单位处理不一致的问题。2. 基础三角函数语法速查与细节拆解2.1 sin、cos、tan与它们的“带d版本”先从最核心的sin说起。它的基本调用方式就是y sin(x)其中x可以是标量、向量、矩阵甚至是多维数组。这一点是Matlab最舒服的地方——你不需要写循环去逐个元素求正弦直接整个数组丢进去输出就是同样大小的数组。x 0:0.1:pi; % 生成从0到pi、步长0.1的向量 y sin(x); % 对向量每个元素求正弦这里的x有32个元素y也是32个元素一一对应。这种“整个数组一起算”的风格叫作向量化是Matlab性能优化的核心原则之一。我在后面的章节会专门展开讲为什么向量化比for循环快以及它在三角函数场景下具体怎么写。cos和tan的用法完全一样没什么好特别说的。真正值得留意的是tand这个函数的一个细节当输入角度是90、270这类正切函数无定义的点时tan(pi/2)会因为浮点数表示pi/2不够精确算出一个非常大的数而不是Inf但tand(90)则会直接返回Inf因为它在内部做了特殊处理。这里我建议你在做涉及正切的数值计算时优先考虑用tand配合角度制至少能避免在无定义点附近出现莫名其妙的巨大数值。另外一个容易被忽视的点是sec、csc、cot这些倒数三角函数。Matlab里也有sec、csc、cot以及它们的角度版本secd、cscd、cotd但实际工程中用得不多因为直接用1 ./ sin(x)也能得到相同结果。唯一的差别在于csc这类函数在输入接近0时返回的是Inf还是很大的数——Matlab文档里说csc会把0映射为Inf而1/sin(x)在x为0时则是Inf因为Matlab里除零不报错而是给Inf。两个行为基本一致但为了代码可读性我更推荐直接用倒数写法。2.2 反三角函数的用法与取值范围陷阱反三角函数是另一个重灾区。asin、acos、atan分别对应反正弦、反余弦、反正切它们返回的是弧度制角度。这里有个非常关键的取值范围问题asin返回值的范围是[-pi/2, pi/2]acos返回值的范围是[0, pi]atan返回值的范围是[-pi/2, pi/2]。这意味着什么呢举一个非常典型的例子如果我在平面直角坐标系里有一个点(x, y)想求它相对原点的极角也就是从x轴正方向逆时针转到该点的角度手算时我们会觉得这个角度应该能覆盖-pi到pi的整个范围。但如果直接用atan(y/x)你会发现当点在第二、三象限时结果会跑到[-pi/2, pi/2]区间内和实际角度差了pi。这就是atan2存在的意义。Matlab里的atan2(y, x)专门用来解决这个问题它能够根据x和y的正负号自动确定角度所在的象限返回从-pi到pi的完整极角。我在实际写代码时的经验法则是凡是用atan(y/x)的地方除非你非常确定x恒大于0否则一律改成atan2(y, x)。这个习惯省了我无数次肉眼排查角度不对的苦工。反三角函数的另一个坑是定义域。asin和acos的输入必须落在[-1, 1]区间内一旦超出这个范围结果就是复数。比如asin(1.5)在Matlab里不会报错而是返回一个复数结果1.5708 - 0.9624i。很多人在处理实验数据时没注意到个别数据点超出了[-1,1]结果一整个计算结果变成了复数后面所有绘图、比较逻辑全乱了。这个问题的排查方法我会在第五章详细讲。2.3 双曲函数与复数域扩展说完基本三角函数和反三角函数我再说说双曲函数。sinh、cosh、tanh这三个函数看起来名字和三角函数很像但它们是建立在指数函数基础上的sinh(x)等于(e^x - e^(-x))/2cosh(x)等于(e^x e^(-x))/2。它们的图像、性质都和普通三角函数完全不同但Matlab里的调用语法是完全一致的。双曲函数在工程上最常出现在两个地方一个是悬链线的计算——就是两端固定、自然下垂的绳索那条曲线它的形状正好是cosh函数另一个是深度学习中常用的tanh激活函数它的取值范围在[-1, 1]之间梯度特性比sigmoid好所以很多神经网络代码里都离不开tanh。如果你在做这几类工作直接y tanh(z)就完事了不需要自己写指数运算。复数域上的三角函数也是Matlab的一个隐藏优势。大家都知道欧拉公式e^(ix) cos(x) i*sin(x)在Matlab里输入exp(i*pi)会得到-1 0i这在验证公式时很直观。而当你把sin的输入从实数换成复数时Matlab也会自动在复数域上计算。比如sin(1i)的结果是0 1.1752i这个值等于(e - 1/e)/2也就是sinh(1)。这里面的数学很有意思但站在实用角度你只需要知道如果哪天计算结果莫名其妙出现了虚部先看看输入数据里是不是有复数“混入”了。3. 矩阵运算与批量计算的正确姿势3.1 对整个数组“一键”求三角函数Matlab里对矩阵求三角函数语法和对标量求三角函数一模一样。比如我有一个3x3的矩阵A想求每个元素的余弦A [0, pi/4, pi/2; pi/3, pi/6, 1; 2, 3, 4]; B cos(A);这个B就是和A同样大小的3x3矩阵每个位置都是对应元素的余弦值。这里要注意的是所谓“对矩阵求三角函数”其实是逐元素运算和线性代数里的矩阵乘法、矩阵指数完全不是一回事。后者需要写成A * A或者expm(A)而三角函数家族在这里全部是“点运算”直接调用即可。多维数组也一样没问题。rand(2,3,4)生成的三维数组也可以直接传给sin输出还是同样尺寸的三维数组。我自己在图像处理中处理像素矩阵时经常会直接把一个二维灰度矩阵丢进sin或者cos里做变换完全不需要写循环这对于代码简洁性和可读性都是巨大的提升。3.2 性能优化向量化的原则与实用技巧Matlab圈子里流传着一句话“让代码跑得快不是写更好的循环而是不写循环。”这在三角函数运算里体现得淋漓尽致。假设我想算100万个点的正弦值最粗暴的写法是n 1000000; x linspace(0, 2*pi, n); y zeros(1, n); for k 1:n y(k) sin(x(k)); end这个循环在Matlab里跑起来奇慢无比因为Matlab是解释型语言每执行一行都有解释、检查的开销循环语句尤其吃亏。而如果你直接写y sin(x);它内部会调用高度优化的底层库对整套数组进行批量计算速度快了不止一个数量级。在我自己的测试里100万个点的正弦计算循环版本需要大约0.5秒向量化版本只需要0.02秒左右差距是25倍。随着数据量增大这个差距还会进一步拉大。所以在写任何涉及三角函数的代码时我的建议只有一条能向量化就向量化永远不要主动写for循环去逐点求三角函数。矩阵运算、多维数组、线性空间生成linspace、meshgrid这些工具配合起来几乎所有常见的三角函数计算场景都能用一条语句解决。4. 实操案例从波形绘制到信号分析4.1 案例一用Matlab画出正弦波叠加效果纸上谈兵够多了我们来写几个能直接跑的实战案例。第一个案例是做信号处理的人几乎每天都要干的事情——生成并绘制正弦波。fs 1000; % 采样率 1000Hz t 0:1/fs:1; % 1秒时长 f1 5; % 第一个频率 5Hz f2 50; % 第二个频率 50Hz y sin(2*pi*f1*t) 0.5*sin(2*pi*f2*t); % 叠加信号 plot(t, y); xlabel(时间 (秒)); ylabel(幅度); title(5Hz与50Hz正弦波叠加);这里有一个细节值得展开说一下。sin(2*pi*f*t)是信号处理中最标准的正弦波生成公式为什么是2pi×频率×时间因为sin的默认输入是弧度一个完整的周期是2pi弧度而f*t表示的是“振荡了几个周期”。比如5Hz的波在1秒内振荡5个周期总弧度就是5×2*pi。这个公式如果你理解了以后生成任何频率的正弦波都不需要查资料直接推出来就行。我还想强调采样率的概念。fs 1000表示每秒钟采样1000个点也就是相邻两个点的时间间隔是1/1000秒。如果你把采样率设得很低比如fs 20再去画50Hz的正弦波就会看到波形严重失真——这是“采样定理”的经典体现采样率必须大于信号最高频率的两倍否则高频信号会“伪装”成低频信号这种现象叫混叠。我自己在做教学演示时经常用这个例子让学生亲手体会混叠效应比任何说教都直观。4.2 案例二傅里叶级数视角下的方波拟合三角函数不仅是用来生成正弦波的它还能拼出矩形波、锯齿波、三角波这些非正弦波形。这个技巧在电力电子、音频合成、信号分析里都有实际应用。这里我用一个方波拟合的例子来说明。方波可以看作无穷多个奇次谐波正弦波的叠加一个频率为f、幅度为1的方波其傅里叶级数展开为(4/pi) * sum(sin(2*pi*(2k-1)*f*t) / (2k-1), k1,2,...)。在Matlab里我们可以用有限的谐波数来逼近方波t 0:0.001:1; f 1; % 1Hz方波 y zeros(size(t)); N 50; % 用50次谐波去逼近 for k 1:N n 2*k-1; % 只取奇次谐波 y y (4/pi) * sin(2*pi*n*f*t) / n; end plot(t, y);注意这里我用了for循环而且循环次数只有50次——这是合理的用法因为每个谐波需要对整条时间轴计算一次正弦值而谐波次数本身不可能向量化得那么彻底。真正的优化方式是先用矩阵广播做类似n 1:2:99的行向量配合t的列向量生成二维正弦矩阵再按轴求和。但对于50次谐波这种规模for循环的耗时可以忽略不计代码可读性反而更好。这个例子还引出一个非常有用的观察你在拟合结果中会看到方波的边缘有细微的振荡这个现象叫“吉布斯现象”。它不是因为代码写错了而是傅里叶级数的固有特性——有限项近似在间断点附近总会过冲约9%。很多初学者第一次看到这个抖动以为是自己程序的问题到处排查半天最后发现是数学本质提前了解就能省下这个冤枉时间。4.3 符号计算中的三角函数化简Matlab里还有一个被严重低估的三角函数应用场景——符号计算。如果你安装了Symbolic Math Toolbox可以用syms声明符号变量然后让Matlab帮你做三角恒等变换。比如syms x expr cos(x)^2 sin(x)^2; simplify(expr) % 输出 1这个功能在做理论推导、化简表达式时非常实用。我记得以前做控制理论作业时有个系统的传递函数里包含了一堆sin(omega*t)和cos(omega*t)的组合要手工展开并合并成单个正弦/余弦形式相当繁琐。后来我用combine(expr, sincos)这个命令一步就把它化简成了A*sin(omega*t phi)的标准形式连幅度和相位都直接给出表达式极大减轻了作业负担。符号计算中常用的还有rewrite可以把sin/cos改写为tan的半角形式或者用exp指数形式表示。expand则会把sin(xy)拆成sin(x)*cos(y) cos(x)*sin(y)。这些函数本质上做了我们高中背过的那些公式但计算机做得快、不会错你只需要告诉它你要展开、化简还是合并就行。5. 高频踩坑与问题排查实录5.1 浮点误差导致的“不等于零”我在2.1节末尾提到的浮点误差问题在这里展开细说。相信不少人都遇到过这样的困惑明明sin(pi)就是0为什么Matlab算出来的结果是1.2246e-16这个问题的根源在于计算机内部用二进制分数来存储数值而pi是一个无限不循环小数二进制下同样无法精确表示。Matlab实际参与计算的是一个非常接近pi但并非精确等于pi的数这个数的正弦自然也不会是精确的0而是某个极小的值。类似地cos(pi/2)在Matlab里约等于6.1232e-17而不是0。这个误差本身很小通常不影响实际工程。但如果你拿它做判断比如写if sin(pi) 0那就会踩雷。正确的做法是设置一个容差比如result sin(pi); if abs(result) 1e-10 disp(近似等于0); end或者使用round(result, 10)四舍五入到指定小数位数。在我自己的经验里判断浮点数是否相等都用abs(a - b) tol的写法tol取1e-10左右既不会误判也不会因为容差太大掩盖真实差异。这也是数值计算的通用原则永远不要用直接比较浮点数除非你能确保双方都是由整数运算精确产生的。5.2 输入复数时结果为何“不对劲”另外一个非常隐蔽的问题出现在输入数据里“混入”了复数时。Matlab有个特性只要数组里有一个元素是复数整个数组的运算结果通常就会带上虚部。比如你的x向量里某个值是2 1i那sin(x)的结果就会包含复数。如果你没注意到后续取实部、绘图、找最大值等操作得到的结果可能都不符合预期。这个问题的典型场景是反三角函数。前面提到过asin和acos要求输入在[-1, 1]内一旦某个数据点越界结果就变成复数而常系数数据里哪怕只有一个是1.0000001都会导致输出复数化。我处理实验数据时的经验是在调用反三角函数之前先检查数据范围data randn(1, 100) * 1.2; % 模拟可能有越界的数据 if any(abs(data) 1) warning(存在超出[-1,1]的数据点结果可能包含复数); end先预警再决定是裁剪数据还是剔除异常点这样才能保证后续计算结果的纯洁性。这个习惯在信号处理、姿态解算等大量使用反三角函数的场景里尤其重要。5.3 反三角函数边界值与NaN的处理还有一些边界值问题。比如atan2(0, 0)在Matlab里返回0这在数学上是有争议的零向量没有定义方向但Matlab选择了一个不报错的默认值。如果你在做极坐标转换、航向角计算这类工作输入数据里确实可能出现x和y同时为0的点这时返回值0可能会被当作有效数据混入后续统计产生偏差。我这里建议的方法是在调用atan2之前先筛选掉x 0 y 0的点或者之后单独处理。另一个常见情况是三角函数输入为Inf或NaN时。sin(Inf)在Matlab里返回NaN因为正弦函数在无穷远处振荡、没有确定的极限——这个数学上是合理的。但问题是如果输入数据采集过程中出现了掉线、漏采填充成了Inf那整条计算链路都会变成NaN。这在长时段数据处理的代码里很致命因为你往往到最后画图时才发现曲线缺了一大段但已经很难追溯是哪个环节引入的Inf了。我的建议是在数据进入计算管线之前就做一轮清洗data(~isfinite(data)) 0;或者用fillmissing插值补全把Inf和NaN提前处理干净。5.4 角度制与弧度制混用的“薛定谔错误”最后再说一个不是错误但在团队协作中极其容易引发灾难的问题角度制与弧度制混用。我看到过不止一次一个人写代码时用tand(60)算角度另一个人后续接手用cos(pi/6)做验证两边结果差了一个数量级排查一整天最后发现是某个* pi / 180被多写或少写了一处。我的个人习惯是在脚本开头用注释明确标注所有角度相关变量是用角度还是弧度并且命名时直接带上单位后缀。比如theta_deg 45; % 角度制 theta_rad deg2rad(theta_deg); % 转换 x cos(theta_rad); % 后续统一用弧度命名带上_deg和_rad后缀成本极低但效果立竿见影。如果你做的是交互式脚本甚至可以在读取用户输入时显式询问“请输入角度度”然后立刻统一为弧度。这种防御性编程的习惯能帮你省下无数个加班排查单位Bug的夜晚。6. 速成笔记的几点实操心得在我自己过去的项目里三角函数很少单独作为主角出现但它永远是配角中的高频选择波形生成、图像旋转、机器人运动学解算、天线方向图计算、三相电的相位变换……这些领域无一处不用到sin和cos。正因为它是基础中的基础才更值得花半小时把细节摸透。最后分享一个我常用的灵感来源Matlab自带的doc sin文档里每一页底部都有“See Also”区域这其实是一座宝藏。我做信号处理项目时偶然点进atan2的See Also顺藤摸瓜发现了cart2pol和pol2cart两个坐标转换函数后来在极坐标绘图和雷达数据处理中帮了大忙。学习Matlab不一定要啃整本官方文档但多点点See Also、多看看示例代码往往能发现比自己现造轮子更优雅的解法。这个系列的速成笔记我尽量保证每篇都能让读者“打开就能用、用后能记住”。三角函数这篇算是整个系列里数学味道较浓的一篇但写代码的实用性和高中知识其实是两码事——哪怕你已经把三角恒等式忘光了只要理解了弧度制与角度制的区别、记住反三角函数的值域限制再养成向量化和防御性编程的习惯Matlab里绝大多数三角函数场景都不会再拦住你了。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑