MWORKS如何进行曼德勃罗集合的动态可视化分析?我在MoHub上找到了了一个基于MWORKS Syslab的曼德勃罗集合动态可视化案例,用Julia实现了逃逸时间算法,把复杂的分形结构一步步、一帧帧地显示出来。
曼德勃罗集合是复平面上的经典分形,边界极其复杂,只用一张静态图很难看懂它是怎样“生长”出来的。借助MWORKS Syslab,我把“迭代次数递增”“分辨率逐级细化”“局部放大”三种过程做成了动态可视化,并在真实运行后核对了结果数据。
本文分享这个案例的算法、脚本与运行结果。
一、案例解决什么问题
曼德勃罗集合描述的是复平面上这样一类复数c:从z0=0出发,反复做:

这一迭代,序列始终有界(不会跑到无穷远)。满足这个条件的c组成的点集,就是曼德勃罗集合。
直观上它是一张带彩边的分形图:集合内的点涂成黑色,集合外的点按“逃逸速度”着色。
但它真正的难点有三点:
(1)每一个像素对应一个复数c,都要独立做最多maxIter次迭代,计算量大。
(2)边界结构在任意尺度下都不会变简单,需要足够的分辨率才能看清细节。
(3)“从模糊到清晰”“从整体到局部”的过程,静态图无法体现。
本案例要解决的,就是在MWORKS Syslab里用一种高效(向量化)的方式画出曼德勃罗集合,并通过三种动态模式把“迭代递增”“分辨率细化”“局部缩放”的过程可视化出来,同时导出PNG图片和GIF动画。
二、MWORKS Syslab中的脚本
案例推荐主运行文件是:
case\\mandelbrot_dynamic_visualization_share.jl
这是分享版,中文注释完整,适合演示。
它依赖MWORKS Syslab自带的三个库:
(1)TyBase:基础工具。
(2)TyImages:图像读写与处理。
(3)TyPlot:绘图与动态图窗。
脚本顶部集中了所有可调参数:
(1)复平面窗口:实轴x从-2.0到1.0,虚轴y从-1.5到1.5。
(2)网格分辨率:width=1000,height=1000。
(3)最大迭代次数:maxIter=200。
(4)逃逸半径:escapeRadius=2.0。
(5)动态模式:dynamicMode可由环境变量MANDELBROT_DYNAMIC_MODE指定为“iteration”“resolution”“zoom”三种。
脚本通过MANDELBROT_DYNAMIC_MODE环境变量切换三种模式,用TyPlot的动态图窗逐帧绘制,并导出静态PNG与动态GIF。
核心代码1:逃逸时间算法
这段函数是整件事的核心,它按“活跃集合”掩码方式做向量化迭代,避免对每个点单独写内层循环:
function compute_escape_matrix(xmin,xmax,ymin,ymax,width,height,maxIter,escapeRadius)
xs = collect(LinRange(xmin,xmax,width))
ys = collect(LinRange(ymin,ymax,height))
complexGrid = vec([ComplexF64(x,y) for y in ys, x in xs])
activeIndex = collect(eachindex(complexGrid))
activeC = copy(complexGrid)
activeZ = zeros(ComplexF64, length(complexGrid))
escapeIter = zeros(Int32, length(complexGrid))
escapeRadiusSq = escapeRadius^2
for iter in 1:maxIter
isempty(activeIndex) && break
activeZ .= activeZ .* activeZ .+ activeC
keepMask = abs2.(activeZ) .<= escapeRadiusSq
escapedNow = .!keepMask
if any(escapedNow)
escapeIter[activeIndex[escapedNow]] .= iter
end
activeIndex = activeIndex[keepMask]
activeC = activeC[keepMask]
activeZ = activeZ[keepMask]
end
reshape(escapeIter, height, width)
end
代码解释:输入是复平面范围、网格尺寸、最大迭代次数、逃逸半径。它先建立complexGrid(每个像素一个复数c),然后反复执行z=z*z+c,用abs2(z)<=escapeRadius^2判断是否“仍有界”。
凡是本次超过逃逸半径的点,记录下它此时已经迭代的次数,并从后续计算中移除(这就是active set优化)。
输出是一个height×width的矩阵,元素是每个像素第一次逃逸时的迭代次数,这个矩阵直接决定最终的着色。
核心代码2:把迭代次数变成颜色
function escape_to_image(escapeIter, currentIter)
frameData = zeros(Float64, size(escapeIter))
escapedMask = escapeIter .> 0
if any(escapedMask)
frameData[escapedMask] .= log1p.(Float64.(escapeIter[escapedMask])) ./ log1p(currentIter)
end
return frameData
end
代码解释:输入的escapeIter矩阵里,集合内部点(始终有界)的逃逸迭代次数为0,集合外部点为早期逃逸的迭代次数。
这里用log1p做对数压缩,让逃逸迭代次数较小的点也能被分辨出来,再除以log1p(currentIter)归一化到0到1,交给imagesc的hot色图显示。
结果就是黑色集合加彩色边界带。
核心代码3:控制三种动态模式
if selectedMode == "iteration"
# 只计算一次,每到指定迭代次数就刷新一帧
elseif selectedMode == "resolution"
# 每种分辨率下重新计算整幅图
else
# 用平滑插值逐步改变观察窗口(局部缩放)
end
代码解释:iteration模式只计算一次,每到指定迭代次数就刷新一帧;resolution模式在每种分辨率下重新计算整幅图;zoom模式用平滑插值逐步改变观察窗口。
三种模式分别对应“边界越来越清晰”“图像越来越精细”“视线越来越深入”三种动态效果。
三、核心计算原理
(1)迭代公式
曼德勃罗集合由:

