;+ ; NAME: modprofile2vis ; ; PURPOSE: ; To convert HESSI modulation profiles for one half rotation ; into visibilities using calibrated phases at map center ; ; METHOD: ; ; a. Gets the ang_pitch from det_index using hessi_params() ; b. Finds the cycle period function from phase_map_ctr(roll_angle) ; ; Explanation: ; If aspect offsets were all zero, the phase_map_ctr would be ; equal to 2*!pi*r_map*cos(roll_angle + const), and on a ; range of roll angles spanning 180 deg, the ; phase_map_ctr function is purely sinusoidal with ; one absolute maximum and a minimum magnitude of 0. ; In general, the slowest modulation occurs when ; abs(phase_map_ctr) = 0, and fastest modulation occurs ; at roll angles 90 degrees earlier or later. ; But when aspect offsets are non zero, phase_map_ctr is ; only approximately sinusoidal, so a fit to the phase values ; is made in the form A*sin(roll_angle)+B*cos(roll_angle), ; and this gets us the cycle lengths. ; ; c. Loops through angles, fitting sinusoids of phase_map_ctr to the ; modulation profile values on each modulation cycle ; d. Uses amplitude and phase to create visibility, taking ; appropriate means of the least-square parameters. ; ; INPUTS: ; roll = array of roll angles spanning 180 degrees ; modprof = array of modulation amplitudes, 1 for each ; angle, same array size as roll ; det_index = 0-17 index of HESSI detector ; phase_map_ctr = array of map-center phases (same size as roll) ; ; OPTIONAL INPUTS: ; cycle_factor=cycle_factor (default=0.5) Small values will use ; fewer points in a cycle to do the least-square sinusoidal fit. ; conj_sign=conj_sign (default=1) If negative, the sign of ; sqrt(-1) will be taken to be negative, corresponding to ; mirror source. ; ; OUTPUTS: ; visibilties = amp*exp(i*(pha - localmean(phase_map_ctr))) ; ; ; EXAMPLE: ; N=512 ; ; det_index=4 ; roll_angle=findgen(N)*!pi/N - !pi/4 ; 180 deg of rotation ; params=hessi_params() ; grid_angle=(params.orient)(det_index) ; pitch=(params.pitch)(det_index) ;; Simulate some aspect coords (can be anything): ; x_asp=2.*randomn(seed,N)+100.*cos(roll_angle) ; ; y_asp=2.*randomn(seed,N)+100.*sin(roll_angle) ; ;; Select an inertial map center: ; X_map=600. ; arc sec ; Y_map=200. ;; Compute the spacecraft coords of map center: ; x_map_sc = x_asp + X_map*cos(roll_angle) - Y_map*sin(roll_angle) ; y_map_sc = y_asp + Y_map*cos(roll_angle) + X_map*sin(roll_angle) ; r_map_sc = sqrt(x_map_sc^2+y_map_sc^2) ; ang_sc=atan(y_map_sc,x_map_sc) ; azimuth of map center ; r_map=mean(r_map_sc) ; approx dist from spin axis ;; Choose a value for the peak_resp_offset (normally from hessi_grm): ; peak_resp_offset=!pi/6 ; h=1 ; fundamental ; Harmonics 2,3,... not tested ;; Simulate the array of map-center phases: ; phase_map_ctr=2*!pi*h*(x_map_sc*cos(grid_angle) $ ; +y_map_sc*sin(grid_angle)+peak_resp_offset)/pitch ; phase_map_ctr=2*!pi*h*(r_map_sc*cos(ang_sc-grid_angle) $ ; +peak_resp_offset)/pitch ;; Simulate a modulation profile for a pair of point sources: ; mod_profile=100.*cos(1.05*phase_map_ctr+!PI/6)+80*cos(phase_map_ctr) ;; Convert the modprof to visibilities: ; vis=modprofile2vis(roll_angle,mod_profile,det_index,phase_map_ctr) ; plot,imaginary(vis),xsty=1 & oplot,vis,line=1 ; ;; To test the fit, compare vis to the true visibilities: ; i=complex(0,1) ; vis_true=100.*exp(i*1.05*phase_map_ctr+i*!PI/6)+80*exp(i*phase_map_ctr) ; ; RESTRICTIONS: ; The sign of imaginary(visibility) is indeterminate, but can be selected ; ; VERSION HISTORY: ; VERS. 1 Derived from test_lscoscos.pro -- EJS May 26, 1999. ; VERS. 2 Added /verb option, upgraded variable names ; -- EJS Jun 15, 1999. ; VERS. 3 Corrected several bugs -- EJS June 18, 1999 ; VERS. 4 Eliminated r_map, uses phase_map_ctr only ; -- EJS June 21, 1999 ; 4.1 Reduced storage space requirements immensely by ; wrapping intermediate least-sq fits into a less sparse array. ; Generalized averaging interval by adding optional cycle_factor ; Added option to reverse sign of imaginary part of vis. ; -- EJS June 25, 1999. ; NOTES: ; July 20, 1999: Found that the sign of the imaginary part of (vis) ; is opposite to what was expected. This is not a problem since the ; sign is arbitrary, but an explanation is needed. ; ; Harmonics h=2,3,4,... need to be tested ; Yet to be tested with simulated score data ; Should add optional user input of (rough?) map azimuth to determine ; sign of imaginary part of visibility. ;- function modprofile2vis,roll,modprof,det_index,phase_map_ctr,$ verb=verb,plo=plo,cycle_factor=cycle_factor,conj_sign=conj_sign params=hessi_params() pitch=(params.pitch)((det_index mod 9)) grid_angle=(params.orient)((det_index mod 9)) ;really should update .orient to .grid_angle angle=roll-grid_angle ; if keyword_set(verb) then message,'Computing amplitudes and phases...',/cont nangles=n_elements(roll) amp=roll*0 & A_vector=amp & B_vector=amp & pha=amp & sig=amp & sigma=0. plot,angle/!dtor,phase_map_ctr,tit='Phase of Map Center' ; Find the parameters of the modulation frequency amp_pha=ls_sin_cos(angle,phase_map_ctr,1.0,yfit,sigma,/amp_pha) print,'amp_pha=',amp_pha modulation_freq=amp_pha(0)*abs(sin(angle-amp_pha[1])) oplot,angle/!dtor,modulation_freq ; Set up cycle periods: rmin_cycle_period=2*!pi/amp_pha[0] ; (radians) imin_cycle_period=rmin_cycle_period*180 ; (indices) c=0.75 ; The modulation freq vanishes at one angle, so we don't just invert ; it to get the period. Instead we use period=const/(const + frequency) if (NOT keyword_set(cycle_factor)) then cycle_factor=0.5 di=fix(cycle_factor*imin_cycle_period/ $ (1.-c+c*modulation_freq/max(modulation_freq))) if (min(di) LT 2) then message,'Warning--sample range LT 4',/cont if (keyword_set(plo)) then plot,angle,modprof,xsty=1 i=complex(0,1) if (keyword_set(conj_sign)) then if (conj_sign lt 0) then i=-i i1=(findgen(nangles)-di)>0 i2=(findgen(nangles)+di)<(nangles-1) dmodulo=2*fix(max(di)) ; could also be anyhing from max(di)+1 to nangles ; This array vv will contain the successive amp/phase fits; ; The NaN's are to flag elements with no data so proper averages ; can be made. ; A side effect is to cause spurious "Floating illegal operand" ; messages. vv=complexarr(dmodulo,nangles)*!values.f_nan ; "compressed" array of NaN for k=0,nangles-1 do begin rolla=angle[k] ; when angle=0, rolla=grid_angle+phase_ctr_angle ; i1[k]=(k-di[k])>0 ; i2[k]=(k+di[k])<(nangles-1) y=modprof[i1[k]:i2[k]] alpha=angle[i1[k]:i2[k]] ; Do a least square fit of A*cos(phase_map_ctr[])+B*sin(phase_map_ctr[]): AB=ls_amp_pha_ctr(alpha,y,phase_map_ctr[i1[k]:i2[k]],yfit,sigma) ;if (keyword_set(plo)) then oplot,alpha,yfit,thick=3 A=AB[0] & B=AB[1] amp=sqrt(A^2+B^2) pha=atan(B,A) ; EXPLANATION: ; yfit = A*cos(phase_map_ctr[i1:i2])+B*sin(phase_map_ctr[i1:i2]) ; = amp[k]*cos(pha - phase_map_ctr[i1:i2]) ; The real part of the visibility = yfit: ; vis_real[k]=yfit(di) ; the central value of yfit (Don't use mean!) ; And the imaginary part of vis is found by replacing cos with sin: ; vis_imag[k]= amp[k]*sin(pha - phase_map_ctr[i1+di]) ) ; vis[k]=amp[k]*(cos(pha-phase_map_ctr[i1:i2]) $ ; +i * sin(pha-phase_map_ctr[i1:i2])) ; =amp[k]*exp(i*(pha - (phase_map_ctr[i1:i2]))--some kind of average ; ; Keep all the fits in a 2D array for subsequent row-averaging: ;vv[k,i1[k]:i2[k]]=yfit(*) + ;i*amp*sin(pha - phase_map_ctr[i1[k]:i2[k]]) ; Accumulate all the fits in array vv to average after the loop. ; wrap around modulo dmodulo to save space: vv((k mod dmodulo),i1[k]:i2[k])= $ yfit(*) + i*amp*sin(pha - phase_map_ctr[i1[k]:i2[k]]) sig[k]=sigma endfor ;k angle loop tvscl,vv if (keyword_set(plo)) then begin window,0 & tvscl,float(vv),0 & tvscl,imaginary(vv),2 endif ;vis=total(vv,1,/NaN)/total(finite(vv),1) ; old array (too big) vis=total(vv,1,/NaN)/total(finite(vv),1) ; average unflagged row elements print,'i=',i return,vis end ; end modprofile2vis
;+ ; NAME: modprof2vis_demo.pro ; ; PURPOSE: ; To demonstrate capability of modprofile2vis ; ; METHOD: ; 1. Simulate a modulation profile for hardwired parameters ; det_index, r_map, phase_ctr_angle, offsets ; ; 2. Calls modprofile2vis (for 180 deg of rotation), which: ; a. Gets the ang_pitch from det_index ; b. Finds the shortest cycle period from map_ctr_phase ; c. Loops through angles, fitting sinusoids of phase to each cycle ; d. Uses amplitude and phase to create visibility ; ; 3. Plots the imaginary and real parts of all the visibilities ; ; INPUTS: None (Hardwired parameters go to modprofile2vis) ; ; ; OUTPUTS: Plots of simulated mod profile, real, imag parts of visibility ; ; ; EXAMPLE: ; compile modprofile2vis, ls_sin_cos, and ls_amp_pha_ctr, then ; .run modprof2vis_demo ; ; ; RESTRICTIONS: ; ; ; VERSION HISTORY: ; VERS. 1 Derived from test_lscoscos.pro -- EJS May 26, 1999. ; VERS. 2 Added /verb option, upgraded variable names-- ; EJS Jun 14, 1999. ; NOTES: ;- pro modprof2vis_demo wset,0 ;1. SIMULATE A MODULATION PROFILE FOR SPECIFIC PARAMETERS: det_index=4 r_map=700. phase_ctr_angle=!pi*0.75 sigma=1. r_src_off1=0.0 ; simulated source positions in polar coords r_src_off2=0.5 phi_src_off1=0.0 phi_src_off2=0.5 srcti='SIMULATED SOURCE OFFSETS: ' + $ '('+ trim(r_src_off1,'(f3.1)')+','+trim(phi_src_off1,'(f3.1)')+') '+ $ '('+ trim(r_src_off2,'(f3.1)')+','+trim(phi_src_off2,'(f3.1)')+')' subti='R_map,phase_ctr_angle='+strcompress(r_map)+','+strcompress(phase_ctr_angle/!dtor) sideti='EJS modprof2vis_demo.pro '+systime(0) N=512 roll_angle=findgen(N)*!pi/N - !pi/4 params=hessi_params() grid_angle=(params.orient)(det_index) pitch=(params.pitch)(det_index) ; Create some aspect coords: x_asp=15.00*smooth(rebin(randomn(seed,N/8),N,/samp),N/8,/edge)+ $ 1.0*randomn(seed,N) y_asp=15.00*smooth(rebin(randomn(seed,N/8),N,/samp),N/8,/edge)+ $ 1.0*randomn(seed,N) ; Select an inertial map center: X_map=600. Y_map=200. ; Compute the spacecraft coords of map center: x_map_sc = x_asp + X_map*cos(roll_angle) - Y_map*sin(roll_angle) y_map_sc = y_asp + Y_map*cos(roll_angle) + X_map*sin(roll_angle) r_map_sc = sqrt(x_map_sc^2+y_map_sc^2) ang_sc=atan(y_map_sc,x_map_sc) ; Choose a value for the peak_resp_offset (normally from hessi_grm): peak_resp_offset=!pi/6 h=1 ; fundamental ; Make the array of map-center phases: phase_map_ctr=2*!pi*h*(x_map_sc*cos(grid_angle)+y_map_sc*sin(grid_angle)$ +peak_resp_offset)/pitch phase_map_ctr=2*!pi*h*(r_map_sc*cos(ang_sc-grid_angle) $ +peak_resp_offset)/pitch angle=roll_angle-phase_ctr_angle-grid_angle ; =0 at pt of slowest modulation print,phase_ctr_angle,grid_angle ;stop modprofile=180.+100.*cos(1.05*phase_map_ctr+!PI/6)+80*cos(phase_map_ctr) mod_profile=modprofile ; Add Poisson noise: for k=0,n_elements(angle)-1 do $ mod_profile[k]=randomu(seed,1,poisson=modprofile[k]) mod_profile=mod_profile-mean(mod_profile) xt='ROLL ANGLE (degrees) plot,roll_angle/!dtor,mod_profile,xsty=1,tit='SIMULATED MODULATION PROFILE',xtit=xt ; 2. Convert the modprof to visibilities: vis=modprofile2vis(roll_angle,mod_profile,det_index,phase_map_ctr,/plo, $ cycle_factor=0.125) ; 3. Plot the visibilities if (!d.name eq "X") then window,2,xsize=750,ysize=500 !p.multi=[0,1,2] ti='REAL PART OF VISIBILITY' plot,roll_angle/!dtor,float(vis),tit=ti,xtit=xt,subtit=subti xyouts,0.5,0.9,srcti,/norm,align=0.5 xyouts,0.99,0.5,sideti,/norm,align=0.5,orient=90 oplot,roll_angle/!dtor,mod_profile,psym=2,symsiz=0.3 ti='IMAG PART OF VISIBILITY' plot,roll_angle/!dtor,imaginary(vis),tit=ti,xtit=xt,subtit=subti xyouts,0.5,0.9,srcti,/norm,align=0.5 xyouts,0.99,0.5,sideti,/norm,align=0.5,orient=90 !p.multi=0 end
;+ ; NAME: ls_amp_pha_ctr.pro ; ; PURPOSE: Returns the least-square fit of y(angle) to the function ; A*cos(phase_map_ctr(angle))+B*sin(phase_map_ctr(angle)) ; or equivalently, AMP*cos(phase_map_ctr(angle)-PHA). ; The result can be used to fit visibilities to HESSI ; countrates, even in the ranges of slow modulation. ; ; METHOD: ; Theta=phase_map_ctr ; Minimize the total squared deviation H of the fit to ; y[i] = A*cos(Theta[i])+B*sin(Theta[i])) ; ; H=total{ [y - A*cos(Theta) - B*sin(Theta)]^2 } ; ; If the angle[i] are chosen to make the cos and sin terms uncorrelated ; then the regression matrix is diagonal. If, they are well correlated ; or nearly anti-correlated, the matrix is singular, and the method fails. ; The results may be meaningless unless r_p has been ; chosen such that phi[angle] ranges over a large fraction of [0,2*!pi]. ; ; INPUTS: ; y=modulation profile (countrates), one for each angle ; angle=vector of angles (radians), possibly irregular ; phase_map_ctr=Array of phases of map center relative to line ; of maximum response, one for each roll angle ; ; OUTPUTS: ; [A,B] cos,sin amplitudes, OR ; [amplitude,phase] if optional amp_pha is set, ; If sigma exists as an argument, the RMS deviation of the fit ; is returned in sigma. ; If y has only 2 elements, sigma is necessarily 0 (exact fit). ; If yfit is a defined argument, fit to y will be returned in it. ; ; EXAMPLE: ; ;Simple simulation of map-center phases ; ;Create an array of angles: ; N=512 ; angle=findgen(N)*!pi/N - !pi/4 ; ;Create some aspect coords: ; x_asp=1.0*randomn(seed,N) ; y_asp=1.0*randomn(seed,N) ; ;Select an inertial map center: ; X_map=600. ; Y_map=200. ; ;Compute the spacecraft coords of map center: ; x_map_sc = x_asp + X_map*cos(angle) - Y_map*sin(angle) ; y_map_sc = y_asp + Y_map*cos(angle) + X_map*sin(angle) ; ;Choose a value for the peak_resp_offset (normally from hessi_grm): ; peak_resp_offset=!pi/6 ; ;Pick a sub_collimator: ; ang_pitch=39.45 & det_index=4 ; grid_angle=0. & h=1 ; ;Now make the array of map-center phases: ; ; phase_map_ctr=2*!pi*h*(x_map_sc*cos(grid_angle)+y_map_sc*sin(grid_angle)$ ; +peak_resp_offset)/ang_pitch ; ;Select a range of indices: ; inx=180+findgen(20) ; y=cos(phase_map_ctr)+0.25*randomn(seed,N) ; z=ls_amppha_pmc(angle(inx),y(inx),phase_map_ctr(inx),yfit,sig) ; plot,angle,y,psym=10,xsty=1 & oplot,angle(inx),yfit,thick=3 ; ; RESTRICTIONS: ; If the data set is enormous, this is slow. ; For a way to speed it up, ; see Press and Rybicki, Ap.J., 338, 277, 1989. ; ; angle must =0 or !pi where the modulation is slowest, and ; angle must= +!pi/2 or -!pi/2 where modulation is fastest ; ; REVISION HISTORY: ; Version 1.0, Derived from ls_cosocs, EJS, June 15, 1999. ; ;- function ls_amp_pha_ctr,angl,y,phase_map_ctr,yfit,sigma, $ AMP_PHA=amp_pha,verb=verb ; message,'stopping' ; Compute the sine and cosine arrays cosine=cos(phase_map_ctr) sine=sin(phase_map_ctr) if (keyword_set(verb)) then message, $ 'Working with '+String(n_elements(phi))+' angles',/cont ; The regression matrix m00=total(cosine^2) & m01=total(sine*cosine) m11= total(sine^2) del=m00*m11-m01^2 if abs(del) lt 1.e-5*m00 then message,'Ill-conditioned LS fit.' c0=total(y*cosine) c1=total(y*sine) A=(c0*m11-c1*m01)/del ; Solution to M # [A,B] = [c0,c1] B=(c1*m00-c0*m01)/del AB=[A,B] yfit=A*cosine+B*sine ; compute the goodness of fit if (n_elements(sigma) GT 0) then sigma=sqrt(variance(y-yfit)) if keyword_set(amp_pha) then AB=[abs(AB),atan(AB[1],AB[0])] return,AB end
; NAME: ls_coscos.pro ; ; PURPOSE: Returns the least-square fit of y(angle) to the function ; A*cos(2*!pi*r_p*cos(angle))+B*sin(2*!pi*r_p*cos(angle)) ; or equivalently, AMP*cos(2*!pi*r_p*cos(angle)-PHA). ; The result can be used to fit visibilities to HESSI ; countrates, even in the ranges of slow modulation. ; ; METHOD: ; Let phi[angle] = 2*!pi*r_p*cos(angle[i]) ; Minimize the total squared deviation H of the fit to ; y[i] = A*cos(phi[i)+B*sin(phi[i])) ; ; H=total{ [y - A*cos(phi) - B*sin(phi)]^2 } ; ; If the angle[i] are chosen to make the cos and sin terms uncorrelated ; then the regression matrix is diagonal. If, they are well correlated ; or nearly anti-correlated, the matrix is singular, and the method fails. ; The results may be meaningless unless r_p has been ; chosen such that phi[angle] ranges over a large fraction of [0,2*!pi]. ; ; INPUTS: ; y=approximate sinusoid (vector) ; angle=vector of angles (radians), possibly irregular ; angle must =0 or !pi where the modulation is slowest, and ; angle must= +!pi/2 or -!pi/2 where modulation is fastest ; angle=roll_angle-grid_angle-phase_ctr_angle ; r_p = radial position of HESSI map center divided by pitch ; ; OUTPUTS: ; [A,B] cos,sin amplitudes, OR ; [amplitude,phase] if optional amp_pha is set, ; If sigma exists as an argument, the RMS deviation of the fit ; is returned in sigma. ; If y has only 2 elements, sigma is necessarily 0 (exact fit). ; If yfit is a defined argument, fit to y will be returned in it. ; ; EXAMPLE: ; Create an array of angles: ; angle=findgen(512)*!pi/512 - !pi/4 ; Define variables: ; r_p=20. & sigma=0. ; Define function values (a simulated modulation profile): ; y=100.*cos(2*!pi*r_p*cos(angle)) + $ ; 80.*cos(2*!pi*(r_p-1.0)*cos(angle+0.01)) & plot,angle,y ; AB=LS_coscos(angle(120:160),y(120:160),r_p,yfit,sigma) ; plot,angle,y,xsty=1 & oplot,angle(120:160),yfit,thick=3 ; OR: ; AB=LS_coscos(angle(330:340),y(330:340),r_p,yfit,sigma) ; plot,angle,y,xsty=1 & oplot,angle(330:340),yfit,thick=3 ; OR: ; AB=LS_coscos(angle(240:250),y(240:250),r_p,yfit,sigma) ; plot,angle,y,xsty=1 & oplot,angle(240:250),yfit,thick=3 ; ; RESTRICTIONS: ; If the data set is enormous, this is slow. ; For a way to speed it up, ; see Press and Rybicki, Ap.J., 338, 277, 1989. ; ; angle must =0 or !pi where the modulation is slowest, and ; angle must= +!pi/2 or -!pi/2 where modulation is fastest ; ; REVISION HISTORY: ; Version 1.0, EJS Derived from LS_sinusoid, May 25, 1999. ; ;-