大数跨境
0
0

Matlab代码深度学习模拟Helmholtz教程:硬约束边界条件PINNs物理信息神经网络

Matlab代码深度学习模拟Helmholtz教程:硬约束边界条件PINNs物理信息神经网络 数据驱动与力学
2025-06-24
4


1. 数学背景与原理

1.1 亥姆霍兹方程

亥姆霍兹方程是描述波动现象的重要偏微分方程,一维形式为:

d²u/dx² + k²u = 0

其中:

  • u(x) 是待求解的声压场函数
  • k = 2πf/c₀ 是波数
  • f 是频率 (Hz)
  • c₀ 是介质中的声速 (m/s)

1.2 边界条件

本程序考虑狄利克雷边界条件:

u(0) = 1 Pa    (左边界)
u(1) = -1 Pa   (右边界)

1.3 解析解

对于给定边界条件的一维亥姆霍兹方程,解析解为:

u(x) = cos(kx) - (csc(k) + cot(k))sin(kx)

其中:

  • csc(k) = 1/sin(k) (余割函数)
  • cot(k) = cos(k)/sin(k) (余切函数)

2. 物理信息神经网络(PINNs)方法

2.1 基本思想

PINNs将物理定律(微分方程)作为约束条件嵌入到神经网络的损失函数中,使得网络在学习数据的同时自动满足物理定律。

2.2 试探函数

为了自动满足边界条件,构造试探函数:

G(x) = φ₁(x)·u₀₁ + φ₂(x)·u₀₂ + φₑ(x)·N(x)

其中:

  • φ₁(x) = 1-x (左边界形状函数)
  • φ₂(x) = x (右边界形状函数)
  • φₑ(x) = φ₁(x)·φ₂(x) = x(1-x) (等效形状函数)
  • u₀₁ = 1, u₀₂ = -1 (边界条件值)
  • N(x) 是神经网络输出

2.3 损失函数

损失函数基于微分方程残差:

Loss = ||d²G/dx² + k²G||²

2.4 硬约束边界条件

根据代码分析,MATLAB程序使用了一种非常巧妙的试探解方法(Trial Solution Method)来实现边界条件,这是PINNs中的一种先进技术。下面详细解释这种实现方式:

1. 边界条件定义

x0BC1 = 0;                      % 左边界 (m)
x0BC2 = 1;                      % 右边界 (m)

u0BC1 = 1;                      % 左边界值 (Pa)
u0BC2 = -1;                     % 右边界值 (Pa)

2. 形状函数构造

在 modelLoss 函数中:

phi1 = 1-X;
phi2 = X;

phi_eqv = phi1.*phi2;

3. 试探解构造

% 试探神经网络
G = phi1*U0(1)+phi2*U0(2)+phi_eqv.*U;

边界条件满足机制

这种构造方式的巧妙之处在于:

在左边界 (x=0) 时:

  • phi1 = 1-0 = 1
  • phi2 = 0
  • phi_eqv = 1×0 = 0
  • 因此:G = 1×U0(1) + 0×U0(2) + 0×U = U0(1) = 1

在右边界 (x=1) 时:

  • phi1 = 1-1 = 0
  • phi2 = 1
  • phi_eqv = 0×1 = 0
  • 因此:G = 0×U0(1) + 1×U0(2) + 0×U = U0(2) = -1

方法优势

  1. 自动满足边界条件:无论神经网络输出什么值,试探解在边界处都严格等于指定的边界值

  2. 无需惩罚项:不需要在损失函数中添加边界条件的惩罚项,避免了权重平衡问题

  3. 数学保证:边界条件的满足是通过数学构造保证的,而不是通过优化近似获得的

  4. 计算效率:减少了损失函数的复杂性,提高了训练效率

这种试探解方法是现代PINNs中处理边界条件的一种优雅且有效的方式,特别适用于狄利克雷边界条件(给定边界值)的问题。

3. 代码详细解读

3.1 参数设置和数据生成

% 整合的1维亥姆霍兹方程求解程序 - 使用物理信息神经网络(PINNs)
% 包含所有必要的函数

clc;
clear all;

%% 生成训练数据
freq = 2000;                     % 频率 (Hz)
c0 = 340;                       % 空气中声速 (m/s)
k = 2*pi*freq/c0;               % 波数 (1/m)

