Physics 114: Lecture 19 Least Squares Fit to 2D Data Dale E. Gary NJIT Physics Department Nonlinear Least Squares Fitting We saw that for a function y(x) the chi-square is 2 y y ( x ) 2 i i which can be used to fit a curve to data points yi. In just the same way, we can easily extend this idea to fitting a function z(x,y), that is, a surface, to a 2D data set of measurements zi(x,y). 2 z z ( x, y ) 2 i 2 i x b c You know that it takes three parameters to fit a Gaussian curve y ( x) ae . To extend this to a 2D Gaussian is straightforward. It is: 2 z ( x, y) ae x b1 y b2 c1 c2 2 . Note that this has 5 parameters, but the most general way to describe a 2D Gaussian actually has 6 parameters, which you will do for homework. Apr 19, 2010 Plotting a 2D Gaussian in MatLAB Let’s introduce some useful MatLAB commands for creating a 2D Gaussian. 2D Gaussian with 5 Parameters One can use a brute force method such as -5 z = zeros(101,101); a = 2.5; bx = 2.3; by = -1.2; cx = 1.5; cy = 0.8; i = 0; for x = -5:0.1:5 i = i + 1; j = 0; for y = -5:0.1:5 j = j + 1; z(i,j) = a*exp(-((x-bx)/cx)^2 – ((y-by)/cy)^2); end end imagesc(-5:0.1:5,-5:0.1:5,z) -4 -3 -2 -1 y 0 1 2 3 4 5 -5 Or, we can plot it as a surface to provide x and y coordinates 0 x surf(-5:0.1:5,-5:0.1:5,z) Apr 19, 2010 5 Better Way of Creating 2D Functions That way of using for loops is a very slow, so here is another way of doing it for “round” Gaussians: x = -5:0.1:5; y = -5:0.1:5; siz = size(x); siz = siz(2); a = 2.5; bx = 2.3; by = -1.2; c = 0.8; dist = zeros(siz,siz); for i=1:siz for j=1:siz dist(i,j) = x(i)^2 + y(j)^2; % Create “distance” array once end end % use the next two statements multiple times for different Gaussians sdist = circshift(dist,round([bx/0.1,by/0.1])); % Shifted “distance” array z = a*exp(-sdist/c); imagesc(x,y,z); Apr 19, 2010 Best Way of Creating 2D Functions The best way, however, is to use the meshgrid() MatLAB function: [x, y] = meshgrid(-5:.1:5, -5:.1:5); a = 2.5; bx = 2.3; by = -1.2; cx = 1.5; cy = 0.8; z = a*exp( - (((x-bx)/cx).^2 + ((y-by)/cy).^2) ; surf(x,y,z); This is completely general, and allows vector calculations which are very fast. 4 Here is another example, the sinc() function: z = a*sinc(sqrt(((x-bx)/cx).^2 + ((y-by)/cy).^2)); 2 You can see that the meshgrid() function is 0 -2 very powerful as a shortcut for 2D function 5 calculation. To add noise, just add sig*randn(size(z)), where sig is the standard deviation of the noise. 0 5 0 -5 -5 Apr 19, 2010 Searching Parameter Space in 2D Just as we did in the 1D case, searching parameter space is just a trial and error exercise. % Initial values around which to search a0 = max(max(z)); [ix iy] = find(z == a0); bx0 = x(ix,iy); by0 = y(ix,iy); cx0 = 1; cy0 = 1; astep = 0.05; bstep = 0.05; cstep = 0.05; chisqmin = 1e20; for a = a0-5*astep:astep:a0+5*astep for bx = bx0-5*bstep:bstep:bx0+5*bstep for by = by0-5*bstep:bstep:by0+5*bstep for cx = cx0-5*cstep:cstep:cx0+5*cstep for cy = cy0-5*cstep:cstep:cy0+5*cstep ztest = a*exp(-(((x-bx)/cx).^2 + ((y-by)/cy).^2)); chisq = sum(sum(((ztest-z)/sig).^2)); if (chisq < chisqmin); chisqmin = chisq; params = [a,bx,by,cx,cy]; end end end end params = 2.1465 2.3000 -1.2000 1.2500 end end 0.8000 Apr 19, 2010 The Result Looks Good, but… To calculate the result of the fit, just type ztest = params(1)*exp(-(((x-params(2))/params(4)).^2 + ((y-params(3))/params(5)).^2)); imagesc(x(1,:),y(:,1),ztest) -5 This gives a reasonable result, but compare the fit parameters with the (known) params: a = 2.1; bx = 2.3; by = -1.2; cx = 1.3; cy = 0.8; params = 2.15 2.3 -1.2 1.25 0.8 The value of cx is especially far off, because our search window was limited to 0.75-1.25, so it could not reach 1.3. Look at the residuals: -4 -3 -2 -1 0 1 2 3 4 5 -5 -4 -3 -2 -1 0 1 imagesc(x(1,:),y(:,1),ztest-z) Can you see a pattern in the noise? To bring out the pattern better, let’s introduce convolution. Apr 19, 2010 2 3 4 5 1D Convolution and Smoothing 2 2 Let’s create a noisy sine wave: 11 u = -5:.1:5; w = sin(u*pi)+0.5*randn(size(u)); plot(u,w) 0.5 We can now smooth the data by convolving it with a vector [1,1,1], which does a 3-point running sum. wsm = conv(w,[1,1,1]); whos wsm Name wsm Size 1x103 Bytes Class Attributes 824 double sin(u) w w wsm 1.5 00 -0.5 -1 -1 -1.5 -2 -5 -2 -5 0 u0 u conv(w, k ) (w * k )(t ) w( )k (t )d Notice wsm is now of length 103. That means we cannot plot(u,wsm), but we can plot(u,wsm(2:102)). Now we see another problem. Try this: plot(u,w) hold on; plot(u,wsm(2:102)/3,’r’) Apr 19, 2010 5 5 2D Convolution To do 2D smoothing, we will use a 2D kernel k = ones(3,3), and use the conv2() function. So to smooth the residuals of our fit, we can use zsm = conv2(ztest-z,k)/9.; imagesc(x,y,zsm(2:102,2:102)) Now we can see the effect of missing the value of cx by 0.05 due to our limited search range. There are other uses for convolution, such as edge detection. For example, we can convolve with a kernel k = [1,1,1,1,1,1]. Or a kernel k = [1,1,1,1,1,1]’. Or even a kernel k = eye(6). Or k = rot90(eye(6)). -5 0 5 -5 0 Apr 19, 2010 5