我有两个向量表示函数f(x),另一个向量f(a x + b),即f(x)的缩放和移位版本。我想找到最好的比例和移位因子。
*最好 - 通过最小二乘误差,最大似然等等。
任何想法?
例如:
f1 = [0;0.450541598502498;0.0838213779969326;0.228976968716819;0.91333736150167;0.152378018969223;0.825816977489547;0.538342435260057;0.996134716626885;0.0781755287531837;0.442678269775446;0];
f2 = [-0.029171964726699;-0.0278570165494982;0.0331454732535324;0.187656956432487;0.358856370923984;0.449974662483267;0.391341738643094;0.244800719791534;0.111797007617227;0.0721767235173722;0.0854437239807415;0.143888234591602;0.251750993723227;0.478953530572365;0.748209818420035;0.908044924557262;0.811960826711455;0.512568916956487;0.22669198638799;0.168136111568694;0.365578085161896;0.644996661336714;0.823562159983554;0.792812945867018;0.656803251999341;0.545799498053254;0.587013303815021;0.777464637372241;0.962722388208354;0.980537136457874;0.734416947254272;0.375435649393553;0.106489547770962;0.0892376361668696;0.242467741982851;0.40610516900965;0.427497319032133;0.301874099075184;0.128396341665384;0.00246347624097456;-0.0322120242872125]
*请注意f(x)可能是不可逆转的......
谢谢,
辖
答案 0 :(得分:6)
对于每个f(x)
,取f(x)
的绝对值并对其进行标准化,使其可以被视为概率质量函数超过其支持。计算预期值E[x]
和Var[x]
的方差。然后,我们有那个
E[a x + b] = a E[x] + b
Var[a x + b] = a^2 Var[x]
使用上述公式和E[x]
和Var[x]
的已知值来计算a
和b
。从您的示例中获取f1
和f2
的值,以下Octave脚本执行此过程:
% Octave script
% f1, f2 are defined as given in your example
f1 = [zeros(length(f2) - length(f1), 1); f1];
save_f1 = f1; save_f2 = f2;
f1 = abs( f1 ); f2 = abs( f2 );
f1 = f1 ./ sum( f1 ); f2 = f2 ./ sum( f2 );
mean = @(x)sum(((1:length(x))' .* x));
var = @(x)sum((((1:length(x))'-mean(x)).^2) .* x);
m1 = mean(f1); m2 = mean(f2);
v1 = var(f1); v2 = var(f2)
a = sqrt( v2 / v1 ); b = m2 - a * m1;
plot( a .* (1:length( save_f1 )) + b, save_f1, ...
1:length( save_f2 ), save_f2 );
axis([0 length( save_f1 )];
输出是
答案 1 :(得分:5)
这是一种简单,有效,但可能有些天真的方法。
首先确保通过这两个函数制作通用插值器。这样,您可以评估给定数据点之间的两个函数。我使用了三次样条插值器,因为这对于你提供的平滑函数类型来说似乎已经足够了(并且不需要额外的工具箱)。
然后在大量的点上评估源函数(“原始”)。将此数字也用作内联函数中的参数,该参数作为输入X
,其中
X = [a b]
(如ax+b
)。对于任何输入X
,此内联函数将计算
目标函数在相同x位置的函数值,但随后分别按a
和b
进行缩放和偏移。
结果函数值与之前计算的源函数之间的平方差之和。
在fminsearch
中使用此内联函数并进行一些初步估计(一种是通过视觉或通过自动方式获得的)。对于你提供的例子,我使用了一些随机的,它们都收敛到接近最优的拟合。
以上所有代码:
function s = findScaleOffset
%% initialize
f2 = [0;0.450541598502498;0.0838213779969326;0.228976968716819;0.91333736150167;0.152378018969223;0.825816977489547;0.538342435260057;0.996134716626885;0.0781755287531837;0.442678269775446;0];
f1 = [-0.029171964726699;-0.0278570165494982;0.0331454732535324;0.187656956432487;0.358856370923984;0.449974662483267;0.391341738643094;0.244800719791534;0.111797007617227;0.0721767235173722;0.0854437239807415;0.143888234591602;0.251750993723227;0.478953530572365;0.748209818420035;0.908044924557262;0.811960826711455;0.512568916956487;0.22669198638799;0.168136111568694;0.365578085161896;0.644996661336714;0.823562159983554;0.792812945867018;0.656803251999341;0.545799498053254;0.587013303815021;0.777464637372241;0.962722388208354;0.980537136457874;0.734416947254272;0.375435649393553;0.106489547770962;0.0892376361668696;0.242467741982851;0.40610516900965;0.427497319032133;0.301874099075184;0.128396341665384;0.00246347624097456;-0.0322120242872125];
figure(1), clf, hold on
h(1) = subplot(2,1,1); hold on
plot(f1);
legend('Original')
h(2) = subplot(2,1,2); hold on
plot(f2);
linkaxes(h)
axis([0 max(length(f1),length(f2)), min(min(f1),min(f2)),max(max(f1),max(f2))])
%% make cubic interpolators and test points
pp1 = spline(1:numel(f1), f1);
pp2 = spline(1:numel(f2), f2);
maxX = max(numel(f1), numel(f2));
N = 100 * maxX;
x2 = linspace(1, maxX, N);
y1 = ppval(pp1, x2);
%% search for parameters
s = fminsearch(@(X) sum( (y1 - ppval(pp2,X(1)*x2+X(2))).^2 ), [0 0])
%% plot results
y2 = ppval( pp2, s(1)*x2+s(2));
figure(1), hold on
subplot(2,1,2), hold on
plot(x2,y2, 'r')
legend('before', 'after')
end
结果:
s =
2.886234493867320e-001 3.734482822175923e-001
请注意,这会计算与生成数据的相反的转换。扭转数字:
>> 1/s(1)
ans =
3.464721948700991e+000 % seems pretty decent
>> -s(2)
ans =
-3.734482822175923e-001 % hmmm...rather different from 7/11!
(我不确定你提供的7/11值;使用你给出的确切值来绘制一个不太精确的近似源函数...你是不是确定7/11?)
可以提高准确度
fmincon
,fminunc
等)fminsearch
到optimset
f1
和f2
中包含更多样本点以提高插值质量无论如何,这种方法很通用,效果很好。它也不需要工具箱。
它有一个主要缺点 - 找到的解决方案可能不是全局优化器,例如,此方法的结果质量可能对您提供的初始估计非常敏感。因此,总是制作(差异)图以确保最终解决方案是准确的,或者如果您有大量此类事情要做,请计算某种品质因数,您决定使用不同的方式重新开始优化初步估计。
当然,很有可能使用傅里叶+梅林变换的结果(如下面的chaohuang所示)作为该方法的初始估计。对于您提供的简单示例而言,这可能有点过分,但我可以很容易地想象这可能确实非常有用的情况。
答案 2 :(得分:3)
对于比例因子a,您可以通过计算两个信号的幅度谱的比率来估计它,因为傅立叶变换不变换。
同样,您可以使用Mellin变换估算偏移因子b,该变换是尺度不变的。
答案 3 :(得分:1)
这是一种估算适用于您的示例数据的比例a
的超级简单方法:
a = length(f2) / length(f1)
这给出了3.4167,接近你声明的3.4值。如果该估计值足够好,您可以使用相关性来估计偏移。
我意识到这并不是你提出的问题,但根据数据的不同,它可能是一个可接受的选择。
答案 4 :(得分:1)
Rody Oldenhuis和jstarr的答案都是正确的。我正在添加我自己的答案,只是为了总结,并在它们之间建立联系。 我把Rody的代码搞砸了一下,结果如下:
function findScaleShift
load f1f2
x0 = [length(f1)/length(f2) 0]; %initial guess, can do better
n=length(f1);
costFunc = @(z) sum((eval_f1(z,f2,n)-f1).^2);
opt.TolFun = eps;
xopt=fminsearch(costFunc,x0,opt);
f1r=eval_f1(xopt,f2,n);
subplot(211);
plot(1:n,f1,1:n,f1r,'--','linewidth',5)
title(xopt);
subplot(212);
plot(1:n,(f1-f1r).^2);
title('squared error')
end
function y = eval_f1(x,f2,n)
t = maketform('affine',[x(1) 0 x(2); 0 1 0 ; 0 0 1]');
y=imtransform(f2',t,'cubic','xdata',[1 n ],'ydata',[1 1])';
end
这给出了零结果: 这种方法准确但详尽,可能需要一些时间。另一个缺点是它只找到局部最小值,如果初始猜测(x0)很远,可能会给出错误的结果。
另一方面,jstarr方法给出了以下结果:
xopt = [ 3.49655562549115 -0.676062367063033]
与正确答案的偏差为10%。相当快的解决方案,但不如我要求的那么准确,但仍应注意。 我认为为了获得最佳结果,jstarr方法应该用作Rody所设方法的初始猜测,给出一个准确的解决方案。
辖