解读:

  • freq = 2000:设置声波频率为2000Hz
  • c0 = 340:空气中标准声速
  • k = 2*pi*freq/c0:根据色散关系计算波数
x0BC1 = 0;                      % 左边界 (m)
x0BC2 = 1;                      % 右边界 (m)

u0BC1 = 1;                      % 左边界值 (Pa)
u0BC2 = -1;                     % 右边界值 (Pa)

X0 = [x0BC1 x0BC2];     
U0 = [u0BC1 u0BC2];

解读:

  • 定义求解区域:x ∈ [0,1]
  • 设置边界条件:u(0)=1, u(1)=-1
  • 将边界位置和值存储为数组
numInternalCollocationPoints = 14000;

pointSet = sobolset(1);                   % 高度均匀填充空间的二进制数字序列
points = net(pointSet,numInternalCollocationPoints);    % 生成准随机点集

dataX = points;         % 在0和1之间创建随机x数据点

解读:

  • numInternalCollocationPoints = 14000:设置配点法的内部点数量
  • sobolset(1):创建一维Sobol序列生成器,产生高度均匀分布的准随机数
  • net(pointSet,14000):生成14000个在[0,1]区间均匀分布的配点
  • 这些配点用于在物理方程约束下训练神经网络

3.2 神经网络架构定义

%% 定义深度学习模型
numLayers = 5;
numNeurons = 90;

parameters = buildNet(numLayers,numNeurons);

解读:

  • 创建5层神经网络,每层90个神经元
  • 调用buildNet函数构建网络参数

buildNet函数详解:

function parameters = buildNet(numLayers,numNeurons)
% 构建神经网络参数

parameters = struct;

% 输入层
sz = [numNeurons 1];
parameters.fc1_Weights = initializeHe(sz,1,"double");
parameters.fc1_Bias = initializeZeros([numNeurons 1],"double");

解读:

  • 输入层:1个输入(x坐标) → 90个神经元
  • 使用He初始化方法初始化权重
  • 偏置初始化为零
% 隐藏层
for layerNumber=2:numLayers-1
    name = "fc"+layerNumber;

    sz = [numNeurons numNeurons];
    numIn = numNeurons;
    parameters.(name + "_Weights") = initializeHe(sz,numIn,"double");
    parameters.(name + "_Bias") = initializeZeros([numNeurons 1],"double");
end

解读:

  • 隐藏层:90个神经元 → 90个神经元
  • 循环创建第2到第4层(共3个隐藏层)
  • 每层都使用He初始化
% 输出层
sz = [1 numNeurons];
numIn = numNeurons;
parameters.("fc" + numLayers + "_Weights") = initializeHe(sz,numIn,"double");
parameters.("fc" + numLayers + "_Bias") = initializeZeros([1 1],"double");

解读:

  • 输出层:90个神经元 → 1个输出
  • 网络最终输出一个标量值N(x)

3.3 前向传播模型

function U = model(parameters,X)
% 神经网络模型前向传播

numLayers = numel(fieldnames(parameters))/2;

% 第一个全连接操作
weights = parameters.fc1_Weights;
bias = parameters.fc1_Bias;
U = fullyconnect(X,weights,bias);

% 对剩余层进行sin激活和全连接操作
fori=2:numLayers
    name = "fc" + i;

    U = sin(U);

    weights = parameters.(name + "_Weights");
    bias = parameters.(name + "_Bias");
    U = fullyconnect(U, weights, bias);
end

解读:

  • numLayers = numel(fieldnames(parameters))/2:计算网络层数(每层有权重和偏置两个参数)
  • 第一层:线性变换但不激活
  • 后续层:先sin激活,再线性变换
  • 重要:使用sin激活函数有利于学习周期性解

3.4 损失函数和梯度计算

function [loss,gradients] = modelLoss(parameters,X,U0,freq,c0)
% 计算模型损失和梯度
% 使用初始条件进行预测
k = 2*pi*freq/c0;
U = model(parameters,X);
phi1 = 1-X;
phi2 = X;

phi_eqv = phi1.*phi2;

% 试探神经网络
G = phi1*U0(1)+phi2*U0(2)+phi_eqv.*U;

