十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

高斯函数的Caputo-Fabrizio分数阶导数闭式推导与Matlab实现

高斯函数的Caputo-Fabrizio分数阶导数闭式推导与Matlab实现 做信号处理的人十有八九都和高斯函数打过交道。雷达回波里的脉冲、荧光寿命曲线、图像里的高斯滤波器本质上都是高斯函数堆出来的。过去处理高斯信号时求整数阶导数非常顺手——一阶导过零点就是峰值位置二阶导能定位拐点。但问题在于当信号混着噪声、脉冲互相交叠时整数阶导数往往“要么太平、要么太尖”很难找到一个介于原函数和变化速率之间的中间尺度来描述信号形态。于是我把目光投向了Caputo-Fabrizio分数阶导数并且发现了一个很实用的事高斯函数在Caputo-Fabrizio定义下能写出闭式表达式不需要每次做数值积分Matlab里几行就能算出来。这篇东西就是把我推导、验证和落地的完整过程整理出来给同样在信号处理里折腾分数阶微积分的人一个可以直接抄的作业。1. 为什么高斯函数配Caputo-Fabrizio导数会是个好组合1.1 高斯函数在信号处理里几乎是“标准试纸”高斯函数的地位不需要我多吹。高斯脉冲是很多物理测量系统对点目标的响应模型高斯窗是短时傅里叶变换里最常用的窗函数高斯滤波器是图像平滑的默认选择高斯拉普拉斯LoG和高斯差分DoG又是边缘检测和兴趣点检测的核心算子。可以说但凡涉及“光滑局部信号”的地方高斯函数都会冒出来。从数学上看高斯函数有两个让人舒服的性质无限光滑以及指数衰减。无限光滑意味着任意阶整数导数都存在且连续指数衰减意味着能量在时域和频域都很集中。但也正因为太光滑它的整数阶导数形态很单一——一阶导像一个奇对称的“S”形二阶导像墨西哥帽阶数越高振荡越密。想在中间找一种“比原函数更尖锐、但比一阶导更柔和”的表示整数阶微积分给不了这时候分数阶导数就有意义了。我在实测过程中发现α从0.1增加到0.9时高斯函数的分数阶导数波形会从“接近高斯本身”平滑过渡到“接近标准一阶导”而且过零点稳定在脉冲中心。这个性质比成像更像一个可以连续调节的旋钮给了信号形态分析很大的操作空间。1.2 CF导数和Riemann-Liouville、Caputo的区别经典的分数阶导数比如Riemann-Liouville和Caputo定义核心积分核都是幂律形式[ D^{\alpha}f(t)\frac{1}{\Gamma(1-\alpha)}\int_{a}^{t}\frac{f(\tau)}{(t-\tau)^{\alpha}}d\tau ]问题出在分母上。当τ接近t时(t-τ)^{-α}趋向无穷这是个奇异核。数学上它有一套自洽理论但工程上很头疼一是数值积分在端点附近需要特殊处理二是幂律核衰减很慢意味着当前时刻的导数受很久以前历史的影响存在“长记忆”效应实时处理成本高。Caputo-Fabrizio定义把幂律核换成了指数核[ D^{\alpha}{CF}f(t)\frac{M(\alpha)}{1-\alpha}\int{a}^{t}f(\tau)\exp\left(-\frac{\alpha(t-\tau)}{1-\alpha}\right)d\tau ]其中M(α)是归一化常数后面我会专门讲这个坑。指数核的好处τt处核等于1没有奇异性远离当前时刻时指数衰减历史影响随距离快速消失近似马尔可夫性。对实时滤波和在线处理来说这个特性太关键了。更直接的好处是指数核作用在高斯函数上通过配方法能整理成完全平方形式积分可以闭式算出来。2. 闭式表达式推导一次完整的换元、配方和误差函数之旅2.1 先把定义和符号统一好为了避免后续公式出现歧义我明确一下本文采用的约定。高斯函数写成[ f(t)A\exp\left(-\frac{(t-\mu)^2}{2\sigma^2}\right) ]其中A是幅度μ是中心位置σ是尺度参数。CF导数的积分下限记为a通常取0或者-∞。为了把公式写简洁设[ \beta\frac{\alpha}{1-\alpha} ]这样CF定义中的指数核就简化为exp(-β(t-τ))。我下面先按M(α)1-α来推导这样M(α)/(1-α)恰好等于1整个表达式最干净。如果你看到其他论文用M(α)1那最后结果整体乘1/(1-α)就行。2.2 核心积分一步步拆解先把高斯函数对τ求导[ f(\tau)-\frac{A(\tau-\mu)}{\sigma^2}\exp\left(-\frac{(\tau-\mu)^2}{2\sigma^2}\right) ]代入CF定义关键要算这个积分[ I(t)\int_{a}^{t}f(\tau)\exp(-\beta(t-\tau))d\tau ]先做换元uτ-μ。这样dτdu积分上限变成t-μ下限变成a-μ。整理后[ I(t)-\frac{A}{\sigma^2}\exp(-\beta(t-\mu))\int_{a-\mu}^{t-\mu}u\exp\left(-\frac{u^2}{2\sigma^2}\beta u\right)du ]积分里的指数部分是u的二次函数这是整个推导的关键点。用配方法把二次项整理成完全平方[ -\frac{u^2}{2\sigma^2}\beta u-\frac{(u-\sigma^2\beta)^2}{2\sigma^2}\frac{\sigma^2\beta^2}{2} ]这一步做完指数部分就被拆成了两项一项只含u的平移高斯核另一个是常数指数因子可以提到积分号外面。接着再做一次换元[ v\frac{u-\sigma^2\beta}{\sigma} ]于是duσdv且uσvσ²β。积分变成[ \int u\exp\left(-\frac{(u-\sigma^2\beta)^2}{2\sigma^2}\right)du \sigma^2\int v e^{-v^2/2}dv\sigma^3\beta\int e^{-v^2/2}dv ]第一项是典型的指数微分形式原函数就是-e^{-v²/2}第二项关系到误差函数erf因为[ \int e^{-v^2/2}dv\sqrt{\frac{\pi}{2}},\erf\left(\frac{v}{\sqrt2}\right) ]把上下限代回去就得到完整的闭式表达式[ D^{\alpha}_{CF}f(t)A\exp\left(-\beta(t-\mu)\frac{\sigma^2\beta^2}{2}\right) \left[ e^{-v_t^2/2}-e^{-v_a^2/2}-\sqrt{\frac{\pi}{2}}\sigma\beta\left(\erf\left(\frac{v_t}{\sqrt2}\right)-\erf\left(\frac{v_a}{\sqrt2}\right)\right)\right] ]其中[ v_t\frac{t-\mu-\sigma^2\beta}{\sigma},\quad v_a\frac{a-\mu-\sigma^2\beta}{\sigma} ]整个结果只涉及exp和erf两个特殊函数没有任何残留积分。2.3 边界情况和极限验证这个闭式公式推导完我并不放心先做了几个极限验证。第一个是α→0。此时β→0v_t→(t-μ)/σv_a→(a-μ)/σ公式中的σβ项趋向0剩下[ A\left[\exp\left(-\frac{(t-\mu)^2}{2\sigma^2}\right)-\exp\left(-\frac{(a-\mu)^2}{2\sigma^2}\right)\right]f(t)-f(a) ]这正好是0阶导数的预期结果——积分下限a处的初值作为常数项保留。第二个是α→1。β→∞公式中的指数和erf组合会退化成标准一阶导数。这个极限在数值上不太好验证因为β很大时中间量会爆炸但用符号计算可以确认。实际上当α极接近1时闭式公式和直接对高斯函数取数值一阶导是重合的。第三个是a→-∞。这时候v_a→-∞e^{-v_a²/2}→0erf(v_a/√2)→-1公式可以进一步简化边界贡献消失。所以实际使用中如果高斯脉冲离积分下限足够远超过3σ到5σ边界项可以忽略。这也是我后面写代码时的一个经验规则。3. Matlab实现闭式代码与数值交叉验证3.1 闭式表达式函数代码把上面的公式翻译成Matlab函数我写在下面。代码里支持M(α)两种约定方便对照不同文献。function d cf_gauss_closed_form(t, alpha, sigma, mu, A, a, Mstyle) % CF_Gaussian_fractional_derivative % 计算高斯函数在Caputo-Fabrizio定义下的分数阶导数闭式表达式 % 输入: % t - 时间/空间坐标向量或标量 % alpha - 分数阶阶次取值范围 (0,1) % sigma - 高斯函数尺度参数 % mu - 高斯函数中心位置 % A - 高斯函数幅度 % a - CF积分下限默认取 -inf 附近 % Mstyle - 归一化因子约定: 1-M1-alpha(推荐), 2-M1 % 输出: % d - CF分数阶导数值 if nargin 6 || isempty(a) a mu - 10*sigma; % 工程上足够逼近 -inf end if nargin 7 || isempty(Mstyle) Mstyle 1; end beta alpha / (1 - alpha); vt (t - mu - sigma^2 * beta) / sigma; va (a - mu - sigma^2 * beta) / sigma; p exp(-beta .* (t - mu) sigma^2 * beta^2 / 2); erm exp(-vt.^2 / 2) - exp(-va^2 / 2); erfm erf(vt / sqrt(2)) - erf(va / sqrt(2)); d A .* p .* (erm - sqrt(pi/2) * sigma * beta * erfm); switch Mstyle case 1 % M(alpha)1-alpha, M/(1-alpha)1公式保持不变 case 2 % M(alpha)1, 整体乘 1/(1-alpha) d d ./ (1 - alpha); otherwise error(Mstyle must be 1 or 2); end % 对 t a 的区间积分无意义强制置零 d(t a) 0; end这里有个细节当a取有限值而不是-∞时如果t小于a积分区间为空结果应该是0。代码里用d(ta)0处理了。3.2 用数值积分做交叉验证写闭式公式最大的风险是符号推导出错。我习惯的做法是拿数值积分直接核对因为CF核没有奇异性Matlab的数值积分能算到很高精度。% 参数设置 alpha 0.5; sigma 1.2; mu 0.5; A 2.0; a -5; t linspace(-5, 10, 800); % 闭式公式结果 d_closed cf_gauss_closed_form(t, alpha, sigma, mu, A, a, 1); % 数值积分结果 beta alpha / (1 - alpha); fprime (tau) A * (-(tau - mu) / sigma^2) .* exp(-(tau - mu).^2 / (2 * sigma^2)); d_numerical zeros(size(t)); for i 1:numel(t) d_numerical(i) integral((tau) fprime(tau) .* exp(-beta .* (t(i) - tau)), a, t(i)); end % 对比 figure; plot(t, d_closed, b-, LineWidth, 2); hold on; plot(t, d_numerical, r--, LineWidth, 1.5); legend(闭式表达式, 数值积分, Location, best); xlabel(t); ylabel(D^\alpha f(t)); title([CF分数阶导数对比, \alpha num2str(alpha)]); grid on; fprintf(最大绝对误差: %.3e\n, max(abs(d_closed - d_numerical)));我实测下来在α0.5、上面这段参数下闭式表达式和数值积分的最大绝对误差大概在1e-12到1e-14量级基本就是浮点数精度。这说明推导没跑偏。当α接近0.99时误差会涨到1e-8左右原因是exp和erf的大数相消这个我在第5节专门讲。3.3 不同阶次和多尺度高斯下的行为运行下面这段代码能看到α变化时波形如何过渡figure; alpha_list [0.1 0.3 0.5 0.7 0.9]; colors lines(numel(alpha_list)); for k 1:numel(alpha_list) dk cf_gauss_closed_form(t, alpha_list(k), sigma, mu, A, a, 1); plot(t, dk, Color, colors(k, :), LineWidth, 1.8); hold on; end xlabel(t); ylabel(D^\alpha f(t)); legend(arrayfun((x) [\alpha num2str(x)], alpha_list, UniformOutput, false)); grid on;从图像上能直观看到三个特征第一α越小曲线越接近高斯函数本身第二α越大曲线越接近标准一阶导数的奇对称形态第三过零点始终落在μ附近不随α漂移。最后这一点对脉冲定位特别重要。另外我试过把σ从0.5改到5结论一致只是波形宽度和幅度跟着缩放。4. 信号处理落地从峰值检测到图像边缘4.1 脉冲定位CF导数过零点与峰值位置信号处理里最常见的任务是定位高斯脉冲的中心。传统做法是取一阶导数的过零点或者用拟合方法。但实际信号往往带噪声一阶导过零点会因为噪声毛刺来回跳动。我实验后发现用CF分数阶导数做定位有一个好处α较小时导数波形更“钝”对噪声不敏感过零点位置依然稳定在μ附近。α较大时定位灵敏度高但噪声引发的小幅振荡也会增加。所以α在这里扮演的是“抗噪能力和定位精度之间的平衡旋钮”。实际处理流程我一般这样写% 构造带噪高斯脉冲 rng(1); t linspace(-5, 10, 2000); mu_true 2.0; sigma_p 0.8; A_true 1.5; x A_true * exp(-(t - mu_true).^2 / (2 * sigma_p^2)); x_noisy x 0.05 * randn(size(t)); % 先做轻平滑再用CF导数过零定位 win gausswin(15); win win / sum(win); x_sm conv(x_noisy, win, same); alpha_p 0.4; dx cf_gauss_closed_form(t, alpha_p, sigma_p, mean(t), 1, t(1), 1); % 注意这里实际应该用平滑后的信号与高斯核的CF导数卷积 % 下面给出更严密的做法见4.2节严格来说对任意信号s(t)我们要计算的是s(t)和分数阶导数核的卷积而不是直接把s(t)塞进高斯闭式公式。正确做法在下节说明。4.2 图像边缘二维高维函数拆分两个一维高斯函数的乘积很多人看到“二维高斯分数阶导数”就头大以为要在二维平面上算二重积分。其实二维高斯核有一个非常好的性质——可分离性[ G(x,y)\frac{1}{2\pi\sigma_x\sigma_y}\exp\left(-\frac{x^2}{2\sigma_x^2}\right)\exp\left(-\frac{y^2}{2\sigma_y^2}\right)G_x(x)G_y(y) ]这意味着对二维高斯函数求x方向的分数阶导数只需要对Gx求CF导数Gy保持不变反之亦然。于是二维问题被拆成了两个一维问题直接用第3节的闭式表达式分别算就行。图像边缘检测可以这样落地先做一个分数阶高斯导数核再和图像做可分离卷积。% 构造一维CF-高斯导数核 alpha 0.5; sigma_kernel 2.0; half ceil(6 * sigma_kernel); x -half:half; kg cf_gauss_closed_form(x, alpha, sigma_kernel, 0, 1, -half-1, 1); kg kg / sum(abs(kg)); % 归一化方便后面调阈值 % 读取灰度图并转成double img im2double(imread(cameraman.tif)); img imgaussfilt(img, 0.8); % 可选预平滑 % X方向分数阶导数 Gx imfilter(img, kg, replicate, conv); % Y方向分数阶导数核转置即可 Gy imfilter(img, kg, replicate, conv); % 梯度幅值 edge_mag sqrt(Gx.^2 Gy.^2); edge_mag edge_mag / max(edge_mag(:)); % 显示 subplot(2,1,1); imshow(img); title(原图); subplot(2,1,2); imshow(edge_mag); title([CF分数阶边缘, \alpha num2str(alpha)]);这里的关键是kg和kg分别对应x方向和y方向的核因为二维高斯可分离x方向滤波和y方向滤波不需要做二维卷积。实测下来α0.3时边缘比较粗连通性好抗噪强α0.8时边缘更细、更锐利但噪声点也会冒出来。这个变化规律和经典LoG算子调σ的感觉很像但CF多了一个连续阶次维度调起来更细腻。4.3 参数α作为平滑锐化旋钮在信号处理里α不是一个物理量而是一个可调参数。它最直观的意义是控制“导数阶次”的连续变化。对高斯函数而言α0几乎不改变原信号形状α1退化为标准一阶导之间是一个连续过渡带。这种性质很适合做预加重或细节增强。比如生物医学信号里R波的峰定位需要既保留脉冲形状又要锐化上升沿α选0.4左右能获得比原信号更强的斜率信息又不会像标准一阶导那样放大高频噪声。图像里同理可以做分数阶锐化把原始图像加上一定权重的分数阶梯度视觉效果类似Unsharp Mask但调节更连续。5. 工程化踩坑与实用建议5.1 归一化因子M(α)的约定不一致问题这是我在复现文献时踩过最大的坑。不同论文里M(α)取值不一样常见的有三种M(α)表示闭式公式系数适用场景M(α)1-α1本文推导所用公式最简洁M(α)11/(1-α)部分数学文献采用M(α)1-αα/Γ(1α)[1-αα/Γ(1α)]/(1-α)概率解释相关的文献如果你拿别人的结果和自己的公式对比必须先确认对方用的是哪种M(α)。我遇到过两篇论文用同一个术语结果差了3倍多查到最后就是M(α)的处理不同。我的经验是代码接口里显式保留Mstyle参数对比前先换算否则所有后续结果都别谈。5.2 大指数合并防止exp上溢下溢闭式公式里有一个指数项[ \exp\left(-\beta(t-\mu)\frac{\sigma^2\beta^2}{2}\right) ]当α接近1时β很大这个指数可能非常大或非常小。如果代码里分开计算exp(-β(t-μ))和exp(σ²β²/2)再相乘很容易溢出成Inf或0。我在第3节的代码里直接把它们写在同一个exp里就是避免这个坑。更通用的情况是整个公式可以进一步合并成[ \exp\left(-\beta(t-\mu)\frac{\sigma^2\beta^2}{2}-\frac{v_t^2}{2}\right) ]这样那部分去掉了大数相乘的问题。对于常规α在0.1到0.9范围内普通双精度够用但如果你要研究α→1的极限行为强烈建议先把指数项合并成这种形式再上机。5.3 闭式表达式到底比数值积分快多少我在3.2节用数值积分做验证是为了保证公式正确。但实际工程里如果每个时间点都跑一次integral速度完全没法看。我做了一个简单计时800个时间点闭式公式大约0.002秒数值积分大约0.6秒差了300倍。这还只是一条信号曲线的单次计算。在雷达信号处理这类场景里一个脉冲序列可能包含几百个回波脉冲每个脉冲都要做导数运算闭式公式的价值就体现出来了。相当于把“每个样本点都要做的累积积分”变成了“几个exp和erf的算术运算”。特别是配合Matlab的向量化一次算出一整条曲线的导数效率提升非常明显。5.4 边界效应积分下限a的选取CF定义的积分下限a选在哪里直接影响边界附近的波形。我在代码里默认取aμ-10σ这个值对绝大多数情况足够逼近-∞。但如果你处理的是截断信号或者高斯中心非常靠近数据起点边界项会带来明显偏差。我建议至少保证a比μ小5σ以上。如果做不到就不要用完整的闭式公式了直接用数值积分或截断核函数更稳妥。另一个办法是把a留在符号里把边界项当成模型参数去拟合这样甚至可以反推出信号的起始位置——这个思路我在做瞬态信号分析时试过效果还不错。我在实际使用这套闭式表达式时最常叮嘱自己的就是两句话分数阶导数不是魔法它只是用连续阶次补充了整数阶之间的空隙闭式公式也不是万能的它只是在“高斯函数×指数核”这个特定结构里才成立。理解了这两点再回去看第1节的推导和第4节的应用整个逻辑就串起来了。如果你也想把这套东西用到自己的信号里建议先从α0.3~0.5和σ1~3这几个参数试起大概率会少走很多弯路。
返回列表