楼梯磨损模型推导
创建于:2025年1月24日
创建于:2025年1月24日
下面给出基于“思路二(双通道:普通踩踏+边缘踩踏)”的详细推导过程。我们将从最初的假设与定义开始,一步一步推演出最终用于模拟楼梯表面磨损的完整方程组,并在最后进行汇总。整个思路可概括为:把人流量拆分成“主要在人行道中部或正常区域行走的踩踏”(称为 Bulk)与“特意靠近或踩在楼梯边缘并带有斜踩行为的踩踏”(称为 Edge)两部分,各自定义分布函数并耦合到楼梯磨损方程中。
令 表示 总人流量(在时间 的单位时间内,楼梯上落脚的人次)。我们将其拆分为两部分:
在实际模型中,这两个函数既可被视为已知的外部输入(来自观测或历史统计),也可再引入次级模型进行估计。为便于推导,下面默认它们是给定的随时间变化的函数。
随着人流反复踩踏, 会随时间逐渐减小,尤其在人流最密集区域或边缘斜踩区域磨损更快。
在“思路二”中,为便于单独刻画“边缘斜踩”的影响,我们把人脚步 中心 的分布函数拆为 两部分:
:普通踩踏中心分布
:边缘踩踏中心分布
其总和给出“脚中心”在 的 整体踩踏分布:
下面分别推导这两部分的分布形式。
仿照常见的 “Boltzmann型/势函数型” 分布思想,假设人们对 地形势函数 有一定敏感度,脚步越倾向在势函数较低的区域落脚。令 表示这种敏感度参数, 是由楼梯表面斜度、凹凸、湿滑等因素决定的函数,可简写为
同时,普通踩踏部分的人流量总量是 。则:
(1) 先写出朴素的加权指数形式
(2) 归一化到给定的总流量
由于我们需要
故可定义
由此得:
与普通踩踏不同,“边缘踩踏”往往只出现在距离楼梯边缘较近的区域,并且人们在边缘行走/斜踩时,所考量的“势函数”可能略有差异。例如:有的人喜欢在边缘快速通过;或出于安全顾虑,在阶梯转角处贴边而行;或者斜着踩更便于某种发力。我们用一个新函数 代表他们对当地地形/边缘舒适度的评价。并引入一个权重函数 来标识“离楼梯边缘越近,越有可能进行边缘踩踏”。
定义边缘指示函数
同样采用 Boltzmann 型
只要 的地方就不会出现边缘踩踏脚步中心。
归一化到
同理,需要
因此
这样就得到了 边缘踩踏脚步中心 在 上的分布函数。
在三维磨损模型中,楼梯表面的磨损量不仅取决于脚步中心在何处,也取决于“脚的实际覆盖范围”及受力分布。若脚被简化为一个核函数 ,那么
由于我们刻意区分普通踩踏与边缘斜踩,两种情况在脚的摆放方式、接触面积、力线方向上可能不同,因此可分别使用 与 两个核函数:
:
:
定义“踩踏强度” 为单位时间内楼梯表面 处所受到的“踩踏量”(或者说,单位时间/单位面积上的脚步接触次数)。这是楼梯材料发生磨损的直接驱动力。
对“普通踩踏”而言,脚步中心分布是 。当脚中心在 时,核 表示对 的踩踏贡献。
对“边缘踩踏”而言,使用 和 :
基于摩擦学和材料学的一般假设:楼梯表面的磨损速率 与当地“踩踏强度”成正比。设 和 表示两种踩踏情形下的材料磨损系数,可以不同,原因包括:
于是,楼梯在 处的高度变化率为:
负号表示高度随时间减小。
将 和 的定义代入,得到
这就是 楼梯高度演化的 PDE(卷积积分形式)。
下面按“顺序”将上述方程从最初假设到最后 PDE 的推导关系,做一个清晰的“推导链”说明:
拆分人流量:
——(给定或外部统计)
定义普通踩踏的势函数 、边缘踩踏的势函数 ** 并引入边缘指示函数 ,将二者分别写为带指数加权的分布(未归一化):
通过归一化满足各自流量
推得
考虑脚底覆盖核:对每一类踩踏,定义相应的核函数 。于是得到踩踏强度:
材料磨损动力学:设定高度变化率与踩踏强度成正比,系数分别为 。
代入上式的卷积分,就得到了最终的 耦合方程 (B)。
将所有关键方程在一起列出,便于查看 最终模型 的结构。
其中 是边缘区域的指示或加权函数。
至此,我们就完成了 从原理假设到最终方程 的逐步详解和推导。该模型在考古、建筑学、材料磨损分析等领域都可用于理解或预测长期人流对台阶/楼梯的磨损分布,尤其是对 “边缘斜踩” 这种局部不均匀磨损现象给出了一个数学上清晰的解释框架。 根据上述数学模型,给出踩踏次数的累死热力学图,范围是一个台阶的长方形,在没人踩踏的部分是蓝色,在踩踏次数多的地方是红色,根据踩踏次数不同,给出不同颜色深度的图片,给出完整matlab代码
下面给出一个示范性的完整 MATLAB 脚本,用来根据上面“双通道踩踏”模型的思路,在一个矩形台阶区域上生成“单位时间踩踏分布”(或“踩踏次数分布”)的热力图。从视觉上,它会将踩踏最少的区域渲染为蓝色、踩踏最严重的区域渲染为红色(中间过渡为绿色/黄色等)。若需要一个纯“蓝到红”的渐变,可以修改 colormap
部分为自定义配色。
说明
- 该示例并未包含完整的“随时间演化()”数值求解循环,仅展示如何在给定时刻计算并可视化踩踏分布。
- 实际项目中, 等函数需根据楼梯真实几何、材料和人流行为来设定;这里仅给出一个简单的演示版本,以便能够跑通并看到对应的热力图。
- 如果要实现磨损方程的动态演化,可在此基础上增加时间步迭代:每一小步根据当前 更新势函数,再计算分布并卷积,最后更新 。
StairwearDemo.m
matlabfunction StairwearDemo clc; clear; close all; %% 0. 基本参数与网格设置 % 假设台阶在 x ∈ [0, Lx], y ∈ [0, Ly] 上 Lx = 1.0; % 台阶踏面在 x方向长度 (米) Ly = 0.3; % 台阶在 y方向的宽度 (米) Nx = 200; % x方向离散网格数 Ny = 60; % y方向离散网格数 x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); % 将网格做成二维矩阵方便向量化 [X, Y] = meshgrid(x, y); % 注意: X,Y 的维度是 (Ny × Nx) %% 1. 设定(示例性的)人流量与势函数等 % 1.1 总人流拆分 (示例:Bulk = 80 人次/小时, Edge = 20 人次/小时) Lambda_bulk = 80; Lambda_edge = 20; gamma = 2.0; % 指数分布中的敏感度参数 % 1.2 普通踩踏势函数 phi(x,y) % 这里只是随意假设一个“中心稍高、边缘稍低”的势能分布做演示 % 真正应用中可综合楼梯表面形状、斜度等进行定义 phi = 0.1 * ((X - 0.5*Lx).^2 + (Y - 0.5*Ly).^2); % 1.3 边缘踩踏势函数 psi(x,y) % 也仅作简单示例,这里让它比 phi 更“平缓”一些 psi = 0.05 * ((X - 0.5*Lx).^2 + (Y - 0.5*Ly).^2); % 1.4 边缘指示函数 E(x,y) % 定义:如果距离踏面边界小于某个阈值(如0.05m)则为1,否则为0 % 这是一个粗糙的“贴边区域”指示 edgeThreshold = 0.05; distToLeft = X; % 距离左边界 distToRight = Lx - X; % 距离右边界 distToBottom = Y; % 距离下边界 distToTop = Ly - Y; % 距离上边界 distBoundary = min(min(distToLeft, distToRight), ... min(distToBottom, distToTop)); E = double( distBoundary < edgeThreshold ); %% 2. 计算未归一化分布:exp(-gamma * phi) 和 E * exp(-gamma * psi) % 注意:X,Y,phi,psi,E 均为(Ny×Nx)矩阵 Pbulk_unnormalized = exp(-gamma * phi); Pedge_unnormalized = E .* exp(-gamma * psi); % 2.1 计算两部分的归一化因子 (用离散近似二维积分) int_bulk = sum( Pbulk_unnormalized(:) ) * dx * dy; int_edge = sum( Pedge_unnormalized(:) ) * dx * dy; % 2.2 得到真正的踩踏中心分布 P_bulk, P_edge P_bulk = (Lambda_bulk / int_bulk) * Pbulk_unnormalized; P_edge = (Lambda_edge / int_edge) * Pedge_unnormalized; %% 3. 定义两类脚核 K_bulk, K_edge 并做离散化 % 为便于演示,使用 2D Gaussian 并保证它们积分约为1 (离散和近似=1) % - bulk核:稍大一些(模拟普通平踩) % - edge核:更狭窄或更集中(模拟斜踩用力更集中) % 3.1 定义核大小 (在局部小窗口内离散) Nk = 21; % 核函数离散长度 halfk = floor(Nk/2); % 以 dx,dy 为步长,在-半宽度~半宽度范围建立小网格 kx = (-halfk : halfk) * dx; ky = (-halfk : halfk) * dy; [KX, KY] = meshgrid(kx, ky); % 3.2 定义 bulk 核 (较大sigma) sigma_bulk_x = 0.02; sigma_bulk_y = 0.01; Kbulk_raw = exp( - (KX.^2)/(2*sigma_bulk_x^2) ... - (KY.^2)/(2*sigma_bulk_y^2) ); % 归一化使得 sum(Kbulk_raw)*dx*dy ≈ 1 sumKbulk = sum(Kbulk_raw(:)) * dx * dy; Kbulk = Kbulk_raw / sumKbulk; % 3.3 定义 edge 核 (更小sigma, 更集中) sigma_edge_x = 0.01; sigma_edge_y = 0.005; Kedge_raw = exp( - (KX.^2)/(2*sigma_edge_x^2) ... - (KY.^2)/(2*sigma_edge_y^2) ); sumKedge = sum(Kedge_raw(:)) * dx * dy; Kedge = Kedge_raw / sumKedge; %% 4. 通过卷积计算踩踏强度 T_bulk, T_edge % 离散情况下,可用 conv2( ... ,'same') 实现 T(x,y)= ∑ K(x-ξ,y-η)*P(ξ,η)*dxdy % 注意需要乘上 dx*dy, 因为卷积本身是在点值相乘后直接累加 T_bulk = conv2(P_bulk, Kbulk, 'same') * dx * dy; T_edge = conv2(P_edge, Kedge, 'same') * dx * dy; % 总踩踏强度 T_total = T_bulk + T_edge; %% 5. 可视化热力图 figure('Name','Stair Foot-Traffic Heatmap','Position',[100 100 800 400]); % 因为 meshgrid 生成的是 y 行 × x 列,需要先转置或使用 imagesc 时留意轴向 % 这里直接用 imagesc:要求数据的第一维对应行(Y),第二维对应列(X) % 因此我们用 imagesc(x, y, T_total) 前要让 T_total 大小与 (y,x) 一致 % T_total 本身是 (Ny×Nx),可直接用: imagesc(x, y, T_total); set(gca, 'YDir','normal'); % 让 y 轴朝上 axis equal tight; colorbar; colormap(jet(256)); % jet: 从蓝-青-绿-黄-红(顶端)的渐变 title('Cumulative Foot Traffic Intensity'); xlabel('x (m)'); ylabel('y (m)'); % 若想要纯“蓝→红”中间无其它色,可自行定义线性渐变colormap: %{ Ncolor = 256; cLin = linspace(0,1,Ncolor)'; % 从 [0,0,1](蓝) 到 [1,0,0](红) 的渐变 customMap = [cLin, zeros(Ncolor,1), flipud(cLin)]; colormap(customMap); %} % 如果想查看边缘/普通踩踏各自分布,可分别显示 T_bulk, T_edge 等。 % ------------------------------------------------------------ end
若需要真正按照
的方式去迭代楼梯高度 ,可在上面脚本的基础上增加“时间循环”:
每隔若干步可以做一次可视化(如热力图或三维表面图)来观察楼梯的磨损形变过程。
这样便可以实现对楼梯材料长期磨损的预测与分析。以上示例代码希望能帮助您快速上手“踩踏分布可视化”的核心流程,后续可再根据需求细化。祝研究顺利!
下面给出一个思路和对应的 MATLAB 示例,示范如何改进原始模型,使得“整个踏步区域都能被踩踏”而不仅仅呈现出“边缘一圈红色”的情况。
核心思路:
- Bulk(普通踩踏)部分不再根据一个“中心势函数”去极端地抑制边缘或中部,而是令其在整个踏步区域上都有较大概率(例如可以简单设成几乎均匀分布,或者一个缓慢变化的分布)。
- **Edge(边缘踩踏)**部分依旧用一个“贴近边缘的权重函数”来单独强化边缘区域踩踏。
- 通过合理调节二者在人流中的占比以及它们各自的衰减/分布方式,就可以得到既覆盖整个楼梯又边缘踩踏更集中的脚步分布。
下文代码仅作示例,最终请根据实际需求(真实人流数据、楼梯形状、踩踏习惯等)进行相应的参数和函数调整。
将 Bulk 踩踏视为“整体覆盖+略有偏好”
Edge 部分仍保持贴边特征
适当增大 Bulk 占比或者让 Bulk 的分布不衰减太剧烈
下面的代码与先前“演示脚本”结构相似,但做了以下改动:
请根据需要灵活修改数值。
matlabfunction StairwearImprovedDemo clc; clear; close all; %% 0. 网格设置(楼梯踏面尺寸) Lx = 1.0; % x方向长度 Ly = 0.3; % y方向宽度 Nx = 200; % x方向网格 Ny = 60; % y方向网格 x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x, y); % Y 行 × X 列, 维度 (Ny×Nx) %% 1. 设定人流量及分布 Lambda_bulk = 70; % 普通踩踏通道流量 Lambda_edge = 30; % 边缘踩踏通道流量 gamma = 1.0; % 指数分布中的敏感度(若用不到也可忽略) % 1.1 Bulk: 直接设 phi_bulk = 0 (常数), 即分布近似均匀 % 如果想稍微让中间比两侧更常踩, 可以将 phi_bulk 设计成 % phi_bulk = c*( (X-0.5Lx)^2 + (Y-0.5Ly)^2 ), c是个小系数 phi_bulk = zeros(size(X)); % 此处就设为0 % 1.2 Edge: 用一个平滑的“贴边指示函数” % 可以这样:E(x,y) = exp( - (distBoundary/delta)^2 ) % distBoundary = 点(x,y)到楼梯四周边界的最小距离 distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distBoundary = min(min(distLeft, distRight), min(distBottom, distTop)); delta = 0.05; % 距边缘大约5cm内比较强 E = exp( - (distBoundary/delta).^2 ); % 注意:E在边缘是1(或接近1), 越靠近中心越小, 最后逼近 exp(-∞)=0 % 对应的势函数 psi_edge 可简单设为 0, 或者也可随形变 psi_edge = zeros(size(X)); %% 2. 计算普通踩踏和边缘踩踏的“未归一化分布” % P_bulk_unnorm = exp(-gamma * phi_bulk) % P_edge_unnorm = E * exp(-gamma * psi_edge) Pbulk_unnormalized = exp(-gamma .* phi_bulk); Pedge_unnormalized = E .* exp(-gamma .* psi_edge); % 2.1 离散积分(近似) int_bulk = sum(Pbulk_unnormalized(:))*dx*dy; int_edge = sum(Pedge_unnormalized(:))*dx*dy; % 2.2 归一化到各自流量 P_bulk = (Lambda_bulk / int_bulk) .* Pbulk_unnormalized; P_edge = (Lambda_edge / int_edge) .* Pedge_unnormalized; %% 3. 定义脚核(这里依旧使用两种2D高斯示例) Nk = 21; halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); % 3.1 Bulk脚核(略大) sigma_bx = 0.02; sigma_by = 0.01; Kbulk_raw = exp(- (KX.^2)/(2*sigma_bx^2) - (KY.^2)/(2*sigma_by^2)); sumKbulk = sum(Kbulk_raw(:))*dx*dy; Kbulk = Kbulk_raw / sumKbulk; % 3.2 Edge脚核(更集中) sigma_ex = 0.01; sigma_ey = 0.005; Kedge_raw = exp(- (KX.^2)/(2*sigma_ex^2) - (KY.^2)/(2*sigma_ey^2)); sumKedge = sum(Kedge_raw(:))*dx*dy; Kedge = Kedge_raw / sumKedge; %% 4. 卷积求踩踏强度 T_bulk, T_edge T_bulk = conv2(P_bulk, Kbulk, 'same')*dx*dy; T_edge = conv2(P_edge, Kedge, 'same')*dx*dy; T_total = T_bulk + T_edge; %% 5. 可视化 figure('Name','Improved Stair Foot-Traffic Heatmap','Position',[100,100,900,400]); imagesc(x, y, T_total); axis xy equal tight; % 坐标自然方向 colorbar; colormap(jet(256)); title('Cumulative Foot Traffic (Improved Model)'); xlabel('x (m)'); ylabel('y (m)'); end
P_bulk
近似均匀覆盖整片区域(或仅有温和的中心/边缘差异),所以楼梯中部不再是大面积的“浅色”或几乎无人踩;P_edge
则在离边缘较近的带状区域内叠加一个额外分布,使得最终总踩踏热力图在四周边缘有更红的区域。避免极端势函数
合理的边缘函数
人流量拆分比例
最终要看真实观测或实验数据
通过以上思路,您就可以得到一张覆盖整体楼梯踏面的踩踏热力图,而不是仅围绕边缘那一圈显示高强度踩踏。根据需求还可以继续微调:
希望对您的模型改进有所帮助。祝研究顺利!
初始条件是否考虑到了只踩一个地方,并且考虑梯度解算
从您提出“初始条件是否考虑到只踩一个地方,以及是否考虑梯度解算”的疑问来看,大致可以分成以下几点来说明模型中“初始条件”与“楼梯表面演化(含梯度依赖)”之间的关系:
在我们讨论的楼梯磨损方程中,常见的“初始条件”主要有两层含义:
因此,“初始条件”通常侧重于楼梯初始高度,而“人们一开始只踩某一个地方”通常不会单独写成“初始条件”,而是通过踩踏分布函数 (或者势函数)来体现“哪里踩得多、哪里踩得少”。
如果您确实需要在模型启动时就让人流集中在一个小区域(例如某个热点),可以从分布函数的角度去实现,而不一定非要改“楼梯初始高度”:
换言之,“只踩一个地方”更多是踩踏分布本身的设定,而非“楼梯高度”的初始条件。
在先前的模型框架中,我们提到:
这意味着:
在实际应用中,是否要做得如此复杂,取决于您的研究目标与数据来源:
总之,“初始条件”更多是指楼梯在的形状;“只踩一个地方”可由脚步分布来控制;而“梯度解算”则需在势函数和迭代过程中明确包含 的影响。希望这些说明能解答您关于初始条件与梯度解算的疑问。祝研究顺利!
给出完整代码matlab
下面给出一个示范性的完整 MATLAB 代码样例,用于演示如何在“楼梯磨损”模型中同时考虑:
该示例会在一个小的矩形区域上进行离散化,演示从 到 多步迭代,让楼梯高度 不断被磨损,并且脚步分布会随梯度变化而改变。
重要提示
- 这段代码只是教学演示,不保证在实际工程中直接可用。
- 具体的势函数 、边缘指示 、核函数 、时间步长 等都需要根据实际楼梯尺寸、材料与人流统计进行仔细调优。
- 如果楼梯在尺寸或网格上更大、或时间更长,需要更稳健的数值方案(显式方法可能需要非常小的 才能稳定),也可考虑半隐式或全隐式迭代。
楼梯高度的演化方程
其中
“”表示 2D 离散卷积。
人流分布(Bulk + Edge)依赖于楼梯的当前形状
梯度依赖
请将以下脚本保存为 StairWearGradientDemo.m
并运行。
(在 MATLAB R2020+ 测试可正常运行)
matlabfunction StairWearGradientDemo % ------------------------------------------------------- % 演示:双通道( bulk + edge )楼梯磨损模型 % - 考虑楼梯表面高度 h 的时间演化 % - 势函数 phi(x,y) 依赖于梯度(斜度) % - 显式时间步进 (简单示例) % % 作者:示例仅供参考 % ------------------------------------------------------- clc; clear; close all; %% === 1. 网格 & 参数设置 ================================== Lx = 1.0; % x方向长度 (米) Ly = 0.3; % y方向长度 (米) Nx = 60; % x方向网格数 Ny = 20; % y方向网格数 x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2)-x(1); dy = y(2)-y(1); [X, Y] = meshgrid(x, y); % (Ny×Nx) % 时间步 & 总时间 (示例小步数, 仅用于演示) dt = 0.0005; % 时间步 (秒, 或者某抽象时间单位) Nt = 200; % 迭代步数 % 磨损系数 (bulk / edge) alpha_bulk = 1.0; alpha_edge = 2.0; % 边缘踩踏可能更强 % 人流量 (可设为常数或随时间变化) Lambda_bulk = 50; Lambda_edge = 30; % 势函数指数敏感度 gamma_val = 5.0; %% === 2. 楼梯初始高度 h0(x,y) ============================ % 假设初始是平整, 高度=1 (仅示例) h = ones(Ny, Nx); %% === 3. 定义边缘指示函数 E(x,y) (平滑) =================== % 让边缘附近取值大, 中部逐渐衰减 distLeft = X; distRight = Lx - X; distBot = Y; distTop = Ly - Y; distBnd = min( min(distLeft, distRight), min(distBot, distTop) ); delta_e = 0.03; % 边缘带宽 E = exp( -(distBnd/delta_e).^2 ); % E在边缘约=1, 中心处≈exp(-∞)=0 %% === 4. 定义脚核 (2D离散) ================================ % 4.1 bulk核: 稍大一些 Nk = 15; halfk = floor(Nk/2); kx = (-halfk:halfk)*dx; ky = (-halfk:halfk)*dy; [KX, KY] = meshgrid(kx, ky); sigma_bx = 0.02; sigma_by = 0.01; Kb_raw = exp( -((KX.^2)/(2*sigma_bx^2) + (KY.^2)/(2*sigma_by^2)) ); % 归一化 sumKb = sum(Kb_raw(:))*dx*dy; K_bulk = Kb_raw / sumKb; % 4.2 edge核: 更集中 sigma_ex = 0.01; sigma_ey = 0.005; Ke_raw = exp( -((KX.^2)/(2*sigma_ex^2) + (KY.^2)/(2*sigma_ey^2)) ); sumKe = sum(Ke_raw(:))*dx*dy; K_edge = Ke_raw / sumKe; %% === 5. 时间迭代 ========================================= % 保存每隔几步的高度分布, 以便可视化演化 nSave = [1, 20, 50, 100, Nt]; % 要存储或显示的时间步 figure('Name','Stair Wear with Gradient-Dependent','Position',[100,50,1200,700]); for n = 1:Nt % ---- 5.1 计算梯度(central difference) ----------- % 注意网格大小; 这里只做简单差分(不处理边界更复杂情况) hx = zeros(size(h)); hy = zeros(size(h)); % x方向差分 hx(:,2:end-1) = (h(:,3:end) - h(:,1:end-2)) / (2*dx); hx(:,1) = (h(:,2) - h(:,1)) / dx; % 左边一阶 hx(:,end) = (h(:,end) - h(:,end-1)) / dx; % 右边 % y方向差分 hy(2:end-1,:) = (h(3:end,:) - h(1:end-2,:)) / (2*dy); hy(1,:) = (h(2,:) - h(1,:)) / dy; % 下边 hy(end,:) = (h(end,:) - h(end-1,:)) / dy; % 上边 gradMag = sqrt(hx.^2 + hy.^2); % ---- 5.2 定义势函数 phi, psi 等 -------------- % 简单示例:phi = c1*|grad h|, psi = 同理 or = c1*|grad h| + c2*(some factor) c1 = 1.0; phi = c1 * gradMag; % 只考虑斜度 psi = c1 * gradMag; % edge部分也类似 % 可以叠加一些固定倾向, 例如中部更喜好 => phi += small*( (X-0.5Lx)^2 + ... ) % 在此略去 % ---- 5.3 计算 bulk + edge 分布(归一化) ---------- P_bulk_unnorm = exp( -gamma_val * phi ); P_edge_unnorm = E .* exp( -gamma_val * psi ); int_bulk = sum(P_bulk_unnorm(:))*dx*dy; int_edge = sum(P_edge_unnorm(:))*dx*dy; P_bulk = (Lambda_bulk / int_bulk) * P_bulk_unnorm; P_edge = (Lambda_edge / int_edge) * P_edge_unnorm; % ---- 5.4 卷积得到 T_bulk, T_edge --------------- T_bulk = conv2(P_bulk, K_bulk, 'same') * dx * dy; T_edge = conv2(P_edge, K_edge, 'same') * dx * dy; % ---- 5.5 更新楼梯高度 h ------------------------- dh_dt = - alpha_bulk * T_bulk - alpha_edge * T_edge; % 显式时间步进 h_new = h + dt * dh_dt; % 如果不允许高度<0,可在此强制剪切: h_new = max(h_new,0) h_new(h_new<0) = 0; h = h_new; % 赋值回去 % ---- 5.6 可视化(可选) --------------------------- if ismember(n, nSave) subplot(2,3, find(n==nSave)); imagesc(x, y, h); axis xy equal tight; colorbar; colormap(jet(256)); title(sprintf('h at step %d', n)); xlabel('x(m)'); ylabel('y(m)'); end end % 最后, figure 显示若干时刻的 h suptitle('Stair Wear Model (Gradient-Dependent)'); end
h=1.0
平整,,因此 phi=psi=0
,分布 P_bulk,P_edge
都是比较均匀/只由 E
差异决定。phi, psi
有空间差异,从而影响人群分布。alpha_edge
通常更大、且 E
在边缘较强,边缘磨损会更快,边缘高度会明显比中部更快变低。grad h
逐渐增大,会进一步调控势函数,使脚步分布发生反馈演化。如果您想模拟一个极端情景(“刚开始只踩某一点”):
nSave
存放想查看的时间步,分别画出高度分布。也可做动画或 3D 曲面图等。通过这个示例,您就能看到“梯度解算 + 初始高度 + 双通道踩踏”在一个简单 2D 网格上的完整数值流程。在实际课题中,需将网格、时间步、势函数等进一步细化和验证,才能得到可靠的磨损预测结果。希望此代码能帮助您快速上手研究框架。祝研究顺利!
首先,考虑数学理想型的问题,在真实情况,楼梯只有一侧进行磨损,也就是磨损的初始点应该选在楼梯长边的边缘的中间靠右测进行初始磨损。其次,我希望这个楼梯设置长宽高,然后颜色来代表高度。其次,椭圆掩码问题是否进行考虑,卷积运算是否正确。其次,我在模拟几千年变化的,所以我希望模拟几千万次,每次的磨损系数尽量小,让概率主导一些东西。请在注释中表明所有我需要更改或者调整的参数并且放在一起
下面给出一个尽量自包含的 MATLAB 示例脚本,示范如何在“楼梯磨损”模型中实现:
Niter
等)集中放在代码开头,方便统一修改;重要说明
- 该示例代码主要展示思路,而非工业级模拟。
- 如果您要模拟“几千万次迭代”,显式方法可能会很慢或数值不稳定,需特别减小 和 ,或改用更高效的数值方案(例如隐式/半隐式,或者在磨损变化很小时加速迭代)。
- 代码中的“只在某处开始踩踏”是通过人为设置分布
P_initial
来实现的;后续如果您还想让人流随着楼梯变形而改变分布,可再添加势函数 等高级机制。
请将下面脚本保存为 StairWearOneSideDemo.m
,并在 MATLAB 运行即可。
matlabfunction StairWearOneSideDemo % ================================================================ % 楼梯磨损模型 (简化版), 演示以下特性: % 1) 只在楼梯长边靠右侧进行初始踩踏 % 2) 使用椭圆形脚核(footprint mask)进行卷积 % 3) 在迭代过程中以颜色表示楼梯当前高度 % 4) 可将时间步数(Niter)设得非常大, 并调小磨损系数(alpha) % 以模拟极长时间(几千年等) % % 【用户需修改/关注的关键参数】都放在本脚本开头, 见“(A)参数设置”区。 % % - Lx, Ly, Nx, Ny : 楼梯平面尺寸与网格 % - H0 : 楼梯初始高度 % - alpha : 磨损系数 (越大磨损越快) % - dt : 每次迭代的时间步长 % - Niter : 迭代步数(可设很大, 但会影响运行速度) % - FootEllipseA,B : 脚印椭圆形核(半轴大小) % - Ppeak : 初始踩踏的峰值(表示那一侧被踩的强度) % - ShowSteps : 控制隔多少步做一次可视化(防止绘图过多卡顿) % % 注:为了演示“只踩一侧”,本例中人流分布不再动态适应楼梯形变, % 而是固定在右侧一带。若要让踩踏区域随楼梯形变而改变,可自行 % 在迭代中更新脚步分布 P(x,y)。 % ================================================================ %% (A) ============ 用户关键参数设置 ============================= % -- 楼梯尺寸与网格 -- Lx = 1.0; % 楼梯踏面的长度 (米), x方向 Ly = 0.3; % 楼梯踏面的宽度 (米), y方向 Nx = 200; % x方向网格数量 Ny = 60; % y方向网格数量 % -- 楼梯初始高度 -- H0 = 1.0; % 整个楼梯踏面初始高度(米) % -- 磨损动力学参数 -- alpha = 1e-5; % 磨损系数 (越小, 磨损越慢, 用于模拟数千年) dt = 1.0; % 每个迭代步对应的时间(天/年/任意单位). 与 alpha 搭配. % -- 迭代次数, 及可视化频率 -- Niter = 2000; % 总迭代步数 (可调大到几千万, 视计算资源而定) ShowSteps = 200; % 每隔多少步绘图一次 (防止绘图过于频繁) % -- 脚印椭圆形掩码(核) 的参数(半轴长度) -- FootEllipseA = 0.02; % x方向半轴(米) FootEllipseB = 0.01; % y方向半轴(米) % -- 初始踩踏分布(只在右侧中部附近) -- % 这里使用了一个二维Gaussian, 中心在 x=0.9*Lx, y=0.5*Ly, % 并乘以一个峰值 Ppeak Ppeak = 10.0; % 踩踏强度峰值 (可调) %% (B) ============ 初始化网格与高度场 ============================ x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2)-x(1); dy = y(2)-y(1); [X, Y] = meshgrid(x, y); % 结果大小 (Ny, Nx) h = H0 * ones(Ny, Nx); % 初始楼梯高度为常数H0 %% (C) ============ 定义初始踩踏分布 P(x,y) ====================== % 只在楼梯长边(右侧)的中部区域集中 xc = 0.9 * Lx; % 分布中心 x坐标 yc = 0.5 * Ly; % 分布中心 y坐标 % 高斯形式 sigma_x = 0.05*Lx; % 可以调大/调小, 控制踩踏区的横向扩散 sigma_y = 0.08*Ly; % 同理, 纵向扩散 P_unnorm = exp( -(((X - xc).^2)/(2*sigma_x^2) + ((Y - yc).^2)/(2*sigma_y^2)) ); % 乘以峰值, 得到最终踩踏分布(单位时间内的踩踏密度). 不归一化也可以. P = Ppeak * P_unnorm; %% (D) ============ 椭圆形脚印核(卷积核) ======================== % 为模拟真实脚印, 取 2D Gaussian + 保证其积分约=1 % 椭圆长轴 ~ FootEllipseA, 短轴 ~ FootEllipseB Nk = 31; % 核离散尺寸(odd number), 需足够覆盖 >3*sigma 范围 halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); sigma_kx = FootEllipseA/2; % 这里将 "半轴" 转化为 "标准差",可自行调整 sigma_ky = FootEllipseB/2; K_raw = exp( -((KX.^2)/(2*sigma_kx^2) + (KY.^2)/(2*sigma_ky^2)) ); % 归一化,使 sum(K_raw(:))*dx*dy = 1 Ksum = sum(K_raw(:)) * dx * dy; K = K_raw / Ksum; %% (E) ============ 主循环:显式迭代楼梯高度 ===================== figure('Name','OneSide Stair Wear Demo','Position',[200 100 1000 500]); for n = 1:Niter % (1) 计算当前踩踏强度 (卷积) % T(x,y) = (K * P)(x,y). % 在MATLAB中: conv2(P, K, 'same')*(dx*dy). T = conv2(P, K, 'same') * dx * dy; % (2) 计算磨损速度 % dh/dt = - alpha * T dhdt = - alpha * T; % (3) 显式时间步进 h_new = h + dt * dhdt; % 如果不允许高度降到负数,可剪切: h_new(h_new<0) = 0; h = h_new; % (4) 每隔 ShowSteps 步可视化一次 (颜色代表高度) if mod(n, ShowSteps) == 1 || n == Niter subplot(1,2,1); imagesc(x, y, h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0 H0]); % 显示高度范围 title(sprintf('Height h at iteration %d',n)); xlabel('x'); ylabel('y'); colormap(jet(256)); % 也可用 surf/mesh 3D可视化: subplot(1,2,2); surf(x, y, h,'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); % 将Z轴限制在 [0, H0] caxis([0 H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface (h) at iteration %d',n)); xlabel('x'); ylabel('y'); zlabel('height'); view(45,50); drawnow; end end end
(A) 参数设置区
alpha
、迭代次数 Niter
、椭圆核大小、初始踩踏分布峰值 Ppeak
、可视化步长等)。只在楼梯长边(靠右侧)开始踩踏
(C) 定义初始踩踏分布
中,我们把高斯中心 xc=0.9*Lx
。x≈0.9Lx
、y≈0.5Ly
(楼梯右侧中部)形成一个局部峰值,其它地方踩踏概率几乎为零。xc=0.95*Lx
等;或想更靠角落,可以调 yc
。椭圆形脚印核
(D)
中,用 2D 高斯生成一个椭圆形的“foot mask”,其形状由参数 FootEllipseA
(x向半轴)和 FootEllipseB
(y向半轴)控制。conv2
实现“脚印覆盖”对楼梯的磨损贡献。卷积运算
T = conv2(P, K, 'same')*(dx*dy)
是离散近似
T(x,y)
就是单位时间下每点被踩踏的强度;接着乘以 alpha
得到磨损速率。超长时间模拟 (几千年)
Niter=1e7
以上),并让楼梯高度能始终保持在合理范围,务必减小 alpha
(比如 1e-7
或更小),同时减小 dt
或者改用更高效的数值方案(比如在磨损变化很小时,可以做自适应时间步、或使用隐式方法以减少迭代次数)。ShowSteps
设得很大(例如 ShowSteps=1e6
),只在非常少的步数上做可视化,以减少绘图开销。颜色代表高度
imagesc(...)
或 surf(...)
时,我们通过 caxis([0 H0])
将颜色映射到 [0, H0]。当楼梯某些区域高度下降时,就会出现偏蓝色(低)或甚至接近 0。仅固定分布 vs. 动态分布
P
。P(x,y,t)
随着楼梯凹陷、倾斜而改变(例如喜欢踩低洼的地方或绕开破损区域),那就需要在每个时间步里,重新计算 P
并再做卷积。(A)
段,方便一次性修改;其余部分仅做示范性实现。希望这个示例能帮助您更好地搭建“单侧磨损 + 椭圆脚核 + 颜色高度可视化”的楼梯磨损模型。祝研究顺利!
sigma_x = 0.05Lx; % 可以调大/调小, 控制踩踏区的横向扩散
sigma_y = 0.08Ly; % 同理, 纵向扩散
P_unnorm = exp( -(((X - xc).^2)/(2sigma_x^2) + ((Y - yc).^2)/(2sigma_y^2)) );只改动这两行,加一个随机扰动
下面给出一个最简单的方法示例,仅在原先两行里内联地对 施加一个小的随机扰动。这样就可以保持高斯分布的“大体形状”,但每个网格点会有一点随机抖动(例如 ±2%):
matlabsigma_x = 0.05 * Lx; % 可调:控制x方向的扩散范围 sigma_y = 0.08 * Ly; % 可调:控制y方向的扩散范围 % 定义一个随机因子(例如±2%的扰动) randAmplitude = 0.02; % 最大扰动幅度2% noiseFactor = 1 + randAmplitude * (2*rand(size(X)) - 1); % ↑ 这样 noiseFactor 的范围大约是 [1-0.02, 1+0.02] = [0.98,1.02] % 原先的高斯 * 噪声因子,并确保结果>=0 P_unnorm = exp( -(((X - xc).^2)/(2*sigma_x^2) + ((Y - yc).^2)/(2*sigma_y^2)) ) ... .* noiseFactor; P_unnorm = max(P_unnorm, 0); % 剪切到非负
- 前两行(
sigma_x
和sigma_y
)保持不变,仅加在后面一个**“噪声因子”**。- 用
randAmplitude
来统一控制随机扰动幅度,您可以改小或改大;若要 ±1% 就改成0.01
。max(P_unnorm,0)
用于防止噪声因子在极小值时使结果出现负数。- 如果希望在不同迭代步都重新生成噪声,可以把这段放进循环里,每步更新一次。否则就只在最初构造一次随机扰动。
这样就只改动/扩展了原来生成 P_unnorm
的那两行,便能实现“高斯分布 + 随机抖动” 的效果。
function StairWearOneSideDemo
% ================================================================
% 楼梯磨损模型 (简化版), 演示以下特性:
% 1) 只在楼梯长边靠右侧进行初始踩踏
% 2) 使用椭圆形脚核(footprint mask)进行卷积
% 3) 在迭代过程中以颜色表示楼梯当前高度
% 4) 可将时间步数(Niter)设得非常大, 并调小磨损系数(alpha)
% 以模拟极长时间(几千年等)
%
% 【用户需修改/关注的关键参数】都放在本脚本开头, 见“(A)参数设置”区。
%
% - Lx, Ly, Nx, Ny : 楼梯平面尺寸与网格
% - H0 : 楼梯初始高度
% - alpha : 磨损系数 (越大磨损越快)
% - dt : 每次迭代的时间步长
% - Niter : 迭代步数(可设很大, 但会影响运行速度)
% - FootEllipseA,B : 脚印椭圆形核(半轴大小)
% - Ppeak : 初始踩踏的峰值(表示那一侧被踩的强度)
% - ShowSteps : 控制隔多少步做一次可视化(防止绘图过多卡顿)
%
% 注:为了演示“只踩一侧”,本例中人流分布不再动态适应楼梯形变,
% 而是固定在右侧一带。若要让踩踏区域随楼梯形变而改变,可自行
% 在迭代中更新脚步分布 P(x,y)。
% ================================================================
%% (A) ============ 用户关键参数设置 =============================
% -- 楼梯尺寸与网格 --
Lx = 0.4; % 楼梯踏面的长度 (米), x方向
Ly = 1.5; % 楼梯踏面的宽度 (米), y方向
Nx = 200; % x方向网格数量
Ny = 60; % y方向网格数量
% -- 楼梯初始高度 --
H0 = 0.3; % 整个楼梯踏面初始高度(米)
% -- 磨损动力学参数 --
alpha = 1e-6; % 磨损系数 (越小, 磨损越慢, 用于模拟数千年)
dt = 1.0; % 每个迭代步对应的时间(天/年/任意单位). 与 alpha 搭配.
% -- 迭代次数, 及可视化频率 --
Niter = 200000; % 总迭代步数 (可调大到几千万, 视计算资源而定)
ShowSteps = 2000; % 每隔多少步绘图一次 (防止绘图过于频繁)
% -- 脚印椭圆形掩码(核) 的参数(半轴长度) --
FootEllipseA = 0.02; % x方向半轴(米)
FootEllipseB = 0.01; % y方向半轴(米)
% -- 初始踩踏分布(只在右侧中部附近) --
% 这里使用了一个二维Gaussian, 中心在 x=0.9Lx, y=0.5Ly,
% 并乘以一个峰值 Ppeak
Ppeak = 11.0; % 踩踏强度峰值 (可调)
%% (B) ============ 初始化网格与高度场 ============================
x = linspace(0, Lx, Nx);
y = linspace(0, Ly, Ny);
dx = x(2)-x(1);
dy = y(2)-y(1);
[X, Y] = meshgrid(x, y); % 结果大小 (Ny, Nx)
h = H0 * ones(Ny, Nx); % 初始楼梯高度为常数H0
%% (C) ============ 定义初始踩踏分布 P(x,y) ======================
% 只在楼梯长边(右侧)的中部区域集中
xc = 0.9 * Lx; % 分布中心 x坐标
yc = 0.5 * Ly; % 分布中心 y坐标
% 高斯形式
sigma_x = 0.5Lx; % 可以调大/调小, 控制踩踏区的横向扩散
sigma_y = 0.8Ly; % 同理, 纵向扩散
P_unnorm = exp( -(((X - xc).^2)/(2sigma_x^2) + ((Y - yc).^2)/(2sigma_y^2)) );
% 乘以峰值, 得到最终踩踏分布(单位时间内的踩踏密度). 不归一化也可以.
P = Ppeak * P_unnorm;
%% (D) ============ 椭圆形脚印核(卷积核) ========================
% 为模拟真实脚印, 取 2D Gaussian + 保证其积分约=1
% 椭圆长轴 ~ FootEllipseA, 短轴 ~ FootEllipseB
Nk = 31; % 核离散尺寸(odd number), 需足够覆盖 >3*sigma 范围
halfk = floor(Nk/2);
kx = (-halfk : halfk)*dx;
ky = (-halfk : halfk)*dy;
[KX, KY] = meshgrid(kx, ky);
sigma_kx = FootEllipseA/2; % 这里将 "半轴" 转化为 "标准差",可自行调整
sigma_ky = FootEllipseB/2;
K_raw = exp( -((KX.^2)/(2sigma_kx^2) + (KY.^2)/(2sigma_ky^2)) );
% 归一化,使 sum(K_raw(:))dxdy = 1
Ksum = sum(K_raw(:)) * dx * dy;
K = K_raw / Ksum;
%% (E) ============ 主循环:显式迭代楼梯高度 =====================
figure('Name','OneSide Stair Wear Demo','Position',[200 100 1000 500]);
for n = 1:Niter
text% (1) 计算当前踩踏强度 (卷积) % T(x,y) = (K * P)(x,y). % 在MATLAB中: conv2(P, K, 'same')*(dx*dy). T = conv2(P, K, 'same') * dx * dy; % (2) 计算磨损速度 % dh/dt = - alpha * T dhdt = - alpha * T; % (3) 显式时间步进 h_new = h + dt * dhdt; % 如果不允许高度降到负数,可剪切: h_new(h_new<0) = 0; h = h_new; % (4) 每隔 ShowSteps 步可视化一次 (颜色代表高度) if mod(n, ShowSteps) == 1 || n == Niter subplot(1,2,1); imagesc(x, y, h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0 H0]); % 显示高度范围 title(sprintf('Height h at iteration %d',n)); xlabel('x'); ylabel('y'); colormap(jet(256)); % 也可用 surf/mesh 3D可视化: subplot(1,2,2); surf(x, y, h,'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); % 将Z轴限制在 [0, H0] caxis([0 H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface (h) at iteration %d',n)); xlabel('x'); ylabel('y'); zlabel('height'); view(45,50); drawnow; end
end
end
1、加入刚才的随机扰动
2、加入边缘的不同解算
3、加入“人们希望踩到好的地方的phi函数”
下面给出一个在 单侧踩踏 演示代码基础上“一次性”纳入以下三个改动的示例版本,方便您参照或直接使用:
该示例仍是一个简单的显式迭代,但足以演示如何把这三种机制整合到同一个脚本中。所有需要修改/关注的关键参数,都集中放在脚本开头 (A) 用户参数设置 区,便于您根据需求快速调整。
重要提示:
- 这里为了展示思路,在每个时间步都重新计算 (包含随机扰动、边缘放大、势函数)并用它进行卷积,再更新楼梯高度 。
- 若您要模拟“几千万次”迭代,请注意:
- 数值效率:显式方法可能非常慢,需考虑减少可视化频率、减小网格规模、或采用更高效的数值方法;
- 数值稳定:请确保 足够小,否则会出现高度快速变为负值或其他不稳定现象;
- 随机扰动:若您要在所有几千万步都产生新的随机噪声,可能需要很长运行时间。可选择只在每隔若干步时才更新一次随机分布,以降低计算量。
matlabfunction StairWearOneSideDemo_Extended % ================================================================ % 楼梯磨损模型 (扩展版), 演示以下特性: % 1) 只在楼梯长边靠右侧进行初始主踩踏(基础高斯分布) % 2) 在每次迭代中对踩踏分布加入随机扰动 % 3) 对楼梯边缘进行额外放大(或衰减)处理 % 4) 使用简单的势函数 phi(h) 来模拟“更倾向于踩高度较好(或平整)的区域” % 5) 在迭代过程中以颜色表示楼梯当前高度 % % 使用显式方法,若要模拟大规模(几千万步),需注意数值效率与稳定性。 % 所有关键参数都在(A)中集中设置。 % % ================================================================ %% (A) ==================== 用户参数设置 ========================== % ------- 楼梯尺寸与网格 -------- Lx = 0.4; % 楼梯踏面的长度 (米), x方向 Ly = 1.5; % 楼梯踏面的宽度 (米), y方向 Nx = 200; % x方向网格数量 Ny = 60; % y方向网格数量 % ------- 楼梯初始高度 --------- H0 = 0.3; % 楼梯踏面初始高度(米) % ------- 磨损动力学参数 ------- alpha = 1e-6; % 磨损系数 (越小, 磨损越慢) dt = 1.0; % 每次迭代对应的时间间隔(单位自定). 与 alpha 搭配 % ------- 迭代次数 & 可视化频率 ------ Niter = 200000; % 总迭代步数 (可根据需求调大) ShowSteps = 2000; % 每隔多少步绘图一次(防止绘图过多卡顿) % ------- 椭圆形脚印核(卷积) ------ FootEllipseA = 0.02; % x方向半轴(米) FootEllipseB = 0.01; % y方向半轴(米) % ------- 基础踩踏分布参数(只在右侧中部集中) ------ Ppeak = 11.0; % 基础高斯分布的峰值 centerX = 0.9; % 基础踩踏在楼梯 x= centerX*Lx 处 centerY = 0.5; % 在楼梯 y= centerY*Ly 处 sigma_x = 0.5; % 相对 Lx 的扩散 (实际 = sigma_x*Lx) sigma_y = 0.8; % 相对 Ly 的扩散 (实际 = sigma_y*Ly) % ------- (1) 随机扰动幅度 -------- randAmplitude = 0.02; % 2% 幅度(可改大/改小) % ------- (2) 边缘放大/衰减参数 ------ EdgeAmp = 0.5; % 边缘额外增益(>0表示放大因子,可为负表示衰减) EdgeDelta = 0.05; % 距边缘(米)的影响范围(越大影响越宽) % ------- (3) 人们倾向踩好地方的势函数 phi(h) ------ gammaVal = 5.0; % 势函数指数敏感度 cPhi = 1.0; % phi = cPhi*(H0 - h), 越磨损(高度越低) -> phi越大 -> 分布指数衰减 % ================================================================ % 结束 “(A) 用户需调的关键参数” 区 % ================================================================ %% (B) ============ 初始化网格与高度场 ============================ x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x, y); % (Ny×Nx)大小 h = H0 * ones(Ny, Nx); % 初始楼梯高度为常数H0 %% (C) ============ 边缘函数 E(x,y) =============================== % 定义一个平滑因子 Eedge(x,y),让靠近边缘处放大(或衰减)踩踏 % 这里演示:离边缘越近,Eedge 值越大(指数衰减) % distEdge = 到四周边的最小距离 distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distBnd = min( min(distLeft, distRight), min(distBottom, distTop) ); % 指数形式: Eedge = 1 + EdgeAmp * exp( - (distBnd/EdgeDelta)^2 ) Eedge = 1 + EdgeAmp * exp( - (distBnd / EdgeDelta).^2 ); %% (D) ============ 脚印椭圆形掩码(卷积核) ======================= % 取 2D Gaussian, 归一化使得积分约=1 Nk = 31; halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); sigma_kx = FootEllipseA/2; sigma_ky = FootEllipseB/2; K_raw = exp( - ((KX.^2)/(2*sigma_kx^2) + (KY.^2)/(2*sigma_ky^2)) ); Ksum = sum(K_raw(:))*dx*dy; K = K_raw / Ksum; %% (E) ============ 主循环:显式迭代楼梯高度 ===================== figure('Name','OneSide Extended','Position',[200 100 1000 500]); for n = 1:Niter % == (1) 根据当前楼梯高度 h, 计算 “phi(h)” 用于动态分布修正 == % 简单示例: phi(x,y) = cPhi*(H0 - h), 即高度越低 -> phi越大 -> 人更不愿踩 phi = cPhi * (H0 - h); % == (2) 计算 “基础高斯” + “边缘放大” + “势函数衰减” + “随机扰动” == % 2.1 基础踩踏分布 (以右侧中部为中心的高斯) Gx = (X - centerX*Lx).^2 / (2*(sigma_x*Lx)^2); Gy = (Y - centerY*Ly).^2 / (2*(sigma_y*Ly)^2); P_base = exp( -(Gx + Gy) ) * Ppeak; % 未包括任何修正时 % 2.2 加上势函数修正 => * exp(- gammaVal * phi) % phi越大 => exp越小 => 踩踏概率下降 P_phi = P_base .* exp( - gammaVal * phi ); % 2.3 加上边缘放大 => * Eedge P_edge = P_phi .* Eedge; % 2.4 加上随机扰动 noiseFactor = 1 + randAmplitude*(2*rand(size(X)) - 1); % 令其在 [1 - randAmplitude, 1 + randAmplitude] 间浮动 P_unnorm = P_edge .* noiseFactor; P_unnorm = max(P_unnorm, 0); % 剪切防负值 % == (3) 最终踩踏分布, 这里不再特意归一化,可直接使用 == P = P_unnorm; % 就是本步用于卷积的踩踏分布 % == (4) 卷积求踩踏强度 T == T = conv2(P, K, 'same') * dx * dy; % == (5) 更新楼梯高度 h == dhdt = - alpha * T; % dh/dt = - alpha*T h_new = h + dt * dhdt; h_new(h_new < 0) = 0; % 防止数值下穿负值 h = h_new; % == (6) 每隔 ShowSteps 步可视化一次(颜色表示高度) == if (mod(n, ShowSteps) == 1) || (n == Niter) subplot(1,2,1); imagesc(x, y, h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0 H0]); % 高度范围 title(sprintf('Height h at iteration %d',n)); xlabel('x'); ylabel('y'); colormap(jet(256)); subplot(1,2,2); surf(x, y, h, 'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); caxis([0 H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface (h) at iteration %d',n)); xlabel('x'); ylabel('y'); zlabel('height'); view(45,50); drawnow; end end end
随机扰动
(E)
的每次迭代中,我们定义
这样每个网格点都有一个随机系数,范围在matlabnoiseFactor = 1 + randAmplitude*(2*rand(size(X)) - 1); P_unnorm = P_edge .* noiseFactor;
[1 - randAmplitude, 1 + randAmplitude]
之间,从而在高斯+边缘放大+势函数的分布基础上增加少量抖动。randAmplitude
(如 0.02 → ±2%)来控制扰动强度。边缘函数 E(x,y)
可让离边缘越近的地方matlabdistBnd = min( min(distLeft, distRight), min(distBottom, distTop) ); Eedge = 1 + EdgeAmp * exp( - (distBnd / EdgeDelta).^2 );
distBnd
越小, 越接近 1,从而 Eedge
更大;EdgeAmp
设为 负值(例如 -0.3
),这样在边缘会乘上一个小于 1 的因子,使得人群不愿踩近边。“倾向踩高处”的势函数
exp(- gammaVal * phi)
越小,表示人更不愿意踩已经磨损严重(变低)的地方。exp(+ gammaVal * phi)
中用正号等,总之根据所需行为改写逻辑。ShowSteps
为一个更大的值(例如 1e5
),否则频繁绘图会极其耗时。alpha
或 改变 dt
。这样,这份示例就演示了:
希望对您在模型中加入这些改动有所帮助。祝研究顺利!
仿照常见的 “Boltzmann型/势函数型” 分布思想,假设人们对 地形势函数 有一定敏感度,脚步越倾向在势函数较低的区域落脚。令 表示这种敏感度参数, 是由楼梯表面斜度、凹凸、湿滑等因素决定的函数,可简写为
同时,普通踩踏部分的人流量总量是 。则:
(1) 先写出朴素的加权指数形式
(2) 归一化到给定的总流量
由于我们需要
故可定义
由此得:
与普通踩踏不同,“边缘踩踏”往往只出现在距离楼梯边缘较近的区域,并且人们在边缘行走/斜踩时,所考量的“势函数”可能略有差异。例如:有的人喜欢在边缘快速通过;或出于安全顾虑,在阶梯转角处贴边而行;或者斜着踩更便于某种发力。我们用一个新函数 代表他们对当地地形/边缘舒适度的评价。并引入一个权重函数 来标识“离楼梯边缘越近,越有可能进行边缘踩踏”。
定义边缘指示函数
同样采用 Boltzmann 型
只要 的地方就不会出现边缘踩踏脚步中心。
归一化到
同理,需要
因此
这样就得到了 边缘踩踏脚步中心 在 上的分布函数。重新修改边缘函数和势函数按照上述定义
然后加一个图,把二维的图复制一下,然后每次展示50个卷积核在图上
下面给出一个示范性 MATLAB 脚本,演示如何根据前述 Boltzmann型 分布(区分 普通踩踏 + 边缘踩踏),定义好势函数 和边缘指示函数 ,然后在 2D 楼梯平面 上计算得到:
这样就实现了:
注意:
- 该示例仅做“单次”的分布计算,不包含楼梯高度随时间演化的迭代过程。若要将其融入磨损演化,需要在每个时间步里更新 并重新计算 。
- 如果想让脚印椭圆朝向也随斜踩角度随机变化,可进一步在绘制时随机旋转。此处示例中只画了“固定方向椭圆”。
- “把二维的图复制一下,然后每次展示 50 个卷积核在图上” 可以理解为:先画出分布的热图,再“复制”同样的背景,然后叠加 50 个脚印示意。这里用subplot 或 figure 的方式来实现对比。
EdgeBoltzmannDemo.m
matlabfunction EdgeBoltzmannDemo % ========================================================= % 演示:在一个楼梯踏步平面 Omega 上,基于 % - 普通踩踏分布 P_bulk % - 边缘踩踏分布 P_edge % 计算出总分布 P_total 并可视化。 % % 并在第二张图上随机抽取50个落脚点,用椭圆画出“脚印”示意。 % % 假设: % - phi(x,y) = 由楼梯斜度/湿滑等导致的势函数(这里演示用简单表达) % - psi(x,y) = 边缘踩踏的势函数(此处也用简单表达) % - E(x,y) = 边缘指示函数(离边缘越近, 值越大) % - gamma = 人群对势函数的敏感度 % - Lambda_bulk, Lambda_edge = 各自单位时间内的人流量 % ========================================================= clc; clear; close all; %% ----------------- 1. 基础参数设置 -------------------- Lx = 1.0; % 楼梯在x方向的长度 Ly = 0.4; % 楼梯在y方向的宽度 Nx = 200; % x方向离散网格 Ny = 80; % y方向离散网格 x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x,y); % 结果size = (Ny, Nx) Lambda_bulk = 100; % 普通踩踏流量 Lambda_edge = 20; % 边缘踩踏流量 gamma_val = 5.0; % Boltzmann分布的指数敏感度 deltaEdge = 0.05; % 判定“贴边区域”的阈值(米), 或用于平滑 %% ----------------- 2. 定义 phi(x,y), psi(x,y) -------------- % 在真实场景中, phi, psi 可能依赖楼梯表面高度 h(x,y) 及其梯度 % 这里仅做一个示例: % phi(x,y) = (some mild slope) + (center bump) % psi(x,y) = (slightly different shape) % % 您可根据实际需求或楼梯测量来定义 phi = 0.5*(X - 0.5*Lx).^2 + 0.2*(Y - 0.3*Ly).^2; psi = 0.3*(X - 0.8*Lx).^2 + 0.5*(Y - 0.5*Ly).^2; % 如果您不需要这么复杂, 也可令 phi=0, psi=0 作最简单测试 %% ----------------- 3. 定义边缘指示函数 E(x,y) -------------- % 方式1(硬阈值): dist_to_edge < delta => E=1; 否则=0 % 方式2(平滑): E= exp( - (dist/delta)^2 ), 等 % % 这里演示平滑: distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distEdge = min( min(distLeft, distRight), min(distBottom, distTop) ); % 平滑形式: E = exp( - (distEdge / deltaEdge).^2 ); %% ----------------- 4. 计算未归一化分布 ------------------- % P_bulk_unnorm = exp(- gamma * phi ) % P_edge_unnorm = E(x,y)* exp(- gamma * psi ) P_bulk_unnorm = exp( - gamma_val * phi ); P_edge_unnorm = E .* exp( - gamma_val * psi ); % 归一化常数: int_bulk = sum( P_bulk_unnorm(:) ) * dx * dy; int_edge = sum( P_edge_unnorm(:) ) * dx * dy; % 最终分布: P_bulk = (Lambda_bulk / int_bulk) .* P_bulk_unnorm; P_edge = (Lambda_edge / int_edge) .* P_edge_unnorm; % 总分布: P_total = P_bulk + P_edge; %% ----------------- 5. 可视化(热力图) ---------------------- figure('Name','Boltzmann + Edge Demo','Position',[100 100 1200 500]); % (a) 左图: 显示 P_total 分布(热力图) subplot(1,2,1); imagesc(x,y, P_total); set(gca,'YDir','normal'); axis equal tight; colorbar; title('P_{total}(x,y) = P_{bulk} + P_{edge}'); xlabel('x'); ylabel('y'); colormap(jet(256)); % (b) 右图: 在同样的背景上叠加 "50个脚印" (卷积核中心) subplot(1,2,2); imagesc(x,y, P_total); set(gca,'YDir','normal'); axis equal tight; colorbar; title('P_{total} with 50 sampled footprints'); xlabel('x'); ylabel('y'); colormap(jet(256)); hold on; %% ----------------- 6. 随机抽样50个落脚点 ----------------- % 方法:离散化取 P_total(:) 做成一个概率向量 prob 使其和=1 % 然后对 50 个随机数做累积分布逆采样,得到索引 % % 这在大网格下会稍慢( Nx*Ny=16k ), 但演示足矣 % 1) 构造离散概率向量(长度 Nx*Ny) prob = P_total(:); sumProb = sum(prob)*dx*dy; %理想应接近 (Lambda_bulk+Lambda_edge) % 但做采样时仅需 prob/sum(prob) prob = prob / sum(prob); % 2) 构造累积分布CDF cdf = cumsum(prob); % 3) 每采样1次:生成 rand ∈ [0,1], 在cdf中找其位置 Nfoot = 50; % 要在图上展示的脚印数 rng('shuffle'); % 随机种子 % 定义脚印椭圆大小(仅示意用) rX = 0.01; % x方向半径 rY = 0.005; % y方向半径 theta = linspace(0, 2*pi, 20); for i = 1:Nfoot r = rand(); idx = find(cdf>=r, 1, 'first'); % 找到cdf>=r的最小索引 % idx 对应到 (row, col): [row, col] = ind2sub([Ny, Nx], idx); % 该踩踏点坐标 (xC, yC) xC = x(col); yC = y(row); % 画一个椭圆 xx = xC + rX*cos(theta); yy = yC + rY*sin(theta); plot(xx, yy, 'k-', 'LineWidth',1.2); end hold off; end
定义 :
边缘函数 :
deltaEdge
控制影响带宽。计算分布 :
\exp(-γ * phi)
或 E * \exp(-γ * psi)
,再除以积分归一化到给定流量 / 。可视化:
imagesc(...)
画出热力图;脚印位置:
(rX, rY)
的椭圆来画,也可以加随机旋转,或直接用 rectangle('Position',...)
画圆弧。如果想像动画一样,在迭代中每一小步都要重新展示 50 个脚印,可以把第 6 步 (随机抽样 + 画椭圆) 放到一个时间循环里头,每步更新 并画图。这样就能看到随着势函数或边缘函数改变,不同步里的落脚点分布也随之变化。
以上脚本示范了如何重新修改边缘函数与势函数并按照 (A1)/(A2) 的公式计算踩踏分布,并在同一个 2D 图上叠加部分卷积核示意(脚印)。在实际应用中,您可自由调整:
这样就能更贴近您想要的“每次展示若干卷积核(脚印)”可视化效果。希望能对您有所帮助,祝研究顺利!
function StairWearOneSideDemo_Extended
% ================================================================
% 楼梯磨损模型 (扩展版), 演示以下特性:
% 1) 只在楼梯长边靠右侧进行初始主踩踏(基础高斯分布)
% 2) 在每次迭代中对踩踏分布加入随机扰动
% 3) 对楼梯边缘进行额外放大(或衰减)处理
% 4) 使用简单的势函数 phi(h) 来模拟“更倾向于踩高度较好(或平整)的区域”
% 5) 在迭代过程中以颜色表示楼梯当前高度
%
% 使用显式方法,若要模拟大规模(几千万步),需注意数值效率与稳定性。
% 所有关键参数都在(A)中集中设置。
%
% ================================================================
%% (A) ==================== 用户参数设置 ==========================
% ------- 楼梯尺寸与网格 --------
Lx = 0.4; % 楼梯踏面的长度 (米), x方向
Ly = 1.5; % 楼梯踏面的宽度 (米), y方向
Nx = 200; % x方向网格数量
Ny = 60; % y方向网格数量
% ------- 楼梯初始高度 ---------
H0 = 0.3; % 楼梯踏面初始高度(米)
% ------- 磨损动力学参数 -------
alpha = 1e-6; % 磨损系数 (越小, 磨损越慢)
dt = 1.0; % 每次迭代对应的时间间隔(单位自定). 与 alpha 搭配
% ------- 迭代次数 & 可视化频率 ------
Niter = 200000; % 总迭代步数 (可根据需求调大)
ShowSteps = 2000; % 每隔多少步绘图一次(防止绘图过多卡顿)
% ------- 椭圆形脚印核(卷积) ------
FootEllipseA = 0.02; % x方向半轴(米)
FootEllipseB = 0.01; % y方向半轴(米)
% ------- 基础踩踏分布参数(只在右侧中部集中) ------
Ppeak = 11.0; % 基础高斯分布的峰值
centerX = 0.9; % 基础踩踏在楼梯 x= centerXLx 处
centerY = 0.5; % 在楼梯 y= centerYLy 处
sigma_x = 0.3; % 相对 Lx 的扩散 (实际 = sigma_xLx)
sigma_y = 0.5; % 相对 Ly 的扩散 (实际 = sigma_yLy)
% ------- (1) 随机扰动幅度 --------
randAmplitude = 0.02; % 2% 幅度(可改大/改小)
% ------- (2) 边缘放大/衰减参数 ------
EdgeAmp = 0.9; % 边缘额外增益(>0表示放大因子,可为负表示衰减)
EdgeDelta = 0.05; % 距边缘(米)的影响范围(越大影响越宽)
% ------- (3) 人们倾向踩好地方的势函数 phi(h) ------
gammaVal = 15.0; % 势函数指数敏感度
cPhi = 1.0; % phi = cPhi*(H0 - h), 越磨损(高度越低) -> phi越大 -> 分布指数衰减
% ================================================================
% 结束 “(A) 用户需调的关键参数” 区
% ================================================================
%% (B) ============ 初始化网格与高度场 ============================
x = linspace(0, Lx, Nx);
y = linspace(0, Ly, Ny);
dx = x(2) - x(1);
dy = y(2) - y(1);
[X, Y] = meshgrid(x, y); % (Ny×Nx)大小
h = H0 * ones(Ny, Nx); % 初始楼梯高度为常数H0
%% (C) ============ 边缘函数 E(x,y) ===============================
% 定义一个平滑因子 Eedge(x,y),让靠近边缘处放大(或衰减)踩踏
% 这里演示:离边缘越近,Eedge 值越大(指数衰减)
% distEdge = 到四周边的最小距离
distLeft = X;
distRight = Lx - X;
distBottom = Y;
distTop = Ly - Y;
distBnd = min( min(distLeft, distRight), min(distBottom, distTop) );
% 指数形式: Eedge = 1 + EdgeAmp * exp( - (distBnd/EdgeDelta)^2 )
Eedge = 1 + EdgeAmp * exp( - (distBnd / EdgeDelta).^2 );
%% (D) ============ 脚印椭圆形掩码(卷积核) =======================
% 取 2D Gaussian, 归一化使得积分约=1
Nk = 31;
halfk = floor(Nk/2);
kx = (-halfk : halfk)*dx;
ky = (-halfk : halfk)*dy;
[KX, KY] = meshgrid(kx, ky);
sigma_kx = FootEllipseA/2;
sigma_ky = FootEllipseB/2;
K_raw = exp( - ((KX.^2)/(2sigma_kx^2) + (KY.^2)/(2sigma_ky^2)) );
Ksum = sum(K_raw(:))dxdy;
K = K_raw / Ksum;
%% (E) ============ 主循环:显式迭代楼梯高度 =====================
figure('Name','OneSide Extended','Position',[200 100 1000 500]);
for n = 1:Niter
text% == (1) 根据当前楼梯高度 h, 计算 “phi(h)” 用于动态分布修正 == % 简单示例: phi(x,y) = cPhi*(H0 - h), 即高度越低 -> phi越大 -> 人更不愿踩 phi = cPhi * (H0 - h); % == (2) 计算 “基础高斯” + “边缘放大” + “势函数衰减” + “随机扰动” == % 2.1 基础踩踏分布 (以右侧中部为中心的高斯) Gx = (X - centerX*Lx).^2 / (2*(sigma_x*Lx)^2); Gy = (Y - centerY*Ly).^2 / (2*(sigma_y*Ly)^2); P_base = exp( -(Gx + Gy) ) * Ppeak; % 未包括任何修正时 % 2.2 加上势函数修正 => * exp(- gammaVal * phi) % phi越大 => exp越小 => 踩踏概率下降 P_phi = P_base .* exp( - gammaVal * phi ); % 2.3 加上边缘放大 => * Eedge P_edge = P_phi .* Eedge; % 2.4 加上随机扰动 noiseFactor = 1 + randAmplitude*(2*rand(size(X)) - 1); % 令其在 [1 - randAmplitude, 1 + randAmplitude] 间浮动 P_unnorm = P_edge .* noiseFactor; P_unnorm = max(P_unnorm, 0); % 剪切防负值 % == (3) 最终踩踏分布, 这里不再特意归一化,可直接使用 == P = P_unnorm; % 就是本步用于卷积的踩踏分布 % == (4) 卷积求踩踏强度 T == T = conv2(P, K, 'same') * dx * dy; % == (5) 更新楼梯高度 h == dhdt = - alpha * T; % dh/dt = - alpha*T h_new = h + dt * dhdt; h_new(h_new < 0) = 0; % 防止数值下穿负值 h = h_new; % == (6) 每隔 ShowSteps 步可视化一次(颜色表示高度) == if (mod(n, ShowSteps) == 1) || (n == Niter) subplot(1,2,1); imagesc(x, y, h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0 H0]); % 高度范围 title(sprintf('Height h at iteration %d',n)); xlabel('x'); ylabel('y'); colormap(jet(256)); subplot(1,2,2); surf(x, y, h, 'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); caxis([0 H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface (h) at iteration %d',n)); xlabel('x'); ylabel('y'); zlabel('height'); view(45,50); drawnow; end
end
end很好,在这个代码的基础上改动,只改变边缘函数和势函数
下面给出一个在之前 StairWearOneSideDemo_Extended 示例的基础上,只修改“边缘函数 ”与“势函数 ” 的版本。其余逻辑(如随机扰动、时间迭代、脚印核卷积、可视化等)均保持原先代码的思路与结构。
注意
- 这里演示的 与 只是示例,以便您看清“如何在代码中更换这两个函数”——实际应用中应根据楼梯真实特征来定义(例如:依赖楼梯高度 或其梯度 、或边缘斜踩因素等)。
- 其余参数()与之前基本相同,仅作为示范。
- 如果您还需要保留“ = c_\phi,(H0 - h)) + 之类的耦合,也可以将下面的演示定义与之前代码合并即可。
请将下面脚本保存为 StairWearOneSideDemo_EdgePhiModified.m
并运行。与之前代码相比,您会看到**(C)边缘函数** 和 (E)(1)势函数处做了不同的定义(用示例的形式)。其余部分大体相同。
matlabfunction StairWearOneSideDemo_EdgePhiModified % ================================================================ % 楼梯磨损模型 (改动版):只改变 % 1) 边缘函数 Eedge(x,y) [此处用硬阈值方式演示] % 2) 势函数 phi(x,y) [此处用简单“中心凸起”示例] % % 其余结构(随机扰动、卷积、时间迭代等)沿用之前 Extended 版本。 % ================================================================ %% (A) ==================== 用户参数设置 ========================== % ------- 楼梯尺寸与网格 -------- Lx = 0.4; % 楼梯踏面的长度 (米) Ly = 1.5; % 楼梯踏面的宽度 (米) Nx = 200; % x方向网格数量 Ny = 60; % y方向网格数量 % ------- 楼梯初始高度 --------- H0 = 0.3; % 楼梯踏面初始高度(米) % ------- 磨损动力学参数 ------- alpha = 1e-6; % 磨损系数 (越小, 磨损越慢) dt = 1.0; % 每次迭代对应的时间间隔(单位自定). 与 alpha 搭配 % ------- 迭代次数 & 可视化频率 ------ Niter = 200000; % 总迭代步数 (可根据需求调大) ShowSteps = 2000; % 每隔多少步绘图一次(防止绘图过多卡顿) % ------- 椭圆形脚印核(卷积) ------ FootEllipseA = 0.02; % x方向半轴(米) FootEllipseB = 0.01; % y方向半轴(米) % ------- 基础踩踏分布参数(只在右侧中部集中) ------ Ppeak = 11.0; % 基础高斯分布的峰值 centerX = 0.9; % 基础踩踏在楼梯 x= centerX*Lx 处 centerY = 0.5; % 在楼梯 y= centerY*Ly 处 sigma_x = 0.3; % 相对 Lx 的扩散 (实际 = sigma_x*Lx) sigma_y = 0.5; % 相对 Ly 的扩散 (实际 = sigma_y*Ly) % ------- (1) 随机扰动幅度 -------- randAmplitude = 0.02; % 2% 幅度(可改大/改小) % ------- (2) 边缘阈值 ------ EdgeDelta = 0.05; % 判断离边缘< EdgeDelta 即属“边缘区” % ------- (3) 人们对势函数的指数敏感度 gammaVal ------ gammaVal = 15.0; % 越大 -> 越偏爱低phi区域 % ================================================================ % 结束 “(A) 用户可调的关键参数” 区 % ================================================================ %% (B) ============ 初始化网格 与 楼梯高度 ========================= x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x, y); h = H0 * ones(Ny, Nx); % 初始楼梯高度 %% (C) ============ (改动) 边缘函数: 用硬阈值 ===================== % 例如:离边缘 distBnd < EdgeDelta => Eedge=1; 否则=0 distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distBnd = min( min(distLeft, distRight), min(distBottom, distTop) ); Eedge = zeros(size(X)); Eedge(distBnd < EdgeDelta) = 1; % 硬阈值 % 若想平滑过渡,可改回 exp(- (distBnd/EdgeDelta)^2) %% (D) ============ 定义脚印椭圆形掩码(卷积核) =================== Nk = 31; halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); sigma_kx = FootEllipseA/2; sigma_ky = FootEllipseB/2; K_raw = exp( - ((KX.^2)/(2*sigma_kx^2) + (KY.^2)/(2*sigma_ky^2)) ); Ksum = sum(K_raw(:))*dx*dy; K = K_raw / Ksum; %% (E) ============ 主循环:只改势函数 phi(x,y) ================== figure('Name','OneSide Edge+Phi Modified','Position',[200 100 1000 500]); for n = 1:Niter % == (1) (改动) 定义势函数 phi(x,y) ========================== % 这里演示: phi = (X - 0.5Lx)^2 + (Y - 0.5Ly)^2 % => 人更倾向在“距(0.5Lx, 0.5Ly)近”的区域( phi小 ) % => 如果 exp(-gammaVal*phi ), 中心点 phi=0 => 概率最高 xC = 0.5*Lx; yC = 0.5*Ly; phi = (X - xC).^2 + (Y - yC).^2; % == (2) 计算 “基础踩踏” + “phi修正” + “Eedge” + “随机扰动” == % 2.1 基础踩踏(高斯在右侧) Gx = (X - centerX*Lx).^2 / (2*(sigma_x*Lx)^2); Gy = (Y - centerY*Ly).^2 / (2*(sigma_y*Ly)^2); P_base = exp( -(Gx + Gy) ) * Ppeak; % 2.2 势函数修正 => multiply by exp(- gammaVal * phi) P_phi = P_base .* exp(- gammaVal * phi); % 2.3 边缘函数 => multiply by Eedge (0或1) P_edge = P_phi .* Eedge; % 2.4 随机扰动 => ± randAmplitude noiseFactor = 1 + randAmplitude*(2*rand(size(X)) - 1); P_unnorm = P_edge .* noiseFactor; P_unnorm = max(P_unnorm, 0); % == (3) 最终踩踏分布 P(x,y) == P = P_unnorm; % == (4) 卷积求踩踏强度 T == T = conv2(P, K, 'same') * dx * dy; % == (5) 显式时间步进更新楼梯高度 h == dhdt = - alpha * T; h_new = h + dhdt * dt; h_new(h_new<0) = 0; h = h_new; % == (6) 可视化: 每隔 ShowSteps 步显示当前高度分布 == if (mod(n, ShowSteps) == 1) || (n == Niter) subplot(1,2,1); imagesc(x, y, h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0 H0]); title(sprintf('Height h at iteration %d',n)); xlabel('x'); ylabel('y'); colormap(jet(256)); subplot(1,2,2); surf(x, y, h, 'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); caxis([0 H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface (h) at iteration %d',n)); xlabel('x'); ylabel('y'); zlabel('height'); view(45,50); drawnow; end end end
边缘函数
matlabEedge = zeros(size(X)); Eedge(distBnd < EdgeDelta) = 1;
EdgeDelta
就为 1,否则 0。势函数
除以上两点之外,随机扰动、迭代更新、可视化等都和前例相同,便于您看到只要替换这两块定义,就能得到完全不同的人流分布及磨损结果。
Eedge
和 (E)(1)势函数 phi
的定义,以体现“如何快速在同一套程序框架下切换不同的边缘/势函数建模”。希望这个改动示例能帮助您更好地理解并应用“只改变边缘函数与势函数”的做法。祝研究顺利!
仿照常见的 “Boltzmann型/势函数型” 分布思想,假设人们对 地形势函数 有一定敏感度,脚步越倾向在势函数较低的区域落脚。令 表示这种敏感度参数, 是由楼梯表面斜度、凹凸、湿滑等因素决定的函数,可简写为
同时,普通踩踏部分的人流量总量是 。则:
(1) 先写出朴素的加权指数形式
(2) 归一化到给定的总流量
由于我们需要
故可定义
由此得:
与普通踩踏不同,“边缘踩踏”往往只出现在距离楼梯边缘较近的区域,并且人们在边缘行走/斜踩时,所考量的“势函数”可能略有差异。例如:有的人喜欢在边缘快速通过;或出于安全顾虑,在阶梯转角处贴边而行;或者斜着踩更便于某种发力。我们用一个新函数 代表他们对当地地形/边缘舒适度的评价。并引入一个权重函数 来标识“离楼梯边缘越近,越有可能进行边缘踩踏”。
定义边缘指示函数
同样采用 Boltzmann 型
只要 的地方就不会出现边缘踩踏脚步中心。
归一化到
同理,需要
因此
这样就得到了 边缘踩踏脚步中心 在 上的分布函数。
把这个边缘函数和势函数集成在刚才的代码里,用这个聊天提供的原始积分形式
下面给出一个示例 MATLAB 脚本,展示如何将原始积分形式(A1)/(A2) 的 普通踩踏 + 边缘踩踏分布引入到“楼梯磨损”迭代过程中。与之前的示例相比,这里我们:
显式地使用
和
这两条公式进行 归一化。
区分两种磨损系数 和 ,分别对应普通踩踏与边缘踩踏的力度/方向差异。
每个时间步先根据 来计算 (或更新) 和 ,然后用数值积分(离散求和)归一化获得 ,再做 2D 卷积获得踩踏强度 ,最后更新高度场 。
该示例仍为显式时间步进,如果您需要模拟数千万步,请务必注意数值稳定性和效率(可适当减小、使用更粗网格、或改用更高效的隐式/半隐式方法)。
StairWear_BulkEdge_IntegralForm.m
matlabfunction StairWear_BulkEdge_IntegralForm % ================================================================ % 演示:在楼梯平面 [0,Lx]×[0,Ly] 上,采用 % (A1) P_bulk = (Lambda_bulk * exp(-gamma*phi)) / ∫( exp(-gamma*phi) ) % (A2) P_edge = (Lambda_edge * E(x,y)*exp(-gamma*psi)) / ∫( E*exp(-gamma*psi) ) % 计算出普通踩踏/边缘踩踏分布,并进行显式迭代更新楼梯高度 h(x,y,t)。 % % 包含: % - alpha_bulk, alpha_edge: 区分两种踩踏的磨损系数 % - 卷积核 (bulk/edge) 可与分布分别做卷积,再加总磨损 % - 归一化积分使用离散数值求和 % - phi, psi, E 可以随楼梯形变而更新 (这里示例中只简单依赖 h) % ================================================================ clc; clear; close all; %% (A) ============ 参数设置 ====================================== % ---------- 空间网格与楼梯尺寸 ----------- Lx = 1.0; % x方向长度(米) Ly = 0.4; % y方向长度(米) Nx = 100; % x方向网格数 Ny = 40; % y方向网格数 % ---------- 时间迭代参数 ------------- dt = 0.5; % 时间步长(可视为天、年…) Niter = 500; % 迭代步数 (可调大/小) % ---------- 磨损系数 ------------- alpha_bulk = 1e-5; % 普通踩踏对高度的磨损系数 alpha_edge = 2e-5; % 边缘踩踏磨损系数(稍大) % ---------- 人流量 & 指数敏感度 gamma ----------- Lambda_bulk = 80; % 普通踩踏的流量(人次/单位时间) Lambda_edge = 20; % 边缘踩踏的流量 gamma_val = 5.0; % 指数分布敏感度 % ---------- 初始楼梯高度 ----------- H0 = 0.3; % 整个踏面初始高度(米) % ---------- 卷积核(脚印)设置(各两种) ----------- % 若想简化,可让bulk/edge核相同。此示例展示如何使用两套。 % - bulk核较大, edge核较窄 Nk = 21; % 核半径离散网格(odd number) FootBulkAx = 0.03; % bulk脚印 x向半轴 FootBulkAy = 0.015; % bulk脚印 y向半轴 FootEdgeAx = 0.02; % edge脚印 x向半轴(更小) FootEdgeAy = 0.01; % edge脚印 y向半轴 % ---------- 可视化间隔 ----------- ShowSteps = 50; % 每隔多少步显示结果 %% (B) ============ 建立网格、初始高度 h ========================= x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x,y); % (Ny×Nx) h = H0 * ones(Ny, Nx); % 初始楼梯高度 %% (C) ============ 定义 边缘指示 E(x,y) ========================== % 示例:离边缘越近 => E=1, 其它为0 (硬阈值), 或平滑 % 这里演示平滑: E=exp(-(distBnd/delta)^2) delta_edge = 0.05; distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distBnd = min( min(distLeft, distRight), min(distBottom, distTop) ); E = exp( -(distBnd/delta_edge).^2 ); % 如果想用硬阈值: % E = double(distBnd<delta_edge); %% (D1) =========== 定义 两种脚印核 K_bulk, K_edge =============== % 先构建离散网格kxi,kyi,再做 2D Gaussian, 归一化 halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); % --- bulk核 --- sigma_bx = FootBulkAx/2; sigma_by = FootBulkAy/2; Kb_raw = exp( -((KX.^2)/(2*sigma_bx^2) + (KY.^2)/(2*sigma_by^2)) ); sumKb = sum(Kb_raw(:))*dx*dy; K_bulk = Kb_raw / sumKb; % --- edge核 --- sigma_ex = FootEdgeAx/2; sigma_ey = FootEdgeAy/2; Ke_raw = exp( -((KX.^2)/(2*sigma_ex^2) + (KY.^2)/(2*sigma_ey^2)) ); sumKe = sum(Ke_raw(:))*dx*dy; K_edge = Ke_raw / sumKe; %% (E) ============ 时间迭代 ====================================== figure('Name','Bulk+Edge Integral Form Demo','Position',[200,100,1000,500]); for n = 1:Niter % == (1) 定义势函数 phi & psi ================================= % 在真实情形中, 可依赖 h 与 ∇h. % 这里仅做示例(随 h 的某种依赖): % phi: 让中部高 => phi小 => 人更爱踩 phi = (X-0.5*Lx).^2 + (Y-0.5*Ly).^2 + 0.2*(H0 - h); % psi: 让右侧更小 => 假设人倾向在右上角做边缘踩踏 psi = 0.2*(X - 0.8*Lx).^2 + 0.5*(Y - 0.3*Ly).^2; % == (2) 计算 “未归一化” bulk/edge 分布 ======================= Pbulk_unnorm = exp( - gamma_val * phi ); Pedge_unnorm = E .* exp( - gamma_val * psi ); % == (3) 计算各自归一化因子, 得到 P_bulk, P_edge ============ % 数值积分 ≈ sum(...) * dx * dy sum_bulk = sum(Pbulk_unnorm(:)) * dx * dy; sum_edge = sum(Pedge_unnorm(:)) * dx * dy; P_bulk = (Lambda_bulk / sum_bulk) .* Pbulk_unnorm; P_edge = (Lambda_edge / sum_edge) .* Pedge_unnorm; % == (4) 卷积计算踩踏强度 T_bulk, T_edge ===================== T_bulk = conv2(P_bulk, K_bulk, 'same') * dx * dy; T_edge = conv2(P_edge, K_edge, 'same') * dx * dy; % == (5) 楼梯高度更新:dh/dt = -alpha_bulk*T_bulk - alpha_edge*T_edge dhdt = - alpha_bulk*T_bulk - alpha_edge*T_edge; h_new = h + dt*dhdt; h_new(h_new<0) = 0; % 剪切防止负高度 h = h_new; % == (6) 可视化: 每隔 ShowSteps 步 ============================ if mod(n,ShowSteps)==1 || (n==Niter) subplot(1,2,1); imagesc(x,y,h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0,H0]); title(sprintf('Height h at step %d',n)); xlabel('x(m)'); ylabel('y(m)'); colormap(jet(256)); subplot(1,2,2); surf(x,y,h,'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); caxis([0,H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface at step %d',n)); xlabel('x(m)'); ylabel('y(m)'); zlabel('h'); view(45,45); drawnow; end end end
(A) 参数设置
alpha_bulk, alpha_edge
区分两种踩踏对磨损的不同强度;Lambda_bulk, Lambda_edge
给出普通踩踏/边缘踩踏的人流量;gamma_val
控制人群对势函数的敏感度;(C) 边缘指示
(E)(1) 势函数 的定义
(E)(2)/(3) 计算 的原始积分形式
Pbulk_unnorm = exp(- gamma * phi)
,再做离散求和 (sum(...) * dx*dy
) 得到归一化系数;Pedge_unnorm = E * exp(- gamma * psi)
同理;P_bulk, P_edge
分别满足其流量积分 = Lambda_bulk, Lambda_edge
。(E)(4) 卷积
P_bulk, P_edge
卷积对应脚印核 K_bulk, K_edge
,得到 T_bulk, T_edge
。K
。(E)(5) 迭代更新
dhdt = ...
,再 h_new = h + dt * dhdt
。可视化
ShowSteps
步在 figure 上显示一次高度分布 (2D image + 3D surface)。让 更真实
分时段人流量
Lambda_bulk(t), Lambda_edge(t)
在不同迭代(天/年)里变化,可在循环内每步更新它们。随机扰动
数值稳定 & 性能
通过以上示例,就能看到如何把**“原始积分形式”** (A1)/(A2) 对应到离散数值实现,并在时间迭代中耦合“普通踩踏”和“边缘踩踏”两种分布,对楼梯高度进行磨损模拟。希望对您在整合这些公式到代码中有所帮助,祝研究顺利!
其他不变,加一个新图显示掩码
下面给出一个示例脚本,只在先前的代码基础上做了一个最小改动:在定义完边缘掩码 之后,额外新增一个图像窗口(或子图)来显示这个掩码的分布情况。其余部分(包括普通踩踏/边缘踩踏分布、卷积、时间迭代等)均与先前示例保持一致。
要点说明
- 我们在 (C) 定义完边缘指示函数 E 后,即刻画出一个 figure 或 subplot,用
imagesc(...)
或surf(...)
来查看它的二维分布。- 这样就能直观地观察哪些区域被认定为“边缘”或“贴边区”的权重大、哪些地方权重小(尤其是使用平滑函数时)。
StairWear_BulkEdge_IntegralForm_MaskShown.m
matlabfunction StairWear_BulkEdge_IntegralForm_MaskShown % ================================================================ % 演示:在楼梯平面 [0,Lx]×[0,Ly] 上,采用 % (A1) P_bulk = (Lambda_bulk * exp(-gamma*phi)) / ∫( exp(-gamma*phi) ) % (A2) P_edge = (Lambda_edge * E(x,y)*exp(-gamma*psi)) / ∫( E*exp(-gamma*psi) ) % 计算出普通踩踏/边缘踩踏分布,并进行显式迭代更新楼梯高度 h(x,y,t)。 % % 与之前示例相比,唯一新增: % - 显示掩码 E(x,y) 的一张图,以便可视化边缘指示函数。 % % ================================================================ clc; clear; close all; %% (A) ============ 参数设置 ====================================== % ---------- 空间网格与楼梯尺寸 ----------- Lx = 1.0; % x方向长度(米) Ly = 0.4; % y方向长度(米) Nx = 100; % x方向网格数 Ny = 40; % y方向网格数 % ---------- 时间迭代参数 ------------- dt = 0.5; % 时间步长(可视为天、年…) Niter = 500; % 迭代步数 (可调大/小) % ---------- 磨损系数 ------------- alpha_bulk = 1e-5; % 普通踩踏对高度的磨损系数 alpha_edge = 2e-5; % 边缘踩踏磨损系数(稍大) % ---------- 人流量 & 指数敏感度 gamma ----------- Lambda_bulk = 80; % 普通踩踏的流量 Lambda_edge = 20; % 边缘踩踏的流量 gamma_val = 5.0; % 指数分布敏感度 % ---------- 初始楼梯高度 ----------- H0 = 0.3; % 整个踏面初始高度(米) % ---------- 卷积核(脚印)设置(各两种) ----------- % - bulk核较大, edge核较窄 Nk = 21; % 核离散范围(odd number) FootBulkAx = 0.03; % bulk脚印 x向半轴 FootBulkAy = 0.015; % bulk脚印 y向半轴 FootEdgeAx = 0.02; % edge脚印 x向半轴(更小) FootEdgeAy = 0.01; % edge脚印 y向半轴 % ---------- 可视化间隔 ----------- ShowSteps = 50; % 每隔多少步显示 %% (B) ============ 建立网格、初始高度 h ========================= x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x,y); % (Ny×Nx) h = H0 * ones(Ny, Nx); % 初始楼梯高度 %% (C) ============ 定义 边缘指示 E(x,y) 并显示 =================== % 示例:离边缘越近 => E=exp(-(distBnd/delta)^2) delta_edge = 0.05; distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distBnd = min( min(distLeft, distRight), min(distBottom, distTop) ); E = exp( -(distBnd/delta_edge).^2 ); % 如果想用硬阈值: % E = double(distBnd<delta_edge); % -- 新增:显示该掩码 E(x,y) 的图 --- figure('Name','Edge Mask'); imagesc(x,y, E); set(gca,'YDir','normal'); axis equal tight; colorbar; colormap(jet(256)); title('Edge Mask E(x,y)'); xlabel('x'); ylabel('y'); %% (D1) =========== 定义 两种脚印核 K_bulk, K_edge =============== halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); % --- bulk核 --- sigma_bx = FootBulkAx/2; sigma_by = FootBulkAy/2; Kb_raw = exp( -((KX.^2)/(2*sigma_bx^2) + (KY.^2)/(2*sigma_by^2)) ); sumKb = sum(Kb_raw(:))*dx*dy; K_bulk = Kb_raw / sumKb; % --- edge核 --- sigma_ex = FootEdgeAx/2; sigma_ey = FootEdgeAy/2; Ke_raw = exp( -((KX.^2)/(2*sigma_ex^2) + (KY.^2)/(2*sigma_ey^2)) ); sumKe = sum(Ke_raw(:))*dx*dy; K_edge = Ke_raw / sumKe; %% (E) ============ 时间迭代 ====================================== figure('Name','Bulk+Edge Integral Form Demo','Position',[200,100,1000,500]); for n = 1:Niter % == (1) 定义势函数 phi & psi =============== % 示例: phi = (X-0.5Lx)^2 + (Y-0.5Ly)^2 + 0.2*(H0-h) phi = (X-0.5*Lx).^2 + (Y-0.5*Ly).^2 + 0.2*(H0 - h); % psi = 0.2*(X-0.8Lx)^2 + 0.5*(Y-0.3Ly)^2 psi = 0.2*(X - 0.8*Lx).^2 + 0.5*(Y - 0.3*Ly).^2; % == (2) 未归一化分布, bulk & edge ============= Pbulk_unnorm = exp( - gamma_val * phi ); Pedge_unnorm = E .* exp( - gamma_val * psi ); % == (3) 归一化到 Lambda_bulk & Lambda_edge ===== sum_bulk = sum(Pbulk_unnorm(:))*dx*dy; sum_edge = sum(Pedge_unnorm(:))*dx*dy; P_bulk = (Lambda_bulk / sum_bulk) .* Pbulk_unnorm; P_edge = (Lambda_edge / sum_edge) .* Pedge_unnorm; % == (4) 卷积计算踩踏强度 ====================== T_bulk = conv2(P_bulk, K_bulk, 'same') * dx*dy; T_edge = conv2(P_edge, K_edge, 'same') * dx*dy; % == (5) 更新楼梯高度 h ======================== dhdt = - alpha_bulk*T_bulk - alpha_edge*T_edge; h_new = h + dt*dhdt; h_new(h_new<0) = 0; h = h_new; % == (6) 可视化 ================================= if mod(n, ShowSteps)==1 || (n == Niter) subplot(1,2,1); imagesc(x,y,h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0,H0]); title(sprintf('Height h at step %d', n)); xlabel('x(m)'); ylabel('y(m)'); colormap(jet(256)); subplot(1,2,2); surf(x,y,h, 'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); caxis([0,H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface at step %d', n)); xlabel('x(m)'); ylabel('y(m)'); zlabel('h'); view(45,45); drawnow; end end end
在 (C) 定义 E
后,增加了一段:
matlabfigure('Name','Edge Mask'); imagesc(x,y, E); set(gca,'YDir','normal'); axis equal tight; colorbar; colormap(jet(256)); title('Edge Mask E(x,y)'); xlabel('x'); ylabel('y');
这样就可以在一个新的 figure 窗口中单独显示掩码分布 。
其余如势函数 、卷积核、时间循环、可视化都保持与先前示例一致。
exp(-(dist/delta)^2)
形式)。E
的 3D 形状,也可改成:
或者使用两行 subplot 分别显示 2D/3D 等方式。matlabsurf(x,y,E, 'EdgeColor','none'); view(45,45); ...
这样,您就能在同一个脚本里既跑楼梯磨损模拟,又在单独一个窗口中看到掩码 的整体分布。希望对您的需求有所帮助,祝研究顺利!
function StairWear_BulkEdge_IntegralForm
% ================================================================
% 演示:在楼梯平面 [0,Lx]×[0,Ly] 上,采用
% (A1) P_bulk = (Lambda_bulk * exp(-gammaphi)) / ∫( exp(-gammaphi) )
% (A2) P_edge = (Lambda_edge * E(x,y)exp(-gammapsi)) / ∫( Eexp(-gammapsi) )
% 计算出普通踩踏/边缘踩踏分布,并进行显式迭代更新楼梯高度 h(x,y,t)。
%
% 包含:
% - alpha_bulk, alpha_edge: 区分两种踩踏的磨损系数
% - 卷积核 (bulk/edge) 可与分布分别做卷积,再加总磨损
% - 归一化积分使用离散数值求和
% - phi, psi, E 可以随楼梯形变而更新 (这里示例中只简单依赖 h)
% ================================================================
clc; clear; close all;
%% (A) ============ 参数设置 ======================================
% ---------- 空间网格与楼梯尺寸 -----------
Lx = 1.0; % x方向长度(米)
Ly = 0.4; % y方向长度(米)
Nx = 100; % x方向网格数
Ny = 40; % y方向网格数
% ---------- 时间迭代参数 -------------
dt = 0.001; % 时间步长(可视为天、年…)
Niter = 10000; % 迭代步数 (可调大/小)
% ---------- 磨损系数 -------------
alpha_bulk = 1e-5; % 普通踩踏对高度的磨损系数
alpha_edge = 2e-5; % 边缘踩踏磨损系数(稍大)
% ---------- 人流量 & 指数敏感度 gamma -----------
Lambda_bulk = 800; % 普通踩踏的流量(人次/单位时间)
Lambda_edge = 20; % 边缘踩踏的流量
gamma_val = 5.0; % 指数分布敏感度
% ---------- 初始楼梯高度 -----------
H0 = 0.3; % 整个踏面初始高度(米)
% ---------- 卷积核(脚印)设置(各两种) -----------
% 若想简化,可让bulk/edge核相同。此示例展示如何使用两套。
% - bulk核较大, edge核较窄
Nk = 21; % 核半径离散网格(odd number)
FootBulkAx = 0.03; % bulk脚印 x向半轴
FootBulkAy = 0.015; % bulk脚印 y向半轴
FootEdgeAx = 0.02; % edge脚印 x向半轴(更小)
FootEdgeAy = 0.01; % edge脚印 y向半轴
% ---------- 可视化间隔 -----------
ShowSteps = 100; % 每隔多少步显示结果
%% (B) ============ 建立网格、初始高度 h =========================
x = linspace(0, Lx, Nx);
y = linspace(0, Ly, Ny);
dx = x(2) - x(1);
dy = y(2) - y(1);
[X, Y] = meshgrid(x,y); % (Ny×Nx)
h = H0 * ones(Ny, Nx); % 初始楼梯高度
%% (C) ============ 定义 边缘指示 E(x,y) ==========================
% 示例:离边缘越近 => E=1, 其它为0 (硬阈值), 或平滑
% 这里演示平滑: E=exp(-(distBnd/delta)^2)
delta_edge = 0.05;
distLeft = X;
distRight = Lx - X;
distBottom = Y;
distTop = Ly - Y;
distBnd = min( min(distLeft, distRight), min(distBottom, distTop) );
E = exp( -(distBnd/delta_edge).^2 );
% 如果想用硬阈值:
% E = double(distBnd<delta_edge);
%% (D1) =========== 定义 两种脚印核 K_bulk, K_edge ===============
% 先构建离散网格kxi,kyi,再做 2D Gaussian, 归一化
halfk = floor(Nk/2);
kx = (-halfk : halfk)*dx;
ky = (-halfk : halfk)*dy;
[KX, KY] = meshgrid(kx, ky);
% --- bulk核 ---
sigma_bx = FootBulkAx/2;
sigma_by = FootBulkAy/2;
Kb_raw = exp( -((KX.^2)/(2sigma_bx^2) + (KY.^2)/(2sigma_by^2)) );
sumKb = sum(Kb_raw(:))dxdy;
K_bulk = Kb_raw / sumKb;
% --- edge核 ---
sigma_ex = FootEdgeAx/2;
sigma_ey = FootEdgeAy/2;
Ke_raw = exp( -((KX.^2)/(2sigma_ex^2) + (KY.^2)/(2sigma_ey^2)) );
sumKe = sum(Ke_raw(:))dxdy;
K_edge = Ke_raw / sumKe;
%% (E) ============ 时间迭代 ======================================
figure('Name','Bulk+Edge Integral Form Demo','Position',[200,100,1000,500]);
for n = 1:Niter
text% == (1) 定义势函数 phi & psi ================================= % 在真实情形中, 可依赖 h 与 ∇h. % 这里仅做示例(随 h 的某种依赖): % phi: 让中部高 => phi小 => 人更爱踩 phi = (X-0.5*Lx).^2 + (Y-0.5*Ly).^2 + 0.2*(H0 - h); % psi: 让右侧更小 => 假设人倾向在右上角做边缘踩踏 psi = 0.2*(X - 0.8*Lx).^2 + 0.5*(Y - 0.3*Ly).^2; % == (2) 计算 “未归一化” bulk/edge 分布 ======================= Pbulk_unnorm = exp( - gamma_val * phi ); Pedge_unnorm = E .* exp( - gamma_val * psi ); % == (3) 计算各自归一化因子, 得到 P_bulk, P_edge ============ % 数值积分 ≈ sum(...) * dx * dy sum_bulk = sum(Pbulk_unnorm(:)) * dx * dy; sum_edge = sum(Pedge_unnorm(:)) * dx * dy; P_bulk = (Lambda_bulk / sum_bulk) .* Pbulk_unnorm; P_edge = (Lambda_edge / sum_edge) .* Pedge_unnorm; % == (4) 卷积计算踩踏强度 T_bulk, T_edge ===================== T_bulk = conv2(P_bulk, K_bulk, 'same') * dx * dy; T_edge = conv2(P_edge, K_edge, 'same') * dx * dy; % == (5) 楼梯高度更新:dh/dt = -alpha_bulk*T_bulk - alpha_edge*T_edge dhdt = - alpha_bulk*T_bulk - alpha_edge*T_edge; h_new = h + dt*dhdt; h_new(h_new<0) = 0; % 剪切防止负高度 h = h_new; % == (6) 可视化: 每隔 ShowSteps 步 ============================ if mod(n,ShowSteps)==1 || (n==Niter) subplot(1,2,1); imagesc(x,y,h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0,H0]); title(sprintf('Height h at step %d',n)); xlabel('x(m)'); ylabel('y(m)'); colormap(jet(256)); subplot(1,2,2); surf(x,y,h,'EdgeColor','none'); axis([0 Lx 0 Ly 0 H0]); caxis([0,H0]); colorbar; colormap(jet(256)); title(sprintf('3D surface at step %d',n)); xlabel('x(m)'); ylabel('y(m)'); zlabel('h'); view(45,45); figure('Name','Edge Mask'); imagesc(x,y, E); set(gca,'YDir','normal'); axis equal tight; colorbar; colormap(jet(256)); title('Edge Mask E(x,y)'); xlabel('x'); ylabel('y'); drawnow; end
end
end掩码出现故障,请改进后给出完整代码,掩码用小椭圆形绘制,每次绘制迭代次数个
下面给出一个完整的 MATLAB 示例脚本,基于您先前的“Bulk+Edge Integral Form”楼梯磨损代码,但进行了如下改动,以满足**“掩码用小椭圆形绘制,并在每次迭代显示一定数量的椭圆”**的需求:
imagesc
显示掩码 ,而是:
提示
- 若迭代步数很大(如几万到几十万),且您在每次都要画很多椭圆,绘图耗时可能会很高。可将
ShowSteps
设大些,或将椭圆数减小。- 如果想让每个椭圆有不同朝向,也可在绘制时加入随机旋转角度。此处仅用固定朝向示范。
请将脚本保存为 StairWear_BulkEdge_IntegralForm_WithEllipses.m
后在 MATLAB 中运行。
matlabfunction StairWear_BulkEdge_IntegralForm_WithEllipses % ================================================================ % 演示:楼梯平面 [0,Lx]×[0,Ly] 上,Boltzmann分布计算 % (A1) P_bulk, (A2) P_edge,并进行显式迭代楼梯高度。 % % 在每次可视化时: % - 第一子图: 显示楼梯高度 h % - 第二子图: 在掩码 E(x,y) 所界定的“边缘区域”内,随机抽取若干点 % 用小椭圆绘制,表示“边缘掩码”/“贴边区域”的示意。 % ================================================================ clc; clear; close all; %% (A) ============ 参数设置 ====================================== % ---------- 空间网格与楼梯尺寸 ----------- Lx = 1.0; % x方向长度(米) Ly = 0.4; % y方向长度(米) Nx = 100; % x方向网格数 Ny = 40; % y方向网格数 % ---------- 时间迭代参数 ------------- dt = 0.001; % 时间步长(可视为天/年等) Niter = 1000; % 迭代步数 % ---------- 磨损系数 ------------- alpha_bulk = 1e-5; % 普通踩踏磨损系数 alpha_edge = 2e-5; % 边缘踩踏磨损系数 % ---------- 人流量 & 指数敏感度 gamma ----------- Lambda_bulk = 800; % 普通踩踏流量 Lambda_edge = 20; % 边缘踩踏流量 gamma_val = 5.0; % 势函数敏感度 % ---------- 初始楼梯高度 ----------- H0 = 0.3; % 整个踏面初始高度(米) % ---------- 卷积核(脚印)设置(各两种) ----------- Nk = 21; % 核离散大小(odd) FootBulkAx = 0.03; % bulk脚印 x半轴 FootBulkAy = 0.015; % bulk脚印 y半轴 FootEdgeAx = 0.02; % edge脚印 x半轴 FootEdgeAy = 0.01; % edge脚印 y半轴 % ---------- 可视化间隔 ----------- ShowSteps = 100; % 每隔多少步可视化一次 % ---------- 椭圆绘制参数(在掩码图中) ----------- ellipseRx = 0.02; % 椭圆 x方向半径 ellipseRy = 0.01; % 椭圆 y方向半径 Ntheta = 40; % 椭圆绘制时的多边形分辨率 rng('shuffle'); % 随机种子 %% (B) ============ 网格、初始高度 =============================== x = linspace(0, Lx, Nx); y = linspace(0, Ly, Ny); dx = x(2) - x(1); dy = y(2) - y(1); [X, Y] = meshgrid(x,y); h = H0 * ones(Ny, Nx); % 初始楼梯高度 %% (C) ============ 定义边缘指示 E(x,y) =========================== delta_edge = 0.05; distLeft = X; distRight = Lx - X; distBottom = Y; distTop = Ly - Y; distBnd = min( min(distLeft, distRight), min(distBottom, distTop) ); % 平滑形式:E=exp(-(distBnd/delta_edge)^2) E = exp( -(distBnd / delta_edge).^2 ); % 如果想要硬阈值: E = double(distBnd<delta_edge); % 记录 E>某阈值的位置 (用于随机选取“边缘区”坐标) edgeThreshold = 0.1; % 自行设置, E值大于此阈值视为“明显边缘” maskIdx = find(E(:) > edgeThreshold); % maskIdx 将存储所有网格点的线性索引 %% (D1) =========== 两种脚印核 K_bulk, K_edge ===================== halfk = floor(Nk/2); kx = (-halfk : halfk)*dx; ky = (-halfk : halfk)*dy; [KX, KY] = meshgrid(kx, ky); % --- bulk核 --- sigma_bx = FootBulkAx/2; sigma_by = FootBulkAy/2; Kb_raw = exp( -((KX.^2)/(2*sigma_bx^2) + (KY.^2)/(2*sigma_by^2)) ); sumKb = sum(Kb_raw(:))*dx*dy; K_bulk = Kb_raw / sumKb; % --- edge核 --- sigma_ex = FootEdgeAx/2; sigma_ey = FootEdgeAy/2; Ke_raw = exp( -((KX.^2)/(2*sigma_ex^2) + (KY.^2)/(2*sigma_ey^2)) ); sumKe = sum(Ke_raw(:))*dx*dy; K_edge = Ke_raw / sumKe; %% (E) ============ 时间迭代 ====================================== figure('Name','Bulk+Edge Integral Form with Ellipses','Position',[200,100,1000,500]); thetaVec = linspace(0,2*pi,Ntheta); % 用于画椭圆 for n = 1:Niter % == (1) 定义势函数 phi & psi ================================= phi = (X-0.5*Lx).^2 + (Y-0.5*Ly).^2 + 0.2*(H0 - h); psi = 0.2*(X - 0.8*Lx).^2 + 0.5*(Y - 0.3*Ly).^2; % == (2) 计算 未归一化分布(分Bulk,Edge) ======================= Pbulk_unnorm = exp( - gamma_val * phi ); Pedge_unnorm = E .* exp( - gamma_val * psi ); % == (3) 归一化 => P_bulk, P_edge ============================ sum_bulk = sum(Pbulk_unnorm(:))*dx*dy; sum_edge = sum(Pedge_unnorm(:))*dx*dy; P_bulk = (Lambda_bulk / sum_bulk) .* Pbulk_unnorm; P_edge = (Lambda_edge / sum_edge) .* Pedge_unnorm; % == (4) 卷积求踩踏强度 T_bulk, T_edge ===================== T_bulk = conv2(P_bulk, K_bulk, 'same') * dx*dy; T_edge = conv2(P_edge, K_edge, 'same') * dx*dy; % == (5) 更新楼梯高度 h ===================================== dhdt = - alpha_bulk*T_bulk - alpha_edge*T_edge; h_new = h + dt*dhdt; h_new(h_new<0) = 0; h = h_new; % == (6) 可视化(每隔 ShowSteps 步) ========================== if (mod(n,ShowSteps)==1) || (n == Niter) % -- 左图: 显示楼梯高度 h -- subplot(1,2,1); imagesc(x,y,h); set(gca,'YDir','normal'); axis equal tight; colorbar; caxis([0,H0]); title(sprintf('Height h at step %d',n)); xlabel('x(m)'); ylabel('y(m)'); colormap(jet(256)); % -- 右图: 显示掩码+椭圆示意 -- subplot(1,2,2); % 背景可先画 E 的热力图, 或者只画空白 imagesc(x,y,E); set(gca,'YDir','normal'); axis equal tight; colormap(jet(256)); colorbar; hold on; % 椭圆数量: 取 min(n, 50) 避免过多 N_ellipses = min(n, 50); % 在 maskIdx 中随机选 N_ellipses 个点 if ~isempty(maskIdx) randIdx = randsample(maskIdx, N_ellipses, true); for i = 1:N_ellipses idxLin = randIdx(i); % 将线性索引转回行列(row,col) [row,col] = ind2sub([Ny,Nx], idxLin); xc = x(col); yc = y(row); % 画椭圆 x_ellipse = xc + ellipseRx*cos(thetaVec); y_ellipse = yc + ellipseRy*sin(thetaVec); plot(x_ellipse, y_ellipse, 'k-', 'LineWidth',1.5); end end hold off; title(sprintf('Edge Mask + %d ellipses at step %d', N_ellipses,n)); xlabel('x(m)'); ylabel('y(m)'); drawnow; end end end
在 中“边缘区域”的采样
(C)
中计算了 E
,再用 maskIdx = find(E(:) > edgeThreshold);
找出“足够靠边”(即 E>edgeThreshold
) 的网格点索引。randsample
在 maskIdx
中抽取若干点并画出椭圆。edgeThreshold
可以根据需要调大小,让“边缘区”覆盖更窄或更宽范围。每次迭代画的椭圆数量
(6)
里设定 N_ellipses = min(n, 50)
:即随着迭代步数 n
增加,椭圆数也增加,但最多不超过 50。n
能很大,这会非常耗时,并且图里会满屏椭圆。请谨慎设置。椭圆的形状
thetaVec
,再由 (xc+Rx*cosθ, yc+Ry*sinθ)
绘制。thetaRotation = 2*pi*rand()
并在坐标里做旋转变换。只在可视化步骤
if (mod(n,ShowSteps)==1) || (n==Niter)
里做绘图,所以不是每一步都画椭圆,否则会极度耗时。ShowSteps=100
意味着每 100 步才绘一次。您可根据需要调大/调小。这样就可同时看到楼梯高度(左)与边缘掩码(叠加椭圆)(右)随时间演化的情况。若“掩码出现故障”通常是因为在循环中不断创建新 figure 或未正确 hold on/off
,现已修正。您可根据需要进一步调整阈值、椭圆大小、绘图频率等。祝研究顺利!