解读:

  • U = model(parameters,X):神经网络输出N(x)
  • phi1 = 1-X:左边界形状函数
  • phi2 = X:右边界形状函数
  • phi_eqv = phi1.*phi2:等效形状函数 = x(1-x)
  • G = ...:构造试探函数,自动满足边界条件
% 计算对X的一阶导数
Gx = dlgradient(sum(G,'all'),X,'EnableHigherDerivatives',true);

% 计算对X的二阶导数
Gxx = dlgradient(sum(Gx,'all'),X,'EnableHigherDerivatives',true);

% 计算损失
f = Gxx+k^2*G;
zeroTarget = zeros(size(f),"like",f);
loss = l2loss(f, zeroTarget);

% 计算相对于可学习参数的梯度
gradients = dlgradient(loss,parameters);

解读:

  • dlgradient:自动微分计算梯度
  • EnableHigherDerivatives=true:允许计算高阶导数
  • Gx:dG/dx (一阶导数)
  • Gxx:d²G/dx² (二阶导数)
  • f = Gxx+k^2*G:亥姆霍兹方程左边的表达式
  • loss = l2loss(f, zeroTarget):L2损失,要求f≈0
  • gradients:损失函数对网络参数的梯度

3.5 优化设置和训练

%% 指定优化选项
options = optimoptions("fmincon", ...
    HessianApproximation="lbfgs", ...
    MaxIterations=14000, ...
    MaxFunctionEvaluations=14000, ...
    OptimalityTolerance=1e-3, ...
    SpecifyObjectiveGradient=true, ...
    Display='iter');

解读:

  • 使用fmincon进行约束优化
  • lbfgs:有限内存BFGS算法,适合大规模优化
  • MaxIterations=14000:最大迭代次数
  • SpecifyObjectiveGradient=true:使用解析梯度加速收敛
%% 训练网络
start = tic;

[parametersV,parameterNames,parameterSizes] = parameterStructToVector(parameters);
parametersV = extractdata(parametersV);

%% 将变量转换为深度学习变量
X = dlarray(dataX,"BC");
X0 = dlarray(X0,"CB");
U0 = dlarray(U0,"CB");

objFun = @(parameters) objectiveFunction(parameters,X,U0,parameterNames,parameterSizes,freq,c0);

parametersV = fmincon(objFun,parametersV,[],[],[],[],[],[],[],options);

parameters = parameterVectorToStruct(parametersV,parameterNames,parameterSizes);

toc(start)

解读:

  • parameterStructToVector:将结构体参数转换为向量形式
  • dlarray:创建深度学习数组,支持自动微分
  • "BC""CB":指定数组维度标签(B=batch, C=channel)
  • objFun:创建目标函数句柄
  • fmincon:执行优化求解
  • 训练完成后将参数转换回结构体形式

3.6 模型评估和可视化

%% 评估模型精度
numPredictions = 500;
XTest = linspace(x0BC1,x0BC2,numPredictions);

dlXTest = dlarray(XTest,'CB');
U = model(parameters,dlXTest);

% 空间函数
phi1_test = 1-dlXTest;
phi2_test = dlXTest;
phi_eqv_test = phi1_test.*phi2_test;

% 预测解
dlUPred = phi1_test*U0(1)+phi2_test*U0(2)+phi_eqv_test.*U;

% 真实解
UTest = solve1DWaveEqn(XTest,k);

% 计算误差
err = norm(extractdata(dlUPred) - UTest) / norm(UTest);

解读:

  • 在500个测试点上评估模型
  • 使用训练好的参数计算预测解
  • 调用解析解函数计算真实解
  • 计算相对L2误差:||u_pred - u_true||/||u_true||
f1 = figure;
% 绘制预测解
plot(XTest,extractdata(dlUPred),'-','LineWidth',2);

% 绘制真实解
hold on
plot(XTest, UTest, '--','LineWidth',2)
hold off

xlabel('x (m)','FontSize',14,'FontWeight','bold')
ylabel('声压 (Pa)','FontSize',14,'FontWeight','bold')
title("频率 = " + freq + " Hz;" + " 误差 = " + gather(err));

legend('预测解','真实解')

解读:

  • 可视化预测解和真实解的对比
  • 显示频率和相对误差信息

