How do I rescale the polyfit coefficients back to normal coordinate system?
18 visualizzazioni (ultimi 30 giorni)
Mostra commenti meno recenti
Neil Campbell
il 14 Giu 2016
Modificato: Faruk Telibecirovic
il 16 Dic 2023
I fit some data with 1) [p,S,mu] = polyfit(x,y,1); These polynomial coefficients are different from those you would get from 2) [p,S] = polyfit(x,y,1); I need the coeffecients that correspond to a fit on my original, unscaled coordinate system. However, I want to use the 1st equation to benefit from the centering and scaling. How do I use the 1st equation (with mu) and obtain coefficients that correspond to my unscaled system?
0 Commenti
Risposta accettata
Frank Fournel
il 4 Mar 2017
Hello, i've found a way to do this : [pp(i,:),~,mu(i,:)]=polyfit(x1,y(i,:),order);%Fit par renormalisation normx(i,:)=[1/mu(i,2) -mu(i,1)/mu(i,2)]; r(i,:) = sym2poly(subs(poly2sym(pp(i,:)),poly2sym(normx(i,:)))); yy2(i,:)=polyval(r(i,:),x1);
but I would like to have a stand alone application and it is not possible to compile symbolic function. Have you found another way to do this?
2 Commenti
James Thompson
il 9 Feb 2019
What did you end up doing? I am having trouble doing exactly this and also don't want to use symbolic functions.
Più risposte (2)
Jannik M.
il 4 Nov 2020
Modificato: Jannik M.
il 4 Nov 2020
If phat are the output coefficients of polyfit in standardized x units, and mu = [mean(x) std(x)] the standardization values, you can get the coefficients p in units of x like this:
[phat, ~, mu] = polyfit(x, y, n)
phat = flip(phat); % Flip order to [p0, ..., pn]
p = zeros(size(q));
for i = 0:n
for k = i:n
p(i+1) = p(i+1) + nchoosek(k, k-i) * phat(k+1)/mu(2)^k * (-mu(1))^(k-i);
end
end
p = flip(p); % Back to original order [pn, ..., p0]
Background
The standardization polyfit applies to the x-values is
where
(mu(1)) and
(mu(2)) are the mean and standard deviation of the original x-values. Express the polynomial function
in terms of
and the standardized coefficients
and use the binomial formula, such that
If you write this out explicitly (e.g., for
) and regroup the prefactors by the power of x, you will see that you can express
in terms of p,
using the transformation:
which is the formula applied in the code.
3 Commenti
Al
il 24 Ago 2022
I used p and it worked for me. Note you will need to plot anything taken from poly2sym since it buggy and randomly gives bad results. If using the equation in a SPICE code or other program that needs the equation double check, it will save you a lot of headaches. If it is wrong try changing the polyfit to a different order fit and re-check.
Steven Lord
il 24 Ago 2022
Note you will need to plot anything taken from poly2sym since it buggy and randomly gives bad results.
Do you have a concrete small example of a random "bad result" from poly2sym?
Faruk Telibecirovic
il 16 Dic 2023
Modificato: Faruk Telibecirovic
il 16 Dic 2023
I also stumbled on this problem and find relief in @Jannik M.code. Precision can be improved by changing this line:
p(i+1) = p(i+1) + nchoosek(k, k-i) * phat(k+1)/mu(2)^k * (-mu(1))^(k-i);
to fuse division of large powers of 'mu':
p(i+1) = p(i+1) + nchoosek(k, k-i) * phat(k+1) * ((-mu(1))^(k-i) / mu(2)^k);
If further precision is needed, without use of symbolic functions, I implemented some Dekker's double-double math:
function [p] = rescalePhatDekker(phat,mu)
n = numel(phat) - 1;
phat = flip(phat); % Flip order to [p0, ..., pn]
p = zeros(size(phat));
for i = 0:n
po_s = [0.0,0.0];
for k = i:n
nck_s = split(nchoosek(k, k-i));
ph_s = split(phat(k+1));
nckph_s = dd_mul(nck_s, ph_s);
m1_s = split(-mu(1));
m1p_s = dd_pow(m1_s,(k-i));
m2_s = split(mu(2));
m2p_s = dd_pow(m2_s, k);
m1d2p_s = dd_div(m1p_s,m2p_s);
rowadd_s = dd_mul(nckph_s, m1d2p_s);
po_s = dd_add(po_s,rowadd_s);
end
p(i+1) = po_s(1) + po_s(2);
end
p = flip(p); % Back to original order [pn, ..., p0]
end
function xs = split(x)
% Splits double x into two non-overlapping components
t = 134217729 * x; % 2^27 + 1
a = t - (t - x);
b = x - a;
xs = [a, b];
end
function r = mul12(a, b)
% Multiplies double a and b, returning the result as two non-overlapping components
as = split(a);
a1 = as(1);
a2 = as(2);
bs = split(b);
b1 = bs(1);
b2 = bs(2);
r1 = a * b;
r2 = a2 * b2 - (((r1 - a1 * b1) - a2 * b1) - a1 * b2);
r = [r1, r2];
end
function [r] = dd_div(a, b)
u = a(1) / b(1);
t = mul12(u, b(1));
L = (a(1) - t(1) - t(2) + a(2) - u * b(2) ) / b(1);
r1 = u + L;
r2 = u - r1 +L;
r = [r1, r2];
end
function z = dd_add(x, y)
A = x(1);
a = x(2);
B = y(1);
b = y(2);
R = A+B;
r = 0.0;
if (abs(A) > abs(B))
r = A-R+B+b+a;
else
r = B-R+A+a+b;
end
C = R + r;
c = R - C + r;
z = [C, c];
end
function z = dd_sub(x, y)
A = x(1);
a = x(2);
B = y(1);
b = y(2);
R = A-B;
r = 0.0;
if (abs(A) > abs(B))
r = A-R-B-b+a;
else
r = -B-R+A+a-b;
end
C = R + r;
c = R - C + r;
z = [C, c];
end
function p = dd_mul(a, b)
% Double-double precision multiplication
a1 = a(1);
a2 = a(2);
b1 = b(1);
b2 = b(2);
s = mul12(a1, b1);
s1 = s(1);
s2 = s(2);
s2 = s2 + a1 * b2;
s2 = s2 + a2 * b1;
p = fast_two_sum(s1, s2);
end
function r = fast_two_sum(a, b)
% Helper function to sum two floating-point numbers with non-overlapping bits
r1 = a + b;
v = r1 - a;
r2 = b - v;
r = [r1, r2];
end
function r = dd_pow(a, n)
% Double-double exponentiation by squaring
% a is a double-double number, and n is an integer exponent
r = [1, 0]; % Initialize result as double-double 1
x = a; % Initialize base
while n > 0
if mod(n, 2) == 1
r = dd_mul(r, x); % Multiply result by current base if bit is 1
end
x = dd_mul(x, x); % Square the base
n = floor(n / 2); % Move to the next bit
end
end
For my problem (interpolation), error is even smaler than with 100 digit symbolic solution. Strange, but true. More than here used, helper functions, are there for convinience.
BR,
FT
0 Commenti
Vedere anche
Categorie
Scopri di più su Calculus in Help Center e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!