=====Deflectometry principle===== svg file for the diagram: https://bvdp.inetdoc.net/files/deflectometry/graphique_pour_daniel/dessin8.svg {{https://bvdp.inetdoc.net/files/deflectometry/graphique_pour_daniel/1.png}} {{https://bvdp.inetdoc.net/files/deflectometry/graphique_pour_daniel/2.png}} {{https://bvdp.inetdoc.net/files/deflectometry/graphique_pour_daniel/3.png}} =====Deflectometry model simulator==== function display_closed_contour(countour,style,origin_style) if nargin==3 plot([countour(1,1)],[countour(1,2)],origin_style); end for n=1:size(countour,1)-1 plot([countour(n,1),countour(n+1,1)],[countour(n,2),countour(n+1,2)],style); end plot([countour(size(countour,1),1),countour(1,1)],[countour(size(countour,1),2),countour(1,2)],style); end function [ R] = rodrigues2R( wi ) %bvdp % R=rodrigues2R( [1, 2,-1]) %il faut que R*R^-1= Id et det(R)=1 theta=norm(wi,2) w=wi/theta ws=[0 -w(3) w(2) ; w(3) 0 -w(1) ; -w(2) w(1) 0] wwt=ws*ws if ~isa(w,'sym') & theta {{https://bvdp.inetdoc.net/files/deflectometry/deflectoschematic.png}} %B. Vandeportaële & D. Maestro 2017 close all clear all %symbolic or numeric simulation symbolic=1 %size of the mirror in x mirrorwidth=100; %size of the mirror in y mirrorheigth=130; if exist('symbolic','var') tcx=sym('tcx','real'); tcy=sym('tcy','real'); tcz=sym('tcz','real'); rcx=sym('rcx','real'); rcy=sym('rcy','real'); rcz=sym('rcz','real'); rc=[rcx,rcy,rcz]'; else tcx= 190; tcy= 85; tcz=200; %rc=[0,1,0]'*110*pi/180; %rc=[0,1,0]'*110*pi/180; %set the rotation matrix from axis correspondances Rapprox=[0 0.7 -0.7;1 0 0; 0,-0.7 -0.7]; det(Rapprox) [U,S,V] =svd(Rapprox) R=U*V' rr=rodrigues(R) rrangle=norm(rr) rraxis=rr/rrangle rc=rr end tc=[tcx,tcy,tcz]'; Tmc=[rodrigues2R(rc), tc; 0,0,0,1]; if exist('symbolic','var') fu=sym('fu','real'); fv=sym('fv','real'); pu=sym('pu','real'); pv=sym('pv','real'); else camera_image_width=2560; camera_image_height=2048; pu=camera_image_width/2; pv=camera_image_height/2; horizontal_fov=70*pi/180; vertical_fov=60*pi/180; fu=(camera_image_width/2)/tan(horizontal_fov/2); fv=(camera_image_height/2)/tan(vertical_fov/2); end K=[fu 0 pu 0; 0 fu pv 0; 0 0 1 0]; if ~exist('symbolic','var') mirror_corners=[0,0;mirrorwidth,0;mirrorwidth,mirrorheigth;0,mirrorheigth]; mirror_corners_projected=zeros(size(mirror_corners)); for n=1:size(mirror_corners,1) P=[ mirror_corners(n,:),0,1]'; PP=inv(Tmc)*P if (PP(3)<0) display('the point is behind the camera'); end p=K*PP; p=p/p(3); mirror_corners_projected(n,:)=p(1:2)'; end end if exist('symbolic','var') display_pixel_size_x=sym('display_pixel_size_x','real'); display_pixel_size_y=sym('display_pixel_size_y','real'); else camera_image_boundaries=[0,0;camera_image_width,0;camera_image_width,camera_image_height;0,camera_image_height]; display_pixel_size_x=0.205; display_pixel_size_y=0.205; display_pixel_width=2560; display_pixel_height=1800; %metric unit mm display_metric_width=display_pixel_size_x*display_pixel_size_x; display_metric_height=display_pixel_size_y*display_pixel_size_y; end pixel2metric=[display_pixel_size_x 0 0; 0 display_pixel_size_y 0; 0 0 1]; if exist('symbolic','var') tdx=sym('tdx','real'); tdy=sym('tdy','real'); tdz=sym('tdz','real'); rdx=sym('rdx','real'); rdy=sym('rdy','real'); rdz=sym('rdz','real'); rd=[rcx,rcy,rcz]'; else %set the rotation matrix from axis correspondances %close to perfect configuration %Rapprox2=[0 -0.7 -0.7;1 0 0; 0,-0.7 +0.7]; %another configuration with 3 degrees of freedom rotation Rapprox2=[0 -0.7 -0.5;0.7 0.2 0.1; 0,-0.7 +0.9]; [U,S,V] =svd(Rapprox2); R2=U*V'; rr2=rodrigues(R2); rrangle2=norm(rr2); rraxis2=rr2/rrangle2; rd=rr2 tdx=-64; tdy=-220; tdz=530; end % rd=[rdx,rdy,rdz]'; td=[tdx,tdy,tdz]'; Tmd=[rodrigues2R(rd), td; 0,0,0,1]; %Tdm=inv(Tmd); Treflection=[1 0 0 0; 0 1 0 0 ; 0 0 -1 0; 0 0 0 1]; MMM=[1 0 0; 0 1 0; 0 0 0; 0 0 1]; %form P2 to P3 in z=0 plane if ~exist('symbolic','var') display_image_boundaries=[0,0;display_pixel_width,0;display_pixel_width,display_pixel_height;0,display_pixel_height]; display_corners_projected=zeros(size(display_image_boundaries)); for n=1:size(mirror_corners,1) Pd=[ display_image_boundaries(n,:),1]' Pdmetric=pixel2metric*Pd; %PdmetricP3=[Pdmetric(1:2);0;Pdmetric(3)]; %compute location in P3 for z=0 plane PdmetricP3=MMM*Pdmetric; P=Treflection*Tmd*PdmetricP3; PP=inv(Tmc)*P if (PP(3)<0) display('the point is behind the camera'); end p=K*PP; p=p/p(3); display_corners_projected(n,:)=p(1:2)'; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %computation of the homography between display and camera taking %into account the reflexion Hcd=K*inv(Tmc)*Treflection*Tmd*MMM*pixel2metric %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if exist('symbolic','var') jacobian(reshape(Hcd,9,1),[rd]) end if exist('symbolic','var') jacobian(reshape(Tmd,16,1),[rd]) end if exist('symbolic','var') %what happen if we use Tcm instead of Tmc=> other parameterization tcix=sym('tcix','real'); tciy=sym('tciy','real'); tciz=sym('tciz','real'); rcix=sym('rcix','real'); rciy=sym('rciy','real'); rciz=sym('rciz','real'); rci=[rcix,rciy,rciz]'; tci=[tcix,tciy,tciz]'; Tcm=[rodrigues2R(rci), tci; 0,0,0,1]; Hcd=K*Tcm*Treflection*Tmd*MMM*pixel2metric J= jacobian(reshape(Hcd,9,1),[rd',td',rci',tci']) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %display %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if ~exist('symbolic','var') figure hold on axis equal axis ij display_closed_contour(camera_image_boundaries,'b-','bx') display_closed_contour(mirror_corners_projected,'r-','rx') display_closed_contour(display_corners_projected,'g-','gx') for ud=0:100:display_pixel_width-1 for vd=0:100:display_pixel_height-1 p=Hcd*[ud;vd;1]; p=p/p(3); plot(p(1),p(2),'g+'); end end end {{https://bvdp.inetdoc.net/files/deflectometry/simu2.png}} =====2D analysis for uncertainty propagation===== %B. Vandeportaële & D. Maestro 2017 close all clear all %example for the inversion of P1 to P1 scale and offset pixperm=sym('pixperm','real'); pud=sym('pud','real'); Kd=[pixperm pud; 0 1] a=sym('a','real'); b=sym('b','real'); c=sym('c','real'); d=sym('d','real'); Kdinv=[a b;c d ] eqn= reshape(Kdinv*Kd-eye(2),4,1) S=solve(eqn,a,b,c,d) Kdinv=[S.a S.b;S.c S.d] jacobian(reshape(Kdinv,4,1),[pixperm,pud]) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% tcx=sym('tcx','real'); tcy=sym('tcy','real'); r11=sym('r11','real'); r12=sym('r12','real'); r21=sym('r21','real'); r22=sym('r22','real'); M=[r11,r12,tcx;r21,r22,tcy ;0 0 1] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fuc=sym('fuc','real'); puc=sym('puc','real'); K=[fuc puc 0; 0 1 0]; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% E=[1 0;0 0 ;0 1] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% H=K*M*E*Kdinv %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% tdx=sym('tdx','real'); tdy=sym('tdy','real'); thetad=sym('thetad','real'); Md=[cos(thetad),-sin(thetad), tdx;sin(thetad),cos(thetad),tdy; 0, 0, 1] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% =====Fitting of sinus function===== %@Bertrand Vandeportaele LAAS 2017 function phasefunc() close all symbolicComputation=false; ud=218; vd=153; ud=289; vd=93; of=100; af=73; freq=6/(1920); wt=2*pi*freq; lum=[]; lumn=[]; n=[]; nbPointsPerPeriod=400 global gnoiseLevel gnoiseLevel=3 %useSyntheticData=true useSyntheticData=false if useSyntheticData %polynomial for some non linear disturbance pol=[ 0.003; 0.35; 10] %polynomial for some no disturbance %pol=[ 0; 1; 0] for i=1:nbPoints*PerPeriod p=i*2*pi/nbPointsPerPeriod; deltai=ud*wt; l=of+af*sin(deltai+p); lum=[lum,l]; %non linear disturbance l2=pol(3)+pol(2)*l+pol(1)*l^2; %add noise ln=l2+gnoiseLevel*randn(1); lumn=[lumn,ln]; n=[n,i-1]; end else folder_path = './pos_02/0016/H/'; %folder_path = './pos_02/0032/H/'; %folder_path = './pos_02/0064/H/'; %file_extension='bmp'; %num_imgs= 11 folder_path = '/media/HD500GO/daniel/phases/gray/m_00/t4096/pos_02/0016/H/' file_extension='tif'; num_imgs= 64 ud=128; vd=1024; % vd=1 folder_path = '/media/HD500GO/daniel/phases/gray/m_00/t40/m_00/pos_02/0040/H/' file_extension='tif'; num_imgs= 128 ud=1280; vd=1024; vd=1000 vd=400 %To avoid reloading the images each time. % clear I to force it global I %if true if (size(I,1)==0) || (size(I,2)==0) %% Load Images fprintf('Start loading data\n') tic; for indx=0:num_imgs-1 ima_name = sprintf('%s%s%03d.%s', folder_path,'img_',indx,file_extension); if indx==0 I0 = imread(ima_name); [ rs, cs] = size(I0); % Allocate matrix I = zeros(rs, cs, num_imgs); I(:,:,1) = I0; else %ima_name = fullfile(folder_path, image_files(indx).name); I(:,:,indx+1) = imread(ima_name); end end fprintf([num2str(num_imgs), ' Images Loaded. ']) toc end end n=(0:num_imgs-1)'; lumn=reshape(I(vd,ud,:),num_imgs,1)'; lum=lumn; nbPointsPerPeriod=num_imgs %polynomial for no disturbance pol=[ 0; 1; 0] %numberOfSamplesForMeaning=10 %mask=(1/numberOfSamplesForMeaning)*ones(1,numberOfSamplesForMeaning) %lumn=conv(lumn,mask,'same') global gpuls gpuls=2*pi/nbPointsPerPeriod; %%%%%%%%%%%%%%%%TEST to reduce the number of input data%%%%%%%%%%%%%%%%%%%% % nbPointsPerPeriod=6 % n=n(1:nbPointsPerPeriod) % lum=lum(1:nbPointsPerPeriod) % lumn=lumn(1:nbPointsPerPeriod) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%TEST pertubate some points to check the robustness %lumn(40)=6000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% tic [xLinear covarianceOutLinear]=fitSinusLinear(n,lumn,gpuls) toc tic [xLinearOpt covarianceOutLinearOpt,err]=fitSinusLinearOptimized(n,lumn,gpuls) toc [xPerfect covarianceOutPerfect]=fitSinusLinear(n,lum,gpuls) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %non linear method if symbolicComputation ofs = sym('ofs','real'); amp = sym('amp','real'); gpuls = sym('puls','real'); phas = sym('phas','real'); t = sym('t','real'); y=ofs+amp*sin(gpuls*t+phas) ymes = sym('ymes','real'); res=expand((ymes-y)) %jacobian of res used during optimization J=jacobian(res,[ofs,amp,phas])' %jacobian of res^2, should be 0 at the end of the optimization only %when there is no noise on the data %J2=jacobian(res^2,[ofs,amp,phas])' end %ofs=of+10; %amp=af*0.9; %phas=0; %x0=[ofs,amp,phas]; %x0=x0+[10,40,0.3]%add some error [xNonLinear,resxNonLinear,JxNonLinear]= sinusNonLinearFit(n,lumn,xLinear); %NON!!!!!!!!!!!!!!!!! %covarianceInNonLinear=diag(resxNonLinear.*resxNonLinear); %W=inv(covarianceInNonLinear); %mean of absolute value of errr mean (abs(resxNonLinear),1) variance=var(resxNonLinear) standardDeviation=variance^0.5 W=eye(size(resxNonLinear,1))*variance^-1; JxNonLinear InformationOutNonLinear= (JxNonLinear'*W*JxNonLinear) covarianceOutNonLinear= inv(InformationOutNonLinear); displayResult(xLinear, covarianceOutLinear,'xLinear ' ) %theese 2 values have comparable variances displayResult(xNonLinear, covarianceOutNonLinear,'xNonLinear ' ) %return %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %non linear method taking into account the non linearity of the %camera/display if symbolicComputation ofs = sym('ofs','real'); amp = sym('amp','real'); gpuls = sym('puls','real'); phas = sym('phas','real'); t = sym('t','real'); yperfect=ofs+amp*sin(gpuls*t+phas); nla = sym('nla','real'); nlb = sym('nlb','real'); nlc = sym('nlc','real'); y=nla * yperfect^2 + nlb * yperfect + nlc; ymes = sym('ymes','real'); res=expand((ymes-y)) %jacobian of res used during optimization J=jacobian(res,[ofs,amp,phas,nla,nlb,nlc])' end %ofs=of+10; %amp=af*0.9; %phas=0; %x0=[ofs,amp,phas]; %x0=x0+[10,40,0.3]%add some error x0_2=[xLinear, 0, 1, 0] %x0_2=[1500 1.3 0.5 , 0, 1, 0] [xNonLinear_2,resxNonLinear_2,JxNonLinear_2]= sinusNonLinearFit2(n,lumn,x0_2) %covarianceOutNonLinear_2=zeros(6,6); %covarianceOutNonLinear_2=JxNonLinear_2'*diag(resxNonLinear_2.*resxNonLinear_2)*JxNonLinear_2 %TODO: plot that non linear function and generate the corrected plot %for sinus! %JxNonLinear_2(:,4)=0 pol=xNonLinear_2(4:6) %!!!!! NON j'ai estimé le polynome inverse!!!! %xNonLinear_2=xNonLinear_2(1:3); %covarianceOutNonLinear_2=JxNonLinear_2(:,1:3)'*diag(resxNonLinear_2.*resxNonLinear_2)*JxNonLinear_2(:,1:3) %xNonLinear_2(4:6) =pol %covarianceOutNonLinear_2(6,6)=0 %W=diag(resxNonLinear_2.*resxNonLinear_2); %covarianceInNonLinear=inv(W) %covarianceInNonLinear=eye(128); %InformationOutNonLinear_2= (JxNonLinear_2'*covarianceInNonLinear*JxNonLinear_2) %covarianceOutNonLinear_2= inv(InformationOutNonLinear_2) resxNonLinear_2 %mean of absolute value of errr mean (abs(resxNonLinear_2),1) variance=var(resxNonLinear_2) variancebis=mean(resxNonLinear_2.*resxNonLinear_2) %>give approximately the variance if the mean is close to 0 (no bias) varianceter=(resxNonLinear_2'*resxNonLinear_2)/nbPointsPerPeriod standardDeviation=variance^0.5 % W1=eye(size(resxNonLinear_2,1))*variance^-1; %W2=diag( ((resxNonLinear_2.*resxNonLinear_2)*nbPointsPerPeriod).^-1 ) %W2=diag( ((resxNonLinear_2.^2)*nbPointsPerPeriod).^-1 ) %the squared error is computed for each data point, with a sample size of %one, so the variance of this 1 set is equal o val^2/1 %W2=diag( ((resxNonLinear_2.^2)).^-1 ); %<==> W2=diag( (resxNonLinear_2.^-2)) %traceW1=trace(W1) %MtraceW2=trace(W2) %return %[diag(W1),diag(W2)]'*ones(128,2) %return W=W1; %processing of uncertainty using the whole set of parameters lead to %non invertible information matrix InformationOutNonLinear_2= (JxNonLinear_2'*W*JxNonLinear_2) covarianceOutNonLinear_2= inv(InformationOutNonLinear_2) %= InformationOutNonLinear_2^-1 [u,s,v]=svd(covarianceOutNonLinear_2) covarianceOutNonLinear_2-( u*s*v') sinv=zeros(6,6); for i=1:6 s(i,i) %The sixth term is e-13 and the first is e+16, poor conditionning if (i~=6) sinv(i,i)=1/s(i,i); end end %sinv=inv(s) sinv inverse=v*sinv*u' for i=1:6 inverse(i,i) end rank(covarianceOutNonLinear_2) inverse*covarianceOutNonLinear_2 if false end %work on a reduced version focucing on the sinusoidal function parameters, %because the information matrix is of rank 3 only! JxNonLinear_2red=JxNonLinear_2(:,1:3); InformationOutNonLinear_2= (JxNonLinear_2red'*W*JxNonLinear_2red) rank(InformationOutNonLinear_2) covarianceOutNonLinear_2= inv(InformationOutNonLinear_2) covarianceOutNonLinear_2(1,1) covarianceOutNonLinear_2(2,2) covarianceOutNonLinear_2(3,3) %add 0s to the covariance matrix so it can be displayed later covarianceOutNonLinear_2(6,6)=0; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% figure subplot(1,3,1); %xx=1:255; xx=1:(2^12)-1; yy=polyval(pol,xx); plot(xx, yy,'r-') subplot(1,3,2); hold on plot(n, lum,'r+') displaySin(min(n)-1,max(n)+1,xPerfect,'r-'); plot(n, lumn,'b+') displaySin(min(n)-1,max(n)+1,xLinear,'k:'); displaySin(min(n)-1,max(n)+1,xNonLinear,'g--'); displaySinNonLinear(min(n)-1,max(n)+1,xNonLinear_2,'b--'); legend('data without noise','function without noise','data with noise','fitted function using linear method','fitted function using non linear method','fitted function using non linear method and non linear correction') subplot(1,3,3); %resxNonLinear=randn(size(resxNonLinear,1),1); resToPlot=resxNonLinear_2; numberOfBinsToPlot=12; maxErr=round(max(abs(resToPlot)))+1; binranges = [-maxErr:maxErr/(numberOfBinsToPlot-2):maxErr]; %binranges = [-maxErr:maxErr/10:maxErr]; nbBins=size(binranges,1); [nelements,ind] =histc(resToPlot,binranges); plot(binranges,nelements*nbBins/nbPointsPerPeriod,'r+'); hold on plot(resToPlot,zeros(size(resToPlot,1)),'g+'); meanOfError=mean(resToPlot) varianceOfError=var(resToPlot) standardDeviationOfError=sqrt(varianceOfError) gaussianSamplesx=[-maxErr:0.1:maxErr]; gaussianSamplesy=(1/sqrt(2*pi*varianceOfError))*exp(-( ((gaussianSamplesx-meanOfError).^2)/(2*varianceOfError))); plot(gaussianSamplesx, gaussianSamplesy ,'b-'); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% displayResult(xPerfect, covarianceOutPerfect,'xPerfect ' ) displayResult(xLinear, covarianceOutLinear,'xLinear ' ) displayResult(xNonLinear_2, covarianceOutNonLinear_2,'xNonLinear_2 ' ) %convert the 3sigma uncertainty in phase to pixel position pixelPeriod=16 phase3sigma=3*sqrt(covarianceOutLinear(3,3)) pixelLocation3Sigma=phase3sigma*pixelPeriod/(2*pi) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %compare the distribution of the error with the theroretic one using the %Cumulative distribution function figure resxNonLinear_2sorted=sort(resxNonLinear_2); plot(resxNonLinear_2sorted,n/nbPointsPerPeriod,'r-'); %fonction de répartition: https://en.wikipedia.org/wiki/Normal_distribution variance=var(resxNonLinear_2sorted); x=[-5*sqrt(variance):5*sqrt(variance)]'; for i=1:size(x,1) y(i)=(1/2)*(1+erf( (x(i)-mean(resxNonLinear_2sorted))/(sqrt(variance)*sqrt(2)))); end hold on plot(x,y,'b-'); legend('observed','ideal') title('Cumulative distribution function') end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x,resx,Jx]= sinusNonLinearFit(datax,datay,x0) global gdatax global gdatay gdatax=datax; gdatay=datay; [res0] = myfun2(x0); options = optimset('Jacobian','on','Display','iter', 'MaxFunEvals',200, 'Algorithm' ,{'levenberg-marquardt',.005}); [x,resnorm,residual,exitflag] = lsqnonlin(@myfun2,x0,-Inf,+Inf,options); % Invoke optimizer %[resxPerfect] = myfun2(xPerfect); %norm(resxPerfect,2) [resx,Jx] = myfun2(x); norm(resx,2) end%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [res,J] = myfun2(x) global gpuls global gdatax global gdatay ofs=x(1); amp=x(2); phas=x(3); nbdata=max(size(gdatax)); res=zeros(nbdata,1); J=zeros(nbdata,3); %J2=zeros(nbdata,3); for i=1:nbdata t=gdatax(i); ymes=gdatay(i); y=ofs+amp*sin(gpuls*t+phas); res(i)=ymes-y; %jacobian for residuals J(i,:)=[ -1, - cos(gpuls*t)*sin(phas) - sin(gpuls*t)*cos(phas), amp*sin(gpuls*t)*sin(phas) - amp*cos(gpuls*t)*cos(phas)]; %jacobian for residuals^2 %J2(i,:)=[ 2*ofs - 2*ymes + 2*amp*cos(puls*t)*sin(phas) + 2*amp*sin(puls*t)*cos(phas), % 2*(cos(puls*t)*sin(phas) + sin(puls*t)*cos(phas))*(ofs - ymes + amp*cos(puls*t)*sin(phas) + amp*sin(puls*t)*cos(phas)), % 2*(amp*cos(puls*t)*cos(phas) - amp*sin(puls*t)*sin(phas))*(ofs - ymes + amp*cos(puls*t)*sin(phas) + amp*sin(puls*t)*cos(phas))]; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [res] = displaySin(tmin,tmax,x,style) global gpuls ofs=x(1); amp=x(2); phas=x(3); t=tmin:0.1:tmax; recons=ofs+amp*sin(gpuls.*t+phas); plot(t,recons,style) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x,resx,Jx]= sinusNonLinearFit2(datax,datay,x0) global gdatax global gdatay gdatax=datax; gdatay=datay; %[res0] = myfun3(x0); options = optimset('Jacobian','on','Display','iter', 'MaxFunEvals',200, 'Algorithm' ,{'levenberg-marquardt',.005}); %options = optimset('Jacobian','off','Display','iter', 'MaxFunEvals',200, 'Algorithm' ,{'levenberg-marquardt',.005}); [x,resnorm,resx,exitflag,output,lambda,Jx] = lsqnonlin(@myfun3,x0,-Inf,+Inf,options); % Invoke optimizer %perturbate to add bias %resx=resx+100*ones(size(resx,2)); %[resxPerfect] = myfun2(xPerfect); %norm(resxPerfect,2) %[resx,Jx] = myfun3(x); norm(resx,2) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [res,J] = myfun3(x) global gpuls global gdatax global gdatay ofs=x(1); amp=x(2); phas=x(3); nla=x(4); nlb=x(5); nlc=x(6); nbdata=max(size(gdatax)); res=zeros(nbdata,1); J=zeros(nbdata,6); %J2=zeros(nbdata,3); for i=1:nbdata t=gdatax(i); ymes=gdatay(i); yperfect=ofs+amp*sin(gpuls*t+phas); y=nla * yperfect^2 + nlb * yperfect + nlc; res(i)=ymes-y; %jacobian for residuals J(i,:)=[ - nlb - 2*nla*ofs - 2*amp*nla*cos(gpuls*t)*sin(phas) - 2*amp*nla*sin(gpuls*t)*cos(phas) - nlb*cos(gpuls*t)*sin(phas) - nlb*sin(gpuls*t)*cos(phas) - 2*amp*nla*cos(gpuls*t)^2*sin(phas)^2 - 2*amp*nla*sin(gpuls*t)^2*cos(phas)^2 - 2*nla*ofs*cos(gpuls*t)*sin(phas) - 2*nla*ofs*sin(gpuls*t)*cos(phas) - 4*amp*nla*cos(gpuls*t)*sin(gpuls*t)*cos(phas)*sin(phas) amp*nlb*sin(gpuls*t)*sin(phas) - amp*nlb*cos(gpuls*t)*cos(phas) - 2*amp*nla*ofs*cos(gpuls*t)*cos(phas) - 2*amp^2*nla*cos(gpuls*t)*sin(gpuls*t)*cos(phas)^2 + 2*amp^2*nla*cos(gpuls*t)*sin(gpuls*t)*sin(phas)^2 + 2*amp*nla*ofs*sin(gpuls*t)*sin(phas) - 2*amp^2*nla*cos(gpuls*t)^2*cos(phas)*sin(phas) + 2*amp^2*nla*sin(gpuls*t)^2*cos(phas)*sin(phas) - ofs^2 - amp^2*cos(gpuls*t)^2*sin(phas)^2 - amp^2*sin(gpuls*t)^2*cos(phas)^2 - 2*amp*ofs*cos(gpuls*t)*sin(phas) - 2*amp*ofs*sin(gpuls*t)*cos(phas) - 2*amp^2*cos(gpuls*t)*sin(gpuls*t)*cos(phas)*sin(phas) - ofs - amp*cos(gpuls*t)*sin(phas) - amp*sin(gpuls*t)*cos(phas) -1]'; % [ -1, % - cos(gpuls*t)*sin(phas) - sin(gpuls*t)*cos(phas), % amp*sin(gpuls*t)*sin(phas) - amp*cos(gpuls*t)*cos(phas)]; %jacobian for residuals^2 %J2(i,:)=[ 2*ofs - 2*ymes + 2*amp*cos(puls*t)*sin(phas) + 2*amp*sin(puls*t)*cos(phas), % 2*(cos(puls*t)*sin(phas) + sin(puls*t)*cos(phas))*(ofs - ymes + amp*cos(puls*t)*sin(phas) + amp*sin(puls*t)*cos(phas)), % 2*(amp*cos(puls*t)*cos(phas) - amp*sin(puls*t)*sin(phas))*(ofs - ymes + amp*cos(puls*t)*sin(phas) + amp*sin(puls*t)*cos(phas))]; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [res] = displaySinNonLinear(tmin,tmax,x,style) global gpuls ofs=x(1); amp=x(2); phas=x(3); nla=x(4); nlb=x(5); nlc=x(6); t=tmin:0.1:tmax; reconsperfect=ofs+amp*sin(gpuls.*t+phas); recons=nla * reconsperfect.^2 + nlb * reconsperfect + nlc; plot(t,recons,style) end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [X covarianceOut]=fitSinusLinear(datax,datay,puls) %linear method for known pulsation %https://fr.mathworks.com/matlabcentral/fileexchange/41246-sine-function-fit global gnoiseLevel symbolicComputation=false nbdata=max(size(datax)); A=zeros(nbdata,3); B=zeros(nbdata,1); for i=1:nbdata t=datax(i); ymes=datay(i); B(i)=ymes; dx=puls*t; A(i,:)= [1 cos(dx) sin(dx)] ; end C=(A'*A)^(-1)*A'; %solve the system by expressing it as a linear product Xa=C*B; %propagate uncertainty from datay to Xa estimateVarianceFromMSE=true if ~estimateVarianceFromMSE varianceIn=gnoiseLevel^2 * eye(nbdata); else %in real case, the input variance should be estimated thanks to the MSE %varianceIn=zeros(nbdata); %for i=1:nbdata %t=datax(i); %ymes=datay(i); %dx=puls*t; %ypred=(Xa(1)*1+ Xa(2)* cos(dx) + Xa(3)* sin(dx)); %err=ymes- ypred; %varianceIn(i,i)=err^2; %end err=A*Xa-B; varianceIn=diag(err.*err); end %covariance for the internal parameterization covarianceOutIntern=C*varianceIn*C'; %check if there is covariance (diag matrix) covarianceOutIntern-diag([covarianceOutIntern(1,1), covarianceOutIntern(2,2), covarianceOutIntern(3,3)]); %this uncertainty has to be transfered to the final parameterization if symbolicComputation a=sym('a','real'); a=a; b1 = sym('b1','real'); b2 = sym('b2','real'); b=sqrt(b1*b1+b2*b2); %c=wrapTo2Pi(atan2(b1,b2)); %bring c between 0 and 2pi c=atan(b1/b2); %bring c between 0 and 2pi jacobian(b,[b1,b2]) % [ b1/(b1^2 + b2^2)^(1/2), b2/(b1^2 + b2^2)^(1/2)] jacobian(c,[b1,b2]) % [ 1/(b2*(b*1^2/b2^2 + 1)), -b1/(b2^2*(b1^2/b2^2 + 1))] jacobian([a,b,c],[a,b1,b2]) %[1, 0 , 0; %0, b1/(b1^2 + b2^2)^(1/2), b2/(b1^2 + b2^2)^(1/2); %0, 1/(b2*(b1^2/b2^2 + 1)), -b1/(b2^2*(b1^2/b2^2 + 1))] end a=Xa(1); b1=Xa(2); b2=Xa(3); %compute b & c b=sqrt(b1*b1+b2*b2); c=wrapTo2Pi(atan2(b1,b2)); %bring c between 0 and 2pi %compare c with %wt*ud JJ=[1, 0 , 0; 0, b1/(b1^2 + b2^2)^(1/2), b2/(b1^2 + b2^2)^(1/2); 0, 1/(b2*(b1^2/b2^2 + 1)), -b1/(b2^2*(b1^2/b2^2 + 1))] covarianceOut=JJ*covarianceOutIntern*JJ' covarianceOut-diag([covarianceOut(1,1), covarianceOut(2,2), covarianceOut(3,3)]); X=[a b c]; if symbolicComputation cdx1 = sym('cdx1','real'); sdx1 = sym('sdx1','real'); y1= sym('y1', 'real'); cdx2 = sym('cdx2','real'); sdx2 = sym('sdx2','real'); y2= sym('y2', 'real'); cdx3 = sym('cdx3','real'); sdx3 = sym('sdx3','real'); y3= sym('y3', 'real'); cdx4 = sym('cdx4','real'); sdx4 = sym('sdx4','real'); y4= sym('y4', 'real'); A=[1 cdx1 sdx1; 1 cdx2 sdx2; 1 cdx3 sdx3] B=[y1;y2;y3] solution=simplify((A'*A)^(-1)*A'*B) A=[1 cdx1 sdx1; 1 cdx2 sdx2; 1 cdx3 sdx3; 1 cdx4 sdx4] B=[y1;y2;y3;y4] C=simplify((A'*A)^(-1)*A') leastSquaresSolution=simplify(C*B) %practically, an incremental algorithm should keep track of the %symetric matrix %(A'*A)=[ 4, cdx1 + cdx2 + cdx3 + cdx4, sdx1 + sdx2 + sdx3 + sdx4] % [ cdx1 + cdx2 + cdx3 + cdx4, cdx1^2 + cdx2^2 + cdx3^2 + cdx4^2, cdx1*sdx1 + cdx2*sdx2 + cdx3*sdx3 + cdx4*sdx4] % [ sdx1 + sdx2 + sdx3 + sdx4, cdx1*sdx1 + cdx2*sdx2 + cdx3*sdx3 + cdx4*sdx4, sdx1^2 + sdx2^2 + sdx3^2 + sdx4^2] %and the vector %(A'*B)= [y1 + y2 + y3 + y4 % cdx1*y1 + cdx2*y2 + cdx3*y3 + cdx4*y4 % sdx1*y1 + sdx2*y2 + sdx3*y3 + sdx4*y4] var1 = sym('var1','real'); var2 = sym('var2','real'); var3 = sym('var3','real'); var4 = sym('var4','real'); %for constant known variance on input data varIn=diag([var1,var1,var1,var1]); simplify(A'*varIn*A) %[ 4*var1, var1*(cdx1 + cdx2 + cdx3 + cdx4), var1*(sdx1 + sdx2 + sdx3 + sdx4)] %[ var1*(cdx1 + cdx2 + cdx3 + cdx4), var1*(cdx1^2 + cdx2^2 + cdx3^2 + cdx4^2), var1*(cdx1*sdx1 + cdx2*sdx2 + cdx3*sdx3 + cdx4*sdx4)] %[ var1*(sdx1 + sdx2 + sdx3 + sdx4), var1*(cdx1*sdx1 + cdx2*sdx2 + cdx3*sdx3 + cdx4*sdx4), var1*(sdx1^2 + sdx2^2 + sdx3^2 + sdx4^2)] %for variances obtained from MSE varIn=diag([var1,var2,var3,var4]); simplify(A'*varIn*A) %[ var1 + var2 + var3 + var4, cdx1*var1 + cdx2*var2 + cdx3*var3 + cdx4*var4, sdx1*var1 + sdx2*var2 + sdx3*var3 + sdx4*var4] %[ cdx1*var1 + cdx2*var2 + cdx3*var3 + cdx4*var4, var1*cdx1^2 + var2*cdx2^2 + var3*cdx3^2 + var4*cdx4^2, cdx1*sdx1*var1 + cdx2*sdx2*var2 + cdx3*sdx3*var3 + cdx4*sdx4*var4] %[ sdx1*var1 + sdx2*var2 + sdx3*var3 + sdx4*var4, cdx1*sdx1*var1 + cdx2*sdx2*var2 + cdx3*sdx3*var3 + cdx4*sdx4*var4, var1*sdx1^2 + var2*sdx2^2 + var3*sdx3^2 + var4*sdx4^2] end end % A.X=B % A'.A.X=A'.B %p 31 of http://www.stat.columbia.edu/~fwood/Teaching/w4315/Fall2009/lecture_11 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function displayResult(res,covar,name) %display mean and 3Sigma values nbdata=max(size(res)); s=''; s=sprintf('%s :',name); for n=1:nbdata s=sprintf('%s %d +/- %d ,',s,res(n),3*sqrt(covar(n,n))); end disp(s); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function test() %computation of the inverse of a symetric 3x3 matrix if false a1 = sym('ATAa1','real'); b1 = sym('ATAb1','real'); c1 = sym('ATAc1','real'); d1 = sym('ATAd1','real'); e1 = sym('ATAe1','real'); f1 = sym('ATAf1','real'); A1=[a1 b1 c1 ; b1 d1 e1; c1 e1 f1] % a2 = sym('a2','real'); % b2 = sym('b2','real'); % c2 = sym('c2','real'); % d2 = sym('d2','real'); % e2 = sym('e2','real'); % f2 = sym('f2','real'); % A2=[a2 b2 c2 ; b2 d2 e2; c2 e2 f2] % prod=A1*A2 % equations=reshape(prod-eye(3),9,1) % solve(equations(1:6),[a2 b2 c2 d2 e2 f2]) % solve(equations(1:6),a2 ) % http://www.tutorvista.com/content/math/inverse-of-symmetric-matrix/ % A-1= adj(A)/det(A) A2tmp=adjoint(A1) determinant=det(A1) A2=A2tmp/determinant end end function [X covarianceOut, err]=fitSinusLinearOptimized(datax,datay,puls) nbdata=max(size(datax)); A=zeros(nbdata,3); B=zeros(nbdata,1); err=zeros(nbdata,1); var=zeros(nbdata,1); ATA=zeros(3,3); ATB=zeros(3,1); ATAa=0; ATAb=0; ATAc=0; ATAd=0; ATAe=0; ATAf=0; ATBa=0; ATBb=0; ATBc=0; cdx=zeros(nbdata,1); sdx=zeros(nbdata,1); cdx2=zeros(nbdata,1); sdx2=zeros(nbdata,1); cdxsdx=zeros(nbdata,1); for i=1:nbdata x=datax(i); y=datay(i); B(i)=y; dx=puls*x; cx=cos(dx); sx=sin(dx); cx2=cx*cx; sx2=sx*sx; cxsx=cx*sx; cdx(i)=cx; sdx(i)=sx; cdx2(i)=cx2; sdx2(i)=sx2; cdxsdx(i)=cxsx; ATAa=ATAa+1; ATAb=ATAb+cx; ATAc=ATAc+sx; ATAd=ATAd+cx2; ATAe=ATAe+cxsx; ATAf=ATAf+sx2; ATBa=ATBa+y; ATBb=ATBb+cx*y; ATBc=ATBc+sx*y; end %complete symetric matrices %ATA=[ATAa , ATAb , ATAc ; ATAb , ATAd , ATAe ; ATAc , ATAe , ATAf]; %ATB=[ATBa , ATBb , ATBc ]'; %leastSquaresSolution=inv(ATA)* ATB %a=leastSquaresSolution(1); %b1=leastSquaresSolution(2); %b2=leastSquaresSolution(3); determinant =- ATAf*ATAb^2 + 2*ATAb*ATAc*ATAe - ATAd*ATAc^2 - ATAa*ATAe^2 + ATAa*ATAd*ATAf; ATAinva= (ATAd*ATAf - ATAe^2 )/determinant; ATAinvb= (ATAc*ATAe - ATAb*ATAf )/determinant; ATAinvc= (ATAb*ATAe - ATAc*ATAd )/determinant; ATAinvd= (ATAa*ATAf - ATAc^2 )/determinant; ATAinve= (ATAb*ATAc - ATAa*ATAe )/determinant; ATAinvf= (ATAa*ATAd - ATAb^2 )/determinant; ATAinv=[ ATAinva ATAinvb ATAinvc; ATAinvb ATAinvd ATAinve; ATAinvc ATAinve ATAinvf]; a =ATAinva * ATBa + ATAinvb * ATBb + ATAinvc * ATBc; b1=ATAinvb * ATBa + ATAinvd * ATBb + ATAinve * ATBc; b2=ATAinvc * ATBa + ATAinve * ATBb + ATAinvf * ATBc; Xa=[a b1 b2] %compute b & c b=sqrt(b1*b1+b2*b2); c=wrapTo2Pi(atan2(b1,b2)); %bring c between 0 and 2pi X=[a b c ]; %compute MSE and variance.... ATVarAa=0; ATVarAb=0; ATVarAc=0; ATVarAd=0; ATVarAe=0; ATVarAf=0; for i=1:nbdata er= 1 * a + cdx(i,1) * b1 + sdx(i,1) * b2; vari= er*er; err(i)=er; var(i)=vari; ATVarAa= ATVarAa + vari; ATVarAb= ATVarAb + cdx(i,1) * vari; ATVarAc= ATVarAc + sdx(i,1) * vari; ATVarAd= ATVarAd + cdx2(i,1) * vari; ATVarAe= ATVarAe + cdx(i,1)*sdx(i,1) * vari; ATVarAf= ATVarAf + sdx2(i,1) * vari; end ATVarA=[ ATVarAa ATVarAb ATVarAc; ATVarAb ATVarAd ATVarAe; ATVarAc ATVarAe ATVarAf]; covarianceOutIntern=ATAinv'*ATVarA*ATAinv; JJ=[1, 0 , 0; 0, b1/(b1^2 + b2^2)^(1/2), b2/(b1^2 + b2^2)^(1/2); 0, 1/(b2*(b1^2/b2^2 + 1)), -b1/(b2^2*(b1^2/b2^2 + 1))]; covarianceOut=JJ*covarianceOutIntern*JJ'; end