3.7 解析解函数

function U = solve1DWaveEqn(X,k)
% 1维波动方程的解析解

% 初始化解
U = zeros(size(X));

% 循环遍历x值
for i = 1:numel(X)
    x = X(i);
    U(i) = cos(k*x)-(csc(k)+cot(k))*sin(k*x);
end

解读:

  • 实现一维亥姆霍兹方程的解析解
  • cos(k*x):余弦项
  • csc(k)+cot(k):根据边界条件确定的系数
  • sin(k*x):正弦项

4. 算法优势与特点

4.1 PINNs方法优势

  1. 无网格方法:不需要传统有限元的网格划分
  2. 自动满足边界条件:通过试探函数设计
  3. 高精度:深度学习的强大拟合能力
  4. 可微分:便于梯度计算和优化

4.2 技术要点

  1. 试探函数设计:关键是构造满足边界条件的函数形式
  2. 激活函数选择:sin函数适合周期性问题
  3. 自动微分:MATLAB深度学习工具箱提供高效梯度计算
  4. 优化算法:L-BFGS适合大规模无约束优化

5. 扩展应用

这个框架可以扩展到:

  • 二维/三维亥姆霍兹方程
  • 其他类型边界条件
  • 非均匀介质问题
  • 时域波动方程

6. 运行结果分析

程序运行后会显示:

  • 训练过程的优化迭代信息
  • 最终的相对误差
  • 预测解与解析解的对比图

测试结果的相对误差在1e-4量级,说明硬约束边界PINNs方法能够有效求解亥姆霍兹方程。

7. 总结

本教程展示了如何使用物理信息神经网络求解一维亥姆霍兹方程。通过将物理定律嵌入损失函数,设计硬约束函数,使得PINNs能够自动满足边界条件,避免了PINNs中的复杂的多目标优化问题,这种思想为求解偏微分方程提供了一种新的高效稳定的计算途径。

【完整教程+代码+结果绘图,留言:Hel-code(有偿),往期代码教程留言】

往期内容推荐
《Science》正刊:物理信息深度学习||一文概述物理信息深度学习,理论基础+代码实践+研究前沿!
CFD基础:一文概述NS方程建模与推导||NS方程建模、数值离散、代数求解、后处理可视化
物理信息深度学习与数据驱动研究,现在到底有多火爆?
【PINNs详细代码教程】物理信息神经网络求解Navier-Stokes方程反问题:稀疏数据重构和系统参数辨识,误差1e-3量级
【PINNs代码教程】物理信息深度神经网络求解偏微分方程:Allen-Cahn方程算例,高精度误差2e-4量级
【PINNs新手代码教程】物理信息深度神经网络求解微分方程:Burgers方程算例,误差精度5e-4量级
【NS方程代码教程】基于物理信息神经网络(PINNs)求解二维Navier-Stokes方程正问题:圆柱绕流
【PINNs顶盖驱动流代码教程】物理信息神经网络求解Navier-Stokes方程顶盖驱动流问题
代码教程:使用物理信息神经网络(PINNs)求解二维Helmholtz(亥姆霍兹)方程
【物理深度学习与计算力学代码教程】物理信息神经网络求解欧拉-伯努利梁方程,精度1e-4量级
PINNs模拟孤立波代码教程||物理信息神经网络求解量子场论基本方程Klein-Gordon
物理信息深度学习模拟Euler-Bernoulli梁代码教程
多尺度物理信息深度神经网络求解高频PDE,精度1e-3量级
Klein-Gordon方程的物理信息神经网络(PINNs)求解详细教程
Schrödinger equation代码教程:物理信息深度学习求解非线性薛定谔方程代码
二维方腔驱动流Lid-driven Cavity Flow数值仿真python代码教程


【声明】内容源于网络
0
0
数据驱动与力学
本公众号主要用于分享数据驱动,人工智能,物理信息深度学习与力学交叉研究前沿热点,包括:前沿文献,开源代码,算法实现。
内容 28
粉丝 0
数据驱动与力学 本公众号主要用于分享数据驱动,人工智能,物理信息深度学习与力学交叉研究前沿热点,包括:前沿文献,开源代码,算法实现。
总阅读80
粉丝0
内容28