开源鸿蒙跨平台Flutter开发:量子态波函数坍缩系统-波动力学与概率云渲染架构
摘要: 本文基于量子力学哥本哈根诠释,在Flutter跨平台框架下实现了薛定谔方程时域演化的可视化仿真。通过求解一维无限深势阱中的本征态叠加,在前端设备实时计算复值波函数,并利用GPU光栅化渲染概率云与波函数坍缩现象。系统采用状态机隔离UI层与物理层,通过蒙特卡洛抽样模拟量子观测过程,实现了从概率云到粒子定位的平滑过渡。该工作展示了移动端跨平台技术进行高级物理仿真的可行性,为量子力学教学提供了可视
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
示例效果



摘要
在量子力学的哥本哈根诠释中,微观粒子在被观测之前并不存在一个确定的位置,而是以一种“概率云”的叠加态分布在空间中;当进行观测的瞬间,波函数发生坍缩,粒子瞬间出现在某一个确定点上。本文在 Flutter 的跨平台图形管线上,挑战了对薛定谔方程(Schrödinger equation)进行时域演化可视化。通过求解一维无限深势阱中的本征态叠加,我们在前端设备中硬计算出了复值波函数的实部与概率密度矩阵,并利用 CustomPaint 在 GPU 光栅层还原了极其诡异且美丽的概率云(Probability Cloud)与波函数坍缩(Wave Function Collapse)现象。这篇架构论文旨在揭示移动端跨平台技术在高级物理学仿真领域的降维打击能力。
1. 薛定谔方程与波动力学基础
要在一台手机上构建量子态控制台,我们必须首先对微观系统建立数学模型。在此系统里,我们模拟一个长为 L L L 的一维无限深势阱(1D Infinite Potential Well)。
1.1 一维势阱本征态函数
在该势阱中,处于特定能级 n n n 的本征态波函数(定态波函数)只由空间坐标 x x x 决定,其表达式为:
ψ n ( x ) = 2 L sin ( n π x L ) \psi_n(x) = \sqrt{\frac{2}{L}} \sin\left(\frac{n \pi x}{L}\right) ψn(x)=L2sin(Lnπx)
其对应的能级能量 E n E_n En 表现为阶梯式的离散值。由德布罗意关系可知,它的演化角频率 ω n \omega_n ωn 随着 n 2 n^2 n2 呈指数级增长:
ω n = E n ℏ = n 2 ω 1 \omega_n = \frac{E_n}{\hbar} = n^2 \omega_1 ωn=ℏEn=n2ω1
1.2 叠加态与含时演化
量子系统不仅能处于单一本征态,更重要的是它能处于多个本征态的叠加之中。在此仪器中,我们赋予了系统两个本征态 ψ n 1 \psi_{n_1} ψn1 和 ψ n 2 \psi_{n_2} ψn2,并通过混合角 θ \theta θ 控制它们的混合比例 ∣ c 1 ∣ 2 |c_1|^2 ∣c1∣2 和 ∣ c 2 ∣ 2 |c_2|^2 ∣c2∣2。含时的复波函数 Ψ ( x , t ) \Psi(x,t) Ψ(x,t) 描述如下:
Ψ ( x , t ) = cos ( θ ) ψ n 1 ( x ) e − i ω 1 t + sin ( θ ) ψ n 2 ( x ) e − i ω 2 t \Psi(x,t) = \cos(\theta) \psi_{n_1}(x) e^{-i\omega_1 t} + \sin(\theta) \psi_{n_2}(x) e^{-i\omega_2 t} Ψ(x,t)=cos(θ)ψn1(x)e−iω1t+sin(θ)ψn2(x)e−iω2t
在这个含时的波函数中,不仅每一个分态有自己的振荡频率,它们之间还会产生干涉项(Interference Term)。
1.3 概率密度的玻恩律(Born Rule)
我们在屏幕底部渲染的“概率云热力图”,并非波函数本身,而是它的模平方 ∣ Ψ ( x , t ) ∣ 2 |\Psi(x,t)|^2 ∣Ψ(x,t)∣2:
∣ Ψ ( x , t ) ∣ 2 = cos 2 ( θ ) ψ n 1 2 + sin 2 ( θ ) ψ n 2 2 + 2 cos ( θ ) sin ( θ ) ψ n 1 ψ n 2 cos ( ( ω 2 − ω 1 ) t ) |\Psi(x,t)|^2 = \cos^2(\theta) \psi_{n_1}^2 + \sin^2(\theta) \psi_{n_2}^2 + 2 \cos(\theta)\sin(\theta) \psi_{n_1} \psi_{n_2} \cos((\omega_2 - \omega_1)t) ∣Ψ(x,t)∣2=cos2(θ)ψn12+sin2(θ)ψn22+2cos(θ)sin(θ)ψn1ψn2cos((ω2−ω1)t)
公式中的 cos ( ( ω 2 − ω 1 ) t ) \cos((\omega_2 - \omega_1)t) cos((ω2−ω1)t) 正是导致概率云随时间发生流体状振荡、呼吸与拍频的核心数学根源。
2. 量子系统状态机域建模
要承载上述复杂的复数计算与极速 60fps 重绘,UI 层与物理层的隔离必须达到绝对彻底。
2.1 系统架构依赖域模型
我们利用 UML 图剥离了状态调度器和波函数绘制渲染器的关系:
2.2 波函数坍缩事件瀑布流
最致命的逻辑在于“施加观测”按钮被按下的瞬间。系统必须按照量子力学的规则掷出蒙特卡洛骰子:
3. 极客波动力学核心代码剖析
本节我们将深剖四个具有跨界深度的代码片段,看 Flutter 是如何徒手搓出一个量子计算机的显示端的。
3.1 _observeAndCollapse:量子蒙特卡洛抽样发生器
这并非一个普通的 Random,这是一个完全被物理学方程强行扭曲权重的骰子。概率云越密集的坐标,其掷出的命中率越高。
void _observeAndCollapse() {
if (_isCollapsed) return;
// 1. 构建当前的概率密度分布 PDF
const int resolution = 1000;
List<double> pdf = List.filled(resolution, 0.0);
double sum = 0.0;
double omega1 = _baseOmega * _n1 * _n1;
double omega2 = _baseOmega * _n2 * _n2;
for (int i = 0; i < resolution; i++) {
double x = i / resolution;
double psi1 = math.sqrt(2.0) * math.sin(_n1 * math.pi * x);
double psi2 = math.sqrt(2.0) * math.sin(_n2 * math.pi * x);
double cosTheta = math.cos(_theta);
double sinTheta = math.sin(_theta);
// |Psi|^2 概率密度计算
double prob = math.pow(cosTheta * psi1, 2) +
math.pow(sinTheta * psi2, 2) +
2 * cosTheta * sinTheta * psi1 * psi2 * math.cos((omega2 - omega1) * _time);
pdf[i] = prob;
sum += prob;
}
// 2. 依据 PDF 进行加权随机抽样 (模拟量子蒙特卡洛掷骰子)
double rand = math.Random().nextDouble() * sum;
double acc = 0.0;
int collapseIndex = resolution ~/ 2;
for (int i = 0; i < resolution; i++) {
acc += pdf[i];
if (acc >= rand) {
collapseIndex = i;
break;
}
}
setState(() {
_isCollapsed = true;
_collapsedPosition = collapseIndex / resolution;
});
_collapseController.forward(from: 0.0);
}
解剖:
这里完美复现了哥本哈根概率坍缩理论。我们把一维空间截断成 1000 份,算出每一份的瞬时振幅 prob 作为累加权重 sum。这使得在屏幕上概率云发亮(振幅高)的位置,有极大的可能成为粒子现身的位置;而干涉相消(暗区)几乎永远不会掷出粒子。
3.2 坍缩态狄拉克 δ \delta δ 函数平滑过渡
当发生观测时,弥散的波函数要坍缩成一个实点。在数学上这是一个突变,但在视觉上我们通过插值(Lerp)实现了高斯聚拢。
// --- 坍缩态物理插值 ---
if (isCollapsed) {
// 构建狄拉克 \delta 函数的近似 Gaussian
double deltaSigma = 0.01;
double gaussian = (1.0 / (deltaSigma * math.sqrt(2 * math.pi))) *
math.exp(-math.pow(x - collapsedPosition, 2) / (2 * math.pow(deltaSigma, 2)));
// 归一化缩放
gaussian = gaussian * 0.05;
// 插值计算
// collapseProgress 从 0 到 1 时,波形从薛定谔演化逐渐变成高斯窄峰
double easeProgress = _easeInOutExpo(collapseProgress);
// 坍缩时的振幅快速收敛
rePsi = rePsi * (1.0 - easeProgress) + (gaussian * math.cos(omega1 * time * 5)) * easeProgress;
prob = prob * (1.0 - easeProgress) + gaussian * easeProgress * 15.0; // 高度补偿
}
解剖:
真正的 δ \delta δ 函数宽度为0且高度无穷大,我们退而求其次构建了一个方差 deltaSigma = 0.01 的尖锐高斯波峰 gaussian。当 collapseProgress 由 0 → 1 0 \to 1 0→1 推移时,我们运用极为残暴的非线性方程 _easeInOutExpo 把 rePsi 和 prob 强行拉向这个高斯峰,营造出“空间概率向奇点坍缩”的恐怖物理拉扯感。
3.3 概率热力云的二维立柱渲染
对于一维量子态,它的概率云在 Y 轴上只是一个标量。我们要将其转化为具有光圈效应的赛博光栅流。
// 2. 绘制概率云 (Probability Cloud)
// 将一维概率扩展为二维视觉热力发光柱
final Paint probPaint = Paint();
for (int i = 0; i < probabilityPoints.length; i++) {
double px = probabilityPoints[i].dx;
double prob = probabilityPoints[i].dy;
// 依据进度混合
Color mixColor = Color.lerp(const Color(0xFF00FFCC), Colors.redAccent, isCollapsed ? collapseProgress : 0)!;
probPaint.color = mixColor.withValues(alpha: math.min(1.0, prob * 0.4));
probPaint.strokeWidth = dx * 1.5;
// 画光晕立柱
canvas.drawLine(
Offset(px, cloudCenterY),
Offset(px, cloudCenterY - prob * 80),
probPaint
);
}
解剖:
放弃了连续画线,这里直接用密集的离散柱 drawLine 构建光带。利用计算得到的 prob (概率密度) 决定了笔刷立柱的高度和 Alpha 通道 prob * 0.4,因此大概率区会表现出极度明亮且高耸的青色能量墙。而坍缩进度发生时,Color.lerp 会把这片生机勃勃的干涉云瞬间染成血腥的致命红色。
3.4 波函数曲线的双通道发光截取
在上方绘制波函数的实部空间,我们需要体现出一种量子波特有的“能量流溢”感。
// 3. 绘制实部波函数 Re(Psi)
// 添加外发光
canvas.drawPath(wavePath, Paint()
..color = (isCollapsed ? Colors.redAccent : const Color(0xFFFF00FF)).withValues(alpha: 0.4)
..style = PaintingStyle.stroke
..strokeWidth = 6
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 8));
// 实体线
canvas.drawPath(wavePath, Paint()
..color = isCollapsed ? Colors.white : const Color(0xFFFF00FF)
..style = PaintingStyle.stroke
..strokeWidth = 2
..strokeJoin = StrokeJoin.round);
解剖:
这里采用了图形学领域经典的“霓虹灯管线”(Neon Tubing)绘制法。第一遍使用粗线宽与 MaskFilter.blur 将路径发散,制造周围介质被激发的视错觉;第二遍使用没有任何模糊的细线并设置为更高亮度的核心色重新走线,从而勾勒出那道在无限深势阱中疯狂甩动的波动力学光波。
4. 控制台数据参数空间对照分析
左侧仪表的滑动槽不只是简单的控制项,它是连接数学和可见视觉的神经突触。
| 参数物理意义 | 数据符号 | UI色彩标识 | 波函数方程影响效应 |
|---|---|---|---|
| 基态主量子数 | n 1 n_1 n1 | Colors.cyan |
决定第一组本征波的空间频率(波包数目) |
| 激发态主量子数 | n 2 n_2 n2 | Colors.purpleAccent |
决定混入的高能本征波频率,导致更高频干涉项 |
| 叠加态混合角 | θ \theta θ | Colors.limeAccent |
控制 cos θ \cos\theta cosθ 与 sin θ \sin\theta sinθ,调节权重占比 |
| 干涉拍频 | Δ ω \Delta\omega Δω | HUD面板数据 |
正比于 n 2 2 − n 1 2 n_2^2 - n_1^2 n22−n12,数值越大下方概率云呼吸震荡越快 |
| 波函数崩塌 | - | Colors.red |
随机截取 δ \delta δ 函数位点,毁灭以上所有状态演化 |
5. 结语
物理学从来不仅仅局限于纸面推导与庞杂的超算系统。当我们在移动端或者桌面应用上,用跨平台 UI 框架手撕微积分方程、将波函数坍缩与高斯平滑插值糅合在一起时,Flutter 所暴露出来的巨大渲染吞吐能力足以让人惊叹。这台由一维无限深势阱、 Born 概率测度以及哥本哈根观测机制构成的袖珍控制台,证明了应用层图形引擎能够作为探索极其前沿科学问题的绝佳容器。未来的科学可视化,将在指尖上直接剥离微观世界的奥秘!
源码
import 'dart:math' as math;
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const QuantumCollapseApp());
}
class QuantumCollapseApp extends StatelessWidget {
const QuantumCollapseApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Quantum Wave Function Console',
debugShowCheckedModeBanner: false,
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: const Color(0xFF020205),
colorScheme: const ColorScheme.dark(
primary: Color(0xFF00FFCC),
secondary: Color(0xFFFF00FF),
surface: Color(0xFF080812),
),
),
home: const QuantumConsoleScreen(),
);
}
}
class QuantumConsoleScreen extends StatefulWidget {
const QuantumConsoleScreen({super.key});
@override
State<QuantumConsoleScreen> createState() => _QuantumConsoleScreenState();
}
class _QuantumConsoleScreenState extends State<QuantumConsoleScreen> with TickerProviderStateMixin {
late AnimationController _timeController;
late AnimationController _collapseController;
// 核心量子态参数
double _n1 = 1.0; // 基态主量子数
double _n2 = 2.0; // 激发态主量子数
double _theta = math.pi / 4; // 叠加态混合角 (默认 50/50 混合)
// 物理时间与频率映射
double _time = 0.0;
final double _baseOmega = 2.0; // 基础角频率
// 观测坍缩参数
bool _isCollapsed = false;
double _collapsedPosition = 0.5;
@override
void initState() {
super.initState();
_timeController = AnimationController(
vsync: this,
duration: const Duration(seconds: 10),
)..repeat();
_timeController.addListener(() {
if (!_isCollapsed) {
setState(() {
_time += 0.016; // 维持物理时间流逝
});
}
});
_collapseController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
);
_collapseController.addListener(() {
setState(() {});
});
_collapseController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// 坍缩结束,恢复薛定谔演化
setState(() {
_isCollapsed = false;
});
_collapseController.reset();
}
});
}
@override
void dispose() {
_timeController.dispose();
_collapseController.dispose();
super.dispose();
}
// 哥本哈根诠释:测量导致波函数概率云坍缩
void _observeAndCollapse() {
if (_isCollapsed) return;
// 1. 构建当前的概率密度分布 PDF
const int resolution = 1000;
List<double> pdf = List.filled(resolution, 0.0);
double sum = 0.0;
double omega1 = _baseOmega * _n1 * _n1;
double omega2 = _baseOmega * _n2 * _n2;
for (int i = 0; i < resolution; i++) {
double x = i / resolution;
double psi1 = math.sqrt(2.0) * math.sin(_n1 * math.pi * x);
double psi2 = math.sqrt(2.0) * math.sin(_n2 * math.pi * x);
double cosTheta = math.cos(_theta);
double sinTheta = math.sin(_theta);
// |Psi|^2 概率密度计算
double prob = math.pow(cosTheta * psi1, 2) +
math.pow(sinTheta * psi2, 2) +
2 * cosTheta * sinTheta * psi1 * psi2 * math.cos((omega2 - omega1) * _time);
pdf[i] = prob;
sum += prob;
}
// 2. 依据 PDF 进行加权随机抽样 (模拟量子蒙特卡洛掷骰子)
double rand = math.Random().nextDouble() * sum;
double acc = 0.0;
int collapseIndex = resolution ~/ 2;
for (int i = 0; i < resolution; i++) {
acc += pdf[i];
if (acc >= rand) {
collapseIndex = i;
break;
}
}
setState(() {
_isCollapsed = true;
_collapsedPosition = collapseIndex / resolution;
});
_collapseController.forward(from: 0.0);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
// 左侧:实验参数控制台
Container(
width: 360,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
border: const Border(right: BorderSide(color: Colors.white10, width: 2)),
),
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('薛定谔波函数测绘仪', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white)),
const SizedBox(height: 6),
const Text('SCHRÖDINGER PROBABILITY CLOUD', style: TextStyle(fontSize: 10, color: Color(0xFF00FFCC), letterSpacing: 2.0)),
const Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Divider(height: 1, color: Colors.white12),
),
_buildSlider('本征态 \u03A8\u2081 量子数 (n\u2081)', _n1, 1.0, 5.0, (v) => setState(() => _n1 = v.roundToDouble()), '', Colors.cyan),
_buildSlider('本征态 \u03A8\u2082 量子数 (n\u2082)', _n2, 1.0, 8.0, (v) => setState(() => _n2 = v.roundToDouble()), '', Colors.purpleAccent),
_buildSlider('叠加态混合角 (\u03B8)', _theta, 0.0, math.pi / 2, (v) => setState(() => _theta = v), 'rad', Colors.limeAccent),
const Spacer(),
// HUD 实时读数
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.black38,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFF00FFCC).withValues(alpha: 0.3)),
boxShadow: [
BoxShadow(color: const Color(0xFF00FFCC).withValues(alpha: 0.05), blurRadius: 10, spreadRadius: 2)
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.remove_red_eye_outlined, size: 16, color: Color(0xFF00FFCC)),
SizedBox(width: 8),
Text('波动力学测算矩阵', style: TextStyle(color: Colors.white70, fontSize: 13, fontWeight: FontWeight.bold)),
],
),
const SizedBox(height: 16),
_buildTelemetryRow('\u03A8\u2081 概率权重 |C\u2081|\u00B2', '${(math.pow(math.cos(_theta), 2) * 100).toStringAsFixed(1)} %'),
_buildTelemetryRow('\u03A8\u2082 概率权重 |C\u2082|\u00B2', '${(math.pow(math.sin(_theta), 2) * 100).toStringAsFixed(1)} %'),
_buildTelemetryRow('干涉项频率 \u0394\u03C9', '${(_baseOmega * math.pow(_n2, 2) - _baseOmega * math.pow(_n1, 2)).toStringAsFixed(2)} rad/s'),
_buildTelemetryRow('观测态 (Observation)', _isCollapsed ? 'COLLAPSED' : 'SUPERPOSITION', valueColor: _isCollapsed ? Colors.redAccent : const Color(0xFF00FFCC)),
],
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: _isCollapsed ? Colors.grey[800] : const Color(0xFFFF00FF),
foregroundColor: Colors.white,
elevation: _isCollapsed ? 0 : 12,
shadowColor: const Color(0xFFFF00FF).withValues(alpha: 0.5),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
onPressed: _isCollapsed ? null : _observeAndCollapse,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(_isCollapsed ? Icons.visibility_off : Icons.visibility, size: 20),
const SizedBox(width: 8),
Text(_isCollapsed ? '波函数已坍缩' : '施加观测 (坍缩)', style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold, letterSpacing: 1.2)),
],
),
),
),
],
),
),
// 右侧:概率云与波函数渲染域
Expanded(
child: Container(
color: const Color(0xFF010103),
child: Stack(
children: [
// 1D 一维无限深势阱波函数视图
Positioned.fill(
child: CustomPaint(
painter: QuantumWavePainter(
n1: _n1,
n2: _n2,
theta: _theta,
time: _time,
baseOmega: _baseOmega,
isCollapsed: _isCollapsed,
collapsedPosition: _collapsedPosition,
collapseProgress: _collapseController.value,
),
),
),
// 物理背景说明
Positioned(
top: 24,
left: 24,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: Colors.black54,
border: Border.all(color: Colors.white12),
borderRadius: BorderRadius.circular(8),
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('一维无限深势阱 (1D Infinite Potential Well)', style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold)),
SizedBox(height: 4),
Text('上层:Re(\u03A8) 实部波形 | 下层:|\u03A8|\u00B2 概率云密度', style: TextStyle(color: Colors.white54, fontSize: 12)),
],
),
),
),
],
),
),
),
],
),
);
}
Widget _buildSlider(String label, double value, double min, double max, ValueChanged<double> onChanged, String unit, Color color) {
return Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(color: Colors.white70, fontSize: 13)),
Text('${value.toStringAsFixed(2)} $unit', style: TextStyle(color: color, fontWeight: FontWeight.bold, fontFamily: 'monospace')),
],
),
const SizedBox(height: 8),
SliderTheme(
data: SliderThemeData(
activeTrackColor: color,
inactiveTrackColor: color.withValues(alpha: 0.15),
thumbColor: color,
overlayColor: color.withValues(alpha: 0.2),
trackHeight: 3,
),
child: Slider(
value: value,
min: min,
max: max,
onChanged: _isCollapsed ? null : onChanged, // 坍缩态锁定参数
),
),
],
),
);
}
Widget _buildTelemetryRow(String label, String value, {Color? valueColor}) {
return Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(color: Colors.white54, fontSize: 13)),
Text(value, style: TextStyle(color: valueColor ?? const Color(0xFF00FFCC), fontSize: 15, fontFamily: 'monospace', fontWeight: FontWeight.bold)),
],
),
);
}
}
class QuantumWavePainter extends CustomPainter {
final double n1;
final double n2;
final double theta;
final double time;
final double baseOmega;
final bool isCollapsed;
final double collapsedPosition;
final double collapseProgress;
QuantumWavePainter({
required this.n1,
required this.n2,
required this.theta,
required this.time,
required this.baseOmega,
required this.isCollapsed,
required this.collapsedPosition,
required this.collapseProgress,
});
@override
void paint(Canvas canvas, Size size) {
final double width = size.width;
final double height = size.height;
// 绘图区域分割
final double waveCenterY = height * 0.35;
final double cloudCenterY = height * 0.8;
// 能量角频率
final double omega1 = baseOmega * n1 * n1;
final double omega2 = baseOmega * n2 * n2;
// 阻尼系数 (用于模拟坍缩过程)
// collapseProgress (0 -> 1)
// 如果处于叠加态,阻尼为0
final int resolution = 500;
final double dx = width / resolution;
final wavePath = Path();
final envelopePath = Path();
List<Offset> probabilityPoints = [];
bool isFirst = true;
for (int i = 0; i < resolution; i++) {
double x = i / resolution; // 归一化空间坐标 0 -> 1
// 空间本征函数
double psi1 = math.sqrt(2.0) * math.sin(n1 * math.pi * x);
double psi2 = math.sqrt(2.0) * math.sin(n2 * math.pi * x);
double cosTheta = math.cos(theta);
double sinTheta = math.sin(theta);
// 含时波函数实部 (Re)
double rePsi = cosTheta * psi1 * math.cos(omega1 * time) +
sinTheta * psi2 * math.cos(omega2 * time);
// 概率密度 |Psi|^2
double prob = math.pow(cosTheta * psi1, 2) +
math.pow(sinTheta * psi2, 2) +
2 * cosTheta * sinTheta * psi1 * psi2 * math.cos((omega2 - omega1) * time);
// --- 坍缩态物理插值 ---
if (isCollapsed) {
// 构建狄拉克 \delta 函数的近似 Gaussian
double deltaSigma = 0.01;
double gaussian = (1.0 / (deltaSigma * math.sqrt(2 * math.pi))) *
math.exp(-math.pow(x - collapsedPosition, 2) / (2 * math.pow(deltaSigma, 2)));
// 归一化缩放
gaussian = gaussian * 0.05;
// 插值计算
// collapseProgress 从 0 到 1 时,波形从薛定谔演化逐渐变成高斯窄峰
double easeProgress = _easeInOutExpo(collapseProgress);
// 坍缩时的振幅快速收敛
rePsi = rePsi * (1.0 - easeProgress) + (gaussian * math.cos(omega1 * time * 5)) * easeProgress;
prob = prob * (1.0 - easeProgress) + gaussian * easeProgress * 15.0; // 高度补偿
}
// 映射到屏幕坐标系
double screenX = x * width;
double screenY = waveCenterY - rePsi * 80.0;
double probY = cloudCenterY - prob * 60.0;
if (isFirst) {
wavePath.moveTo(screenX, screenY);
envelopePath.moveTo(screenX, probY);
isFirst = false;
} else {
wavePath.lineTo(screenX, screenY);
envelopePath.lineTo(screenX, probY);
}
probabilityPoints.add(Offset(screenX, prob));
}
// 1. 绘制无限深势阱边界
final borderPaint = Paint()
..color = Colors.white24
..style = PaintingStyle.stroke
..strokeWidth = 2;
canvas.drawLine(Offset(0, waveCenterY - 150), Offset(0, cloudCenterY + 50), borderPaint);
canvas.drawLine(Offset(width, waveCenterY - 150), Offset(width, cloudCenterY + 50), borderPaint);
// 0轴线
canvas.drawLine(Offset(0, waveCenterY), Offset(width, waveCenterY), Paint()..color = Colors.white10..strokeWidth = 1);
canvas.drawLine(Offset(0, cloudCenterY), Offset(width, cloudCenterY), Paint()..color = Colors.white10..strokeWidth = 1);
// 2. 绘制概率云 (Probability Cloud)
// 将一维概率扩展为二维视觉热力发光柱
final Paint probPaint = Paint();
for (int i = 0; i < probabilityPoints.length; i++) {
double px = probabilityPoints[i].dx;
double prob = probabilityPoints[i].dy;
// 依据进度混合
Color mixColor = Color.lerp(const Color(0xFF00FFCC), Colors.redAccent, isCollapsed ? collapseProgress : 0)!;
probPaint.color = mixColor.withValues(alpha: math.min(1.0, prob * 0.4));
probPaint.strokeWidth = dx * 1.5;
// 画光晕立柱
canvas.drawLine(
Offset(px, cloudCenterY),
Offset(px, cloudCenterY - prob * 80),
probPaint
);
}
// 概率密度包络线
canvas.drawPath(envelopePath, Paint()
..color = Colors.white54
..style = PaintingStyle.stroke
..strokeWidth = 1.5);
// 3. 绘制实部波函数 Re(Psi)
// 添加外发光
canvas.drawPath(wavePath, Paint()
..color = (isCollapsed ? Colors.redAccent : const Color(0xFFFF00FF)).withValues(alpha: 0.4)
..style = PaintingStyle.stroke
..strokeWidth = 6
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 8));
// 实体线
canvas.drawPath(wavePath, Paint()
..color = isCollapsed ? Colors.white : const Color(0xFFFF00FF)
..style = PaintingStyle.stroke
..strokeWidth = 2
..strokeJoin = StrokeJoin.round);
// 4. 坍缩特效点 (Particle)
if (isCollapsed) {
double ease = _easeInOutExpo(collapseProgress);
double particleX = collapsedPosition * width;
// 粒子光晕吸收
canvas.drawCircle(Offset(particleX, cloudCenterY), 100 * (1.0 - ease), Paint()
..color = Colors.redAccent.withValues(alpha: 0.1 * (1.0 - ease))
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 20));
// 核心粒子
canvas.drawCircle(Offset(particleX, cloudCenterY), 4 + 4 * ease, Paint()
..color = Colors.white
..maskFilter = const MaskFilter.blur(BlurStyle.solid, 2));
}
}
double _easeInOutExpo(double x) {
return x == 0 ? 0 : x == 1 ? 1 : x < 0.5 ? math.pow(2, 20 * x - 10) / 2 : (2 - math.pow(2, -20 * x + 10)) / 2;
}
@override
bool shouldRepaint(covariant QuantumWavePainter oldDelegate) {
return true; // 随时间持续重绘
}
}
更多推荐



所有评论(0)