MATLAB非均匀网格梯度计算

在matlab中,gradient函数可以很方便的对均匀网格进行梯度计算,但是对于非均匀网格,但是gradient却无法求解非均匀网格的梯度,这一点我之前犯过错误。我之前以为在gradient函数中指定x,y等坐标,其求解的就是非均匀网格梯度了,然而并不是。

于是,今天下午开始写非均匀网格求梯度的函数。

首先,函数的要求为:

1、边界处采用二阶偏心差分

2、内部网格点采用二阶中心差分

3、计算三维矩阵的梯度

明确目标之后,我们首先进行理论推导:

理论推导

1、内部网格点

对a1和a3两点分别进行泰勒展开,公式如下:
a 3 = a 2 + a ˙ 2 Δ x 2 + 1 2 a ¨ 2 Δ x 2 2 + O ( Δ x 2 3 ) 1 ◯ a 1 = a 2 − a ˙ 2 Δ x 1 + 1 2 a ¨ 2 Δ x 1 2 + O ( Δ x 1 3 ) 2 ◯ a_{3}=a_{2}+\dot{a}{2}\Delta x{2}+\frac{1}{2}\ddot{a}{2}\Delta x{2}^{2}+O(\Delta x_{2}^{3})\textcircled{1} \\a_{1}=a_{2}-\dot{a}{2}\Delta x{1}+\frac{1}{2}\ddot{a}{2}\Delta x{1}^{2}+O(\Delta x_{1}^{3})\textcircled{2} a3=a2+a˙2Δx2+21a¨2Δx22+O(Δx23)1◯a1=a2−a˙2Δx1+21a¨2Δx12+O(Δx13)2◯

最终得到

2、边界点

理论部分结束,下面进入代码部分

代码部分

首先,我写了一个1D的函数

matlab 复制代码
function dydx = calc_grad_1D(x,y)
%% 求解一维数组的梯度
%% input1:一维函数坐标-->x
%% input2:一维函数值-->y
dydx = zeros(1,length(x));
for i = 1:length(x)
    if i>1 && i<length(x)
        deltax1 = x(i)-x(i-1);
        deltax2 = x(i+1)-x(i);
        son = (y(i+1)*deltax1^2-y(i-1)*deltax2^2-y(i)*(deltax1^2-deltax2^2));
        mom = (deltax2*deltax1^2+deltax1*deltax2^2);
        dydx(i) = son/mom;
    elseif i==1
        n = (x(3)-x(1))/(x(2)-x(1));
        son = y(i+2)-y(i+1)*n^2-(1-n^2)*y(i);
        mom = (n-n^2)*(x(i+1)-x(i));
        dydx(i)=son/mom;
    elseif i==length(x)
        n = (x(i)-x(i-2))/(x(i)-x(i-1));
        son = y(i-2)-y(i-1)*n^2-(1-n^2)*y(i);
        mom = (n-n^2)*(x(i)-x(i-1));
        dydx(i)=-son/mom;
    end
end
end

接下来验证该函数的准确性

matlab 复制代码
x = [1 2 4 7 10];
y = x.^2;
%%
dydx = calc_grad_1D(x,y);
%%
dydx_ana = 2.*x;
plot(x,dydx_ana,'-*')
hold on
plot(x,dydx,'-o')
xlabel('x');ylabel('dydx')
legend('理论值','数值解')

接下来我们进行3D矩阵的梯度求解,思想是调用上述的1D求解函数。

代码如下:

matlab 复制代码
function [dfdx,dfdy,dfdz] = calc_grad_3D(F,X,Y,Z)
%UNTITLED26 此处提供此函数的摘要
%   此处提供详细说明
nx = size(X,1);ny = size(Y,2);nz = size(Z,3);
dfdx = zeros(nx,ny,nz);dfdy = zeros(nx,ny,nz);dfdz = zeros(nx,ny,nz);
for j = 1:ny
    for k = 1:nz
        dfdx(:,j,k) = calc_grad_1D(X(:,j,k),F(:,j,k));
    end
end
for i = 1:nx
    for k = 1:nz
        dfdy(i,:,k) = calc_grad_1D(Y(i,:,k),F(i,:,k));
    end
end
for i = 1:nx
    for j = 1:ny
        dfdz(i,j,:) = calc_grad_1D(Z(i,j,:),F(i,j,:));
    end
end
end

具体案例是求解函数 F = x 2 + y 2 + z 2 F=x^2+y^2+z^2 F=x2+y2+z2在三个方向的梯度

matlab 复制代码
clc;clear
x = 1:10;y = x;z = x;
[X,Y,Z] = ndgrid(x,y,z);
F = X.^3+Y.^2+Z.^3;
%%
[dFdy,dFdx,dFdz] = gradient(F,Y(1,:,1),X(:,1,1),Z(1,1,:));
%%
[dfdx,dfdy,dfdz] = calc_grad_3D(F,X,Y,Z);
%% 理论解与数值解对比
dfdy_ana = 2.*(Y);
dfdy_ana = reshape(dfdy_ana,1000,1);
dfdy = reshape(dfdy,1000,1);
dFdy = reshape(dFdy,1000,1);
c = abs(dfdy-dfdy_ana);
d = abs(dFdy-dfdy_ana);
plot(c,'-o')
hold on
plot(d,'-o')
%% 绘图设置
axis([0 1000 0 2])
legend('My code','MATLAB gradient')
ylabel('误差')

结果如下:
可以看出,matlab里的gradient函数由于在边界上采用一阶差分,因此存在误差,而我们的函数内部点和边界点都采用二阶精度,因此误差为0。

相关推荐
北冥湖畔的燕雀11 小时前
C++泛型编程(函数模板以及类模板)
开发语言·c++
QX_hao12 小时前
【Go】--map和struct数据类型
开发语言·后端·golang
你好,我叫C小白12 小时前
C语言 循环结构(1)
c语言·开发语言·算法·while·do...while
Evand J14 小时前
【MATLAB例程】基于USBL和DVL的线性回归误差补偿,对USBL和DVL导航数据进行相互补偿,提高定位精度,附代码下载链接
开发语言·matlab·线性回归·水下定位·usbl·dvl
爱喝白开水a15 小时前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
Neverfadeaway15 小时前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
武子康15 小时前
Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
java·开发语言·数据库·sql·mongodb·性能优化·nosql
杰克尼15 小时前
JavaWeb_p165部门管理
java·开发语言·前端
一成码农15 小时前
JavaSE面向对象(下)
java·开发语言
偶尔的鼠标人16 小时前
Avalonia DataGrid 控件的LostFocus事件会多次触发
开发语言·c#