找到两个向量之间的最佳/比例/转换

时间:2012-11-26 10:58:41

标签: algorithm matlab signal-processing octave model-fitting

我有两个向量表示函数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]

simulated example: scale is  2+7/5, shift  42/55, resample bicubic

*请注意f(x)可能是不可逆转的......

谢谢,

5 个答案:

答案 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]的已知值来计算ab。从您的示例中获取f1f2的值,以下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 )];

输出是 enter image description here

答案 1 :(得分:5)

这是一种简单,有效,但可能有些天真的方法。

首先确保通过这两个函数制作通用插值器。这样,您可以评估给定数据点之间的两个函数。我使用了三次样条插值器,因为这对于你提供的平滑函数类型来说似乎已经足够了(并且不需要额外的工具箱)。

然后在大量的点上评估源函数(“原始”)。将此数字也用作内联函数中的参数,该参数作为输入X,其中

X = [a b] 

(如ax+b)。对于任何输入X,此内联函数将计算

  1. 目标函数在相同x位置的函数值,但随后分别按ab进行缩放和偏移。

  2. 结果函数值与之前计算的源函数之间的平方差之和。

  3. 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
    

    the result

    请注意,这会计算与生成数据的相反的转换。扭转数字:

    >> 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?)

    可以提高准确度
    1. 使用其他优化程序(fminconfminunc等)
    2. 要求fminsearchoptimset
    3. 的准确度更高
    4. f1f2中包含更多样本点以提高插值质量
    5. 使用更好的初步估算值
    6. 无论如何,这种方法很通用,效果很好。它也不需要工具箱。

      它有一个主要缺点 - 找到的解决方案可能不是全局优化器,例如,此方法的结果质量可能对您提供的初始估计非常敏感。因此,总是制作(差异)图以确保最终解决方案是准确的,或者如果您有大量此类事情要做,请计算某种品质因数,您决定使用不同的方式重新开始优化初步估计。

      当然,很有可能使用傅里叶+梅林变换的结果(如下面的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

这给出了零结果: enter image description here 这种方法准确但详尽,可能需要一些时间。另一个缺点是它只找到局部最小值,如果初始猜测(x0)很远,可能会给出错误的结果。

另一方面,jstarr方法给出了以下结果:

xopt = [ 3.49655562549115         -0.676062367063033]

与正确答案的偏差为10%。相当快的解决方案,但不如我要求的那么准确,但仍应注意。 我认为为了获得最佳结果,jstarr方法应该用作Rody所设方法的初始猜测,给出一个准确的解决方案。