定义。
对每个像素代表的c,若迭代maxIter次后|z|始终不超过逃逸半径(这里是2.0),就把这个c算作“集合内部”,着色为黑;否则记录它首次超过逃逸半径时的迭代次数,作为“集合外部”的逃逸速度。
逃逸判断为:

(2)动态模式
iteration:
从10次迭代逐步增加到200次,边界随迭代加深而变清晰。
resolution:
分辨率从80×80逐步细化到1000×1000,图像越来越精细。
zoom:
从全局[-2,1]×[-1.5,1.5]平滑缩放到经典“海马谷”区域(约实轴-0.753~-0.734,虚轴0.121~0.140),用smoothstep曲线让缩放过程更自然。
(3)性能技巧
脚本对1000×1000×200迭代的规模,采用“活跃集合”掩码向量化写法:只对尚未逃逸的点继续迭代,并把逃逸点从工作数组中移除。
这比逐像素内层循环快得多,也让MWORKS Syslab能在可接受时间内完成动画。
四、实际运行结果
我在本机MWORKS Syslab 26.6.1(Julia 1.10.10)下,用julia-ty运行了分享版脚本,并通过环境变量分别跑通了三个模式。
三个模式都成功导出PNG和GIF。
运行记录(关键数值):
(1)iteration模式:帧数20,迭代序列为[10,20,30,…,200],画布窗口始终为[-2,1]×[-1.5,1.5],最终PNG与仓库自带结果文件字节数一致。
(2)resolution模式:帧数8,分辨率序列为:
80×80 → 120×120 → 180×180 → 250×250 → 350×350 → 500×500 → 700×700 → 1000×1000
(3)zoom模式:帧数8,观察窗口从全局[-2,1]×[-1.5,1.5]平滑过渡到海马谷[-0.753,-0.734]×[0.121,0.140],最后脚本按设计恢复到初始全图。
图1 MWORKS Syslab曼德勃罗集合整体可视化结果
横轴为复平面实轴(Real Axis),纵轴为虚轴(Imaginary Axis),覆盖范围约[-2,1]×[-1.5,1.5];黑色区域是集合内部(迭代200次仍不逃逸),彩色区域按逃逸迭代次数着色,越靠近边界颜色越亮。
这是1000×1000分辨率、最大迭代200次的最终结果。
图2 曼德勃罗集合海马谷局部放大
这是zoom模式缩放到经典“海马谷”区域(实轴约-0.753~-0.734,虚轴约0.121~0.140)后的细节,1000×1000分辨率、最大迭代200次。
可以看到边界铺满了细密的、类似海马尾巴的螺旋结构,这正是曼德勃罗集合“自相似、无限精细”的体现。
图3 曼德勃罗集合低分辨率(80×80)结果
与图1对比,同样是最大迭代200次,但网格只有80×80,边界明显呈锯齿状、细节丢失。
这张图用于说明分辨率细化模式的意义:同样的算法,分辨率越高边界越精细,这就是“分辨率从低到高动态呈现”的价值。
三种模式配套的GIF动画记录了完整动态过程:迭代模式下边界随迭代加深逐渐清晰;分辨率模式下图像由粗到细成型;缩放模式下视线平滑深入海马谷。
五、关键数值核对
我把“运行输出”和“结果图”做了核对(这也是本案例本次复查的重点):
(1)迭代次数与帧数:iteration模式输出20帧,迭代序列从10到200,与代码iterationStart=10、iterationStep=10一致;不会出现图中的迭代次数与正文不符的情况。
(2)分辨率序列:resolution模式输出8帧,分辨率从80×80递增到1000×1000,与resolutionScales=0.08~1.00一致。
(3)缩放目标:zoom模式8帧,目标区域为海马谷[-0.753,-0.734]×[0.121,0.140],与代码zoomXmin等参数一致;最后一帧按returnToOverviewAtEnd=true恢复初始全图,因此分享版zoom的最终PNG是整体视图,而模块化版本(不做恢复)的zoom最终PNG是海马谷近景——两者不同是有意设计,不是bug。
(4)逃逸迭代范围:整体视图下逃逸迭代次数在0~200之间(集合内部为0,边界附近接近200);80×80低分辨率下最大逃逸迭代为191(网格稀疏,采样点较难逼近需要高迭代的边界点);海马谷近景下为0~200。
这些数值说明图1、图2、图3的着色差异不是错误,而是分辨率与区域不同带来的真实差异,图与数值一致。
六、参数变化还能观察什么
在脚本参数区改动下面任意一项,重新运行时可以观察到不同的行为:
(1)改大maxIter(从200到500)
边界细节更丰富,但计算时间上升;适合在局部放大后进一步欣赏细节。
(2)改小maxIter(如50)
边界变模糊、锯齿明显,适合快速预览。
(3)改动分辨率width/height
直接改变图像精细度,分辨率越低越“像素化”。
(4)换缩放目标
修改zoomXmin、zoomXmax、zoomYmin、zoomYmax这四个坐标,可以放大到其他经典区域,例如“大象谷”。
只需改这四个坐标即可。
(5)换色图(cmap)
改成“magma”“viridis”等,能得到不同配色风格,不影响数据和结论。
七、模型适用范围与局限
必须说明的是,这是一个教学与演示性质的数值可视化案例,用它来做严格数学判定或工程验证是不合适的。
(1)逃逸时间算法是近似
曼德勃罗集合是“无限迭代仍保持有界”的点的集合,任何有限maxIter(这里是200)都只是近似。
真正的边界点可能迭代次数远大于200甚至永远不逃逸,会被误判为集合内部。
(2)分辨率是有限精度的近似
1000×1000只是离散采样,边界上“无限精细”的结构永远无法被有限网格完全表达。
(3)颜色映射仅用于可视化
用log1p归一化颜色是为了可视化,不代表任何物理或工程量。
(4)本案例不是物理或工程模型
不能替代任何工程验证、计算或安全判断。
(5)动态可视化只是计算过程展示
“动态可视化”呈现的是计算过程,不代表算法结果的全局最优或其他工程结论。
八、总结
这个案例展示了如何在MWORKS Syslab里用Julia高效实现曼德勃罗集合的逃逸时间算法,并通过“迭代递增”“分辨率细化”“局部放大”三种模式把它做成动态可视化。
核心是把逃逸迭代次数这个矩阵准确算出来,再用颜色映射成图;再通过活跃集合掩码的向量化写法,让1000×1000×200的规模在可接受时间内跑完。
实际运行核对了帧数、迭代序列、分辨率序列、缩放坐标与逃逸迭代范围,图与数值一致。
它很适合作为理解分形、学习Julia向量化与TyPlot动态图窗的入门案例。
本文使用的MWORKS Syslab曼德勃罗集合动态可视化案例可在MoHub查看,案例页面提供相关模型、脚本及运行文件:
案例地址:
基于Syslab的曼德勃罗集合动态可视化案例 – 详情 – MoHub
本案例实际运行环境为MWORKS Syslab 26.6.1、Julia 1.10.10,依赖TyBase、TyImages、TyPlot。文中所引用的数值与图片均来自我在该环境下的真实运行结果与源码计算结果。
网硕互联帮助中心





评论前必须登录!
注册