First we need a spectrum from CAMB:
x=load('camb_spectrum.txt'); % first col is ell, then TT, TE, EE, BB spectra % (throw out monopole and dipole to prevent touble later) l=x(3:end,1); Cs_l=x(3:end,2:5); plot(l,Cs_l(:,1)); % we want raw C_l - remove the conventional prefactor pf=2*pi./(l.*(l+1)); C_l=Cs_l.*repmat(pf,[1,4]); semilogy(l,C_l(:,1));
imagesc(randn(8));However in order to have a real Fourier transform the random numbers need to be complex and conjugate symmetric about zero frequency and some of them need to be purely real - Cf the \(a_{l,m}\)'s above. Here is a function randn_ft_of_real which delivers the necessary symmetries:
f=randn_ft_of_real(8) imagesc(imag(f)==0)The Fourier transform of these is simply real Gaussian random numbers:
i=fftshift(fft2(fftshift(f))) imagesc(i)The fft function assumes that the zero frequency is in the upper-left corner, with frequency increasing to the middle, and then wrapping around to maximally negative frequency and increasing again back to zero. I find it more convenient to keep zero frequency in the middle - hence the fftshift functions.
Let's make a convenience function which sets up "axis data" for both image and Fourier planes - calc_ad.m. Remember: when going from image to Fourier space (and vice versa) reciprocal of span is resolution, and vice versa. The Fourier space analog of angle \(\theta\) is conventionally denoted \(u\).
% a 20x20 chunk of sky with 256x256 pixels ad=calc_ad(20,256); % look at the radial distance from the origin in F plane imagesc(ad.u_val,ad.u_val,ad.u_r)
% complex random modes with real FT f=randn_ft_of_real(ad.npix); % 2d grid of ell values % - if we increase the image space resolution we increase the ell space span imagesc(ad.l_val,ad.l_val,ad.u_r*2*pi); colorbar % interpolate to these floating point ell values from integer ell values % - this is just 1d power spectrum in 2d radial form plot(l,sqrt(Cs_l(:,1))); imagesc(ad.l_val,ad.l_val,interp1(l,sqrt(Cs_l(:,1)),ad.u_r*2*pi)); % envelope the random numbers - we really want C_l rather than Cs_l fp=f.*interp1(l,sqrt(C_l(:,1)),ad.u_r*2*pi,[],0); imagesc(ad.l_val,ad.l_val,real(fp))
im=fftshift(fft2(fftshift(fp))); imagesc(ad.t_val_deg,ad.t_val_deg,real(im)); colorbar; axis imageWe can compare this to the maps shown in SPT-3G paper fig1 - although that is much smaller chunk of sky.
ad=calc_ad(10,256) % make some random E-modes f=randn_ft_of_real(ad.npix); % envelope with the EE spectrum Ef=f.*interp1(l,sqrt(C_l(:,3)),ad.u_r*2*pi,[],0); % take the B-modes as zero Bf=zeros(size(Ef)); % take the angle of each F-mode in the u/v plane [u,v]=meshgrid(ad.u_val,ad.u_val); chi=-atan2(v,u)+pi/2; imagesc(ad.u_val,ad.u_val,chi); axis xy; colorbar % rotate from E/B to Q/U Qf=+Ef.*cos(2*chi)+Bf.*sin(2*chi); Uf=+Ef.*sin(2*chi)-Bf.*cos(2*chi); % render Q/U maps Qi=fftshift(fft2(fftshift(Qf))); Ui=fftshift(fft2(fftshift(Uf))); % look at the result imagesc(ad.t_val_deg,ad.t_val_deg,real(Qi)); colorbar; axis image imagesc(ad.t_val_deg,ad.t_val_deg,real(Ui)); colorbar; axis imagePerhaps counter-intuitively Q/U maps for an all-E, zero-B sky pattern do have a preferred direction - Q is vert/horiz stripy, and U diagonal stripy. But this is just due to the direction that we select to measure the polarization pseudovector angle from (which in this case is the direction of the north celestial pole).
Before we move on make T map to match Q/U maps:
f=randn_ft_of_real(ad.npix); Tf=f.*interp1(l,sqrt(C_l(:,1)),ad.u_r*2*pi,[],0); Ti=fftshift(fft2(fftshift(Tf)));
nx=200; ny=33; % make the out-back scan in azimuth (x) direction % (imagine the telescope can turn around instantly) x=linspace(-4,4,nx/2); x=[x,fliplr(x)]; plot(x); % make the steps in elevation (y) direction y=linspace(-4,4,ny)'; plot(y); % expand out to the full grid x=repmat(x,[ny,1]); y=repmat(y,[1,nx]); % flip them and then vectorize % (seems to be no way to vectorize along rows...) x=x'; y=y'; x=x(:); y=y(:); % overlay trajectory on T map imagesc(ad.t_val_deg,ad.t_val_deg,real(Qi)); colorbar; axis image hold on plot(x,y,'r'); xlim([-5,5]); ylim([-5,5]); hold off
% first in 1d n=ad.npix/2+1; xv=ad.t_val_deg(n-15:n+15); plot(xv,gauss([1,0,0.5/2.35],xv)); % now in 2d [xg,yg]=meshgrid(xv,xv); r=sqrt(xg.^2+yg.^2); imagesc(xv,xv,r) beam=gauss([1,0,0.5/2.35],r); imagesc(xv,xv,beam)Now convolve the maps with beam:
% ensure convolution does not change normalization beam=beam/sum(beam(:)); % same switch means output map same size as input Ts=conv2(real(Ti),beam,'same'); Qs=conv2(real(Qi),beam,'same'); Us=conv2(real(Ui),beam,'same'); imagesc(ad.t_val_deg,ad.t_val_deg,Ts); colorbar; axis image
% interpolate from maps psiA=pi/4; % make the map as seen by a detector at this angle As=Ts+Qs*cos(2*psiA)+Us*sin(2*psiA); imagesc(ad.t_val_deg,ad.t_val_deg,As); colorbar; axis image at=interp2(ad.t_val_deg,ad.t_val_deg,As,x,y); % now do the same for an orthogonal detector psiB=psiA+pi/2; Bs=Ts+Qs*cos(2*psiB)+Us*sin(2*psiB); bt=interp2(ad.t_val_deg,ad.t_val_deg,Bs,x,y); % plot A/B timestreams for first two out-back moves plot(at) hold on plot(bt,'r') hold off xlim([0,400])
at=at+3*randn(size(at)); bt=bt+3*randn(size(bt)); plot(at) hold on plot(bt,'r') hold off xlim([0,400])
Better would be a web page or similar which intersperses the Matlab code with figures showing the state at appropriate points through the process.
Assignment is due 10am Monday March 7 by email to pryke@physics.umn.edu