This notebook will be used to develop code for when the airglow emission rate should be treated as known to improve the inversion. (e.g., terminator crossover)
How do we handle the terminator? One way is to use a model for airglow VER. Treating VER as known has two aspects:
For item 1:
Measurement model: $$ \underbrace{g_i}_{\textrm{measured interferogram}} = \sum_{j=1}^{N} ~~~\underbrace{a(\bar{r}_{ij})}_{\textrm{VER}}~~~~ \underbrace{f(\bar{r}_{ij})}_{\textrm{interferogram}} ~~~~~\underbrace{\Delta s_{ij}}_{\textrm{path length}}$$
Usually we assume:
And we solve for $a(r_{j})f(r_{j})$ by creating path length matrix using $\Delta s_{ij}$
If airglow is known:
Solve for $f(r_{j})$ by creating path length matrix using $a(\bar{r}_{ij}) \Delta s_{ij}$
%pylab inline
from Scientific.IO.NetCDF import NetCDFFile as Dataset
from datetime import datetime, timedelta
from pyglow import pyglow
from mpl_toolkits.basemap import Basemap
import os
import glob
from scipy.interpolate import griddata
import subprocess
import MIGHTI
import ICON
import sys
import time as time_module
from IPython.display import display, clear_output
# Make default figure size bigger
matplotlib.rcParams['savefig.dpi'] = 150
matplotlib.rcParams['figure.figsize'] = (4,3)
matplotlib.rcParams['font.size'] = 8
Populating the interactive namespace from numpy and matplotlib
WARNING: pylab import has clobbered these variables: ['f', 'unwrap', 'datetime', 'griddata'] `%matplotlib` prevents importing * from pylab and numpy
# Ignore satellite motion for now. (Include velocity in phase, though).
dt = datetime(2013,9,23,2,0,0) # UT
icon_alt = 550.
icon_lat = 20.5
icon_lon = 180. # daytime
icon_velocity = 0.0 # this will likely not be implemented
az = 90. # so that we're only measuring zonal wind
ze_top = 103
ze_bot = 109
ny = 50
nk = 101
#ny = 50
#nk = 501
impose_spherical_symmetry_winds = True
impose_spherical_symmetry_temps = True
impose_spherical_symmetry_ver = True
satlla = [icon_lat, icon_lon, icon_alt]
# Let's say that ICON is going purely east. This shouldn't matter, since velocity is zero.
icon_ecef_ram_vector = ICON.ven_to_ecef(satlla, [0, 1, 0])
# LOAD MIGHTI CONSTANTS/PARAMETERS
emission_color = 'red' # 'red' or 'green'
day = True
emissions = MIGHTI.get_emission_constants()
params = MIGHTI.get_instrument_constants()
params['exptime'] = 60. # sec
params['lam'] = emissions[emission_color]['lam']
params['frq'] = emissions[emission_color]['frq']
params['mass'] = emissions[emission_color]['mass']
if day: # 10% reduction in aperture size during "day", and shorter exposure time
params['aperture_area'] = params['aperture_area'] * 0.1
params['exptime'] = 30.
ray_length = 6000./nk
print '%.2f km steps' % ray_length
tanlla_top = ICON.tangent_point(satlla, az, ze_top)
tanlla_bot = ICON.tangent_point(satlla, az, ze_bot)
zevec = linspace(ze_bot, ze_top, ny)
mighti_ecef_vectors = zeros((ny,3))
alts_along_ray = zeros((nk,ny))
lats_along_ray = zeros((nk,ny))
lons_along_ray = zeros((nk,ny))
tang_alts = zeros(ny)
tang_lats = zeros(ny)
tang_lons = zeros(ny)
for i in range(ny):
ze = zevec[i]
# Determine tangent point
tang_pt = ICON.tangent_point(satlla, az, ze)
tang_alts[i] = tang_pt[2]
tang_lats[i] = tang_pt[0]
tang_lons[i] = tang_pt[1]
# Determine the ECEF look direction and record it
mighti_ecef_vectors[i,:] = ICON.azze_to_ecef(satlla, az, ze)
# Project the line of sight and record winds, temps, and amplitudes along the ray
xyz_proj,lla_proj = ICON.project_line_of_sight(satlla, az, ze, \
step_size = ray_length, total_distance=ray_length*nk)
alts_along_ray[:,i] = lla_proj[2,:]
lats_along_ray[:,i] = lla_proj[0,:]
lons_along_ray[:,i] = lla_proj[1,:]
print '%.1f - %.1f km' % (tang_alts[-1], tang_alts[0])
59.41 km steps 372.4 - 172.4 km
i = 0
figure(figsize=(9,3))
subplot(1,3,1)
plot(lats_along_ray[:,i],'k')
subplot(1,3,2)
plot(lons_along_ray[:,i],'k')
subplot(1,3,3)
plot(alts_along_ray[:,i],'k')
[<matplotlib.lines.Line2D at 0x7fdd67697410>]
def get_airglow_VER(pt):
#VER = exp(-0.5*((altk - 250)/(50))**2)
VER = MIGHTI.get_redline_airglow(pt)
return VER
def get_wind(pt):
pt.run_hwm14()
return pt.u,pt.v,0.0
def get_temperature(pt):
pt.run_msis()
return pt.Tn_msis
# Build the three quantities needed by forward model: VER, LoS wind, and temp
emission_along_ray_r = zeros((nk,ny))
u_along_ray = zeros((nk,ny))
v_along_ray = zeros((nk,ny))
w_along_ray = zeros((nk,ny))
winds_along_ray = zeros((nk,ny)) # LoS
temps_along_ray = zeros((nk,ny))
ven_along_ray = zeros((nk,ny,3))
for i in range(ny):
look_xyz = mighti_ecef_vectors[i,:]
for k in range(nk):
latk = lats_along_ray[k,i]
lonk = lons_along_ray[k,i]
altk = alts_along_ray[k,i]
##### local VEN
ven_look = ICON.ecef_to_ven([latk, lonk, altk], look_xyz)
##### winds
if impose_spherical_symmetry_winds:
pt = pyglow.Point(dt, icon_lat, icon_lon, altk)
else:
pt = pyglow.Point(dt, latk, lonk, altk)
u,v,w = get_wind(pt)
u_along_ray[k,i] = u
v_along_ray[k,i] = v
w_along_ray[k,i] = w
winds_along_ray[k,i] = dot(ven_look,[w,u,v])
##### temperature
if impose_spherical_symmetry_temps:
pt = pyglow.Point(dt, icon_lat, icon_lon, altk)
else:
pt = pyglow.Point(dt, latk, lonk, altk)
T = get_temperature(pt)
temps_along_ray[k,i] = T
##### VER
if impose_spherical_symmetry_ver:
pt = pyglow.Point(dt, icon_lat, icon_lon, altk)
else:
pt = pyglow.Point(dt, latk, lonk, altk)
VER = get_airglow_VER(pt)
emission_along_ray_r[k,i] = VER*ray_length*1e3*1e6/1e10 # cm, km, 10^10 ph
clear_output(wait=True)
time_module.sleep(0.01)
print '%03i/%03i' % (i+1,ny)
sys.stdout.flush()
050/050
i = 0
figure(figsize=(9,3))
subplot(1,3,1)
plot(u_along_ray[:,i],'k')
title('u')
subplot(1,3,2)
plot(v_along_ray[:,i],'k')
title('v')
subplot(1,3,3)
plot(w_along_ray[:,i],'k')
title('w')
<matplotlib.text.Text at 0x7fdd674dae10>
i = 0
figure(figsize=(9,3))
subplot(1,3,1)
plot(winds_along_ray[:,i],'k')
title('Winds')
subplot(1,3,2)
plot(temps_along_ray[:,i],'k')
title('Temps')
subplot(1,3,3)
plot(emission_along_ray_r[:,i],'k')
title('Emission')
tight_layout()
nx = params['npixelx']
ny = shape(winds_along_ray)[1] # number of rows of interferogram
nk = shape(winds_along_ray)[0] # number of steps along ray
Iraw = np.zeros((ny,nx))
for i in range(ny):
for k in range(nk):
amp = emission_along_ray_r[k,i]
vel = winds_along_ray[k,i]
temp = temps_along_ray[k,i]
params['V'] = vel
params['T'] = temp
params['I'] = amp
ccdslice = MIGHTI.interferogram(params)
Iraw[i,:] += ccdslice
figure(figsize=(5,3))
X,TANH = meshgrid(arange(nx),tang_alts)
pcolormesh(X,TANH, Iraw,cmap='jet')
axis('tight')
xlabel('Interferogram Bin')
ylabel('Tangent height [km]')
title('Raw Noiseless Interferogram')
colorbar()
<matplotlib.colorbar.Colorbar instance at 0x7fdd67113a70>
#Inoisy = MIGHTI.add_noise(Iraw, params) # make sure units are right
Inoisy = Iraw.copy()
Ir = zeros(shape(Inoisy))
Ii = zeros(shape(Inoisy))
for i in range(shape(Inoisy)[0]):
# Filter with Hann window (in frequency) surrounding the peak
f = Inoisy[i,:]
F = np.fft.fft(f)
N = len(F)
n = arange(N)
# Create filter as per Ken Marr's email 2013/10/29
peaki = abs(F[5:floor(N/2)]).argmax() + 5
width1 = 20 # width of Hann window
width2 = 5 # width of plateau
hann = np.hanning(width1)
# Create full filter
H = hstack((zeros(peaki-width1/2-(width2-1)/2),
hann[:width1/2],
ones(width2),
hann[width1/2:],
zeros(N - peaki - width1/2 - (width2-1)/2 - 1)))
ap = hanning(N)
f = f - f.mean()
fap = f*ap
F = np.fft.fft(fap)
F2 = F * H
f2 = np.fft.ifft(F2)
Ir[i,:] = np.real(f2)
Ii[i,:] = np.imag(f2)
figure(figsize=(5,3))
X,TANH = meshgrid(arange(nx),tang_alts)
pcolormesh(X,TANH, Ir,cmap='RdBu')
axis('tight')
xlabel('Interferogram Bin')
ylabel('Tangent height [km]')
title('L1-Processed Interferogram [Real Part]')
<matplotlib.text.Text at 0x7fdd6750f2d0>
# Save L1 UIUC file
# Assume no change from start to end of exposure.
fn = '/home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz'
np.savez(fn,
Ir=Ir,
Ii=Ii,
tang_alt_start= tang_alts,
tang_alt_end = tang_alts,
tang_lat_start= tang_lats,
tang_lat_end = tang_lats,
tang_lon_start= tang_lons,
tang_lon_end = tang_lons,
emission_color= 'red',
icon_alt_start= icon_alt,
icon_alt_end= icon_alt,
icon_lat_start= icon_lat,
icon_lat_end= icon_lat,
icon_lon_start= icon_lon,
icon_lon_end= icon_lon,
mighti_ecef_vectors_start= mighti_ecef_vectors,
mighti_ecef_vectors_end= mighti_ecef_vectors,
icon_ecef_ram_vector_start= icon_ecef_ram_vector,
icon_ecef_ram_vector_end= icon_ecef_ram_vector,
icon_velocity_start= icon_velocity,
icon_velocity_end= icon_velocity,
datetime_created= datetime.now(),
source_files = [],
time = dt,)
print 'Saved to %s' % fn
Saved to /home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz
# Create a column vector with projected satellite velocity.
# Remember, we are ignoring horizontal extent for now.
proj_icon_vel = zeros(ny)
for i in range(ny):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
proj_icon_vel[i] = icon_velocity * np.dot(icon_ecef_ram_vector, look_ecef)
tang_point_along_ray = zeros(ny)
for i in range(ny):
kstar = argmin(alts_along_ray[:,i])
tang_point_along_ray[i] = kstar
truth_winds = zeros(ny)
truth_amps = zeros(ny)
for i in range(ny):
kstar = tang_point_along_ray[i]
truth_winds[i] = winds_along_ray[kstar,i] - proj_icon_vel[i]
truth_amps[i] = emission_along_ray_r[kstar,i]
subplot(1,2,1)
plot(truth_winds,tang_alts,'k.-')
subplot(1,2,2)
plot(truth_amps,tang_alts,'k')
tfn = '/home/bhardin2/MIGHTI/truth_winds_known_airglow.npz'
np.savez(tfn,
tang_alts=tang_alts,truth_winds=truth_winds,\
truth_amps=truth_amps)
print 'Saved to %s' % tfn
Saved to /home/bhardin2/MIGHTI/truth_winds_known_airglow.npz
from Scientific.IO.NetCDF import NetCDFFile as Dataset
from datetime import datetime, timedelta
from pyglow import pyglow
from mpl_toolkits.basemap import Basemap
import os
import glob
from scipy.interpolate import griddata
import subprocess
import MIGHTI
import ICON
def unwrap(x):
'''
Phase-unwrap a signal in [-pi,pi] which is increasing
'''
dx = diff(x)
xnew = zeros(len(x))
xnew[0] = x[0]
idx = dx < 0 # 0, or -pi ???
dx[idx] = dx[idx] + 2*pi
xnew[1:] = xnew[0] + cumsum(dx)
return xnew
def circular_mean(angle0,angle1):
'''
Find the mean angle, taking into account 0/360 crossover.
Input and output angles in degrees.
'''
return 180/pi*angle((exp(1j*angle0*pi/180.) + exp(1j*angle1*pi/180.))/2)
def level21(l1uiucfn, l21fn, show_plot=True):
'''
This attemps to do everything in the notebook above. Set l21fn='' to not save anything
'''
Nignore = 20 # ignore first and last few samples due to wraparound ringing (Can this be fixed by zero-padding?)
# ^ This is replicated in L1 code, but that's ok. As long as this one is larger.
phase_offset = -pi # This constant is added to all phases so that there is no chance of a pi/-pi crossover.
# In practice, we'll have to see how the interferometer turns out before deciding on this.
c = 299792458.0 # m/s, speed of light
# Specify ranges for plotting (even though the whole image is analyzed)
min_alt = {'red': 100, 'green': 87}
max_alt = {'red': 400, 'green': 200}
min_amp = 0.0 # if amplitude of fringe is below this, don't even try to analyze it
# Zero wind/phase (TODO: how will this be done for real, and what's the best way to simulate it?)
zero_phase = 252.07801858 + phase_offset# - 0.00196902 # last term added 2015-05-18 for vertical wind study
npzfile = load(l1uiucfn)
# Extract all information from the UIUC L1 file
Ii = npzfile['Ii']
Ir = npzfile['Ir']
emission_color = str(npzfile['emission_color'])
icon_alt_end = npzfile['icon_alt_end']
icon_alt_start = npzfile['icon_alt_start']
icon_lat_end = npzfile['icon_lat_end']
icon_lat_start = npzfile['icon_lat_start']
icon_lon_end = npzfile['icon_lon_end']
icon_lon_start = npzfile['icon_lon_start']
icon_velocity_start = npzfile['icon_velocity_start']
icon_velocity_end = npzfile['icon_velocity_end']
icon_ecef_ram_vector_start = npzfile['icon_ecef_ram_vector_start']
icon_ecef_ram_vector_end = npzfile['icon_ecef_ram_vector_end']
mighti_ecef_vectors_end = npzfile['mighti_ecef_vectors_end']
mighti_ecef_vectors_start = npzfile['mighti_ecef_vectors_start']
tang_alt_end = npzfile['tang_alt_end']
tang_alt_start = npzfile['tang_alt_start']
tang_lat_end = npzfile['tang_lat_end']
tang_lat_start = npzfile['tang_lat_start']
tang_lon_end = npzfile['tang_lon_end']
tang_lon_start = npzfile['tang_lon_start']
datetime_created = npzfile['datetime_created']
source_files = npzfile['source_files']
time = npzfile['time'] # we should really have start time and end time
#print 'Reading file %s' % l1uiucfn
#print 'Created %s' % datetime_created
# Take the midpoint of start and end.
icon_alt = (icon_alt_start+icon_alt_end)/2
icon_lat = (icon_lat_start+icon_lat_end)/2
icon_lon = circular_mean(icon_lon_start, icon_lon_end)
mighti_ecef_vectors = (mighti_ecef_vectors_start + mighti_ecef_vectors_end)/2 # ny by 3
tang_alts = (tang_alt_start + tang_alt_end)/2
tang_lats = (tang_lat_start + tang_lat_end)/2
tang_lons = circular_mean(tang_lon_start, tang_lon_end)
icon_ecef_ram_vector = (icon_ecef_ram_vector_start + icon_ecef_ram_vector_end)/2
icon_velocity = (icon_velocity_start+icon_velocity_end)/2
Ntheta = shape(Ir)[0]
npixel = shape(Ir)[1]
params = MIGHTI.get_instrument_constants()
emission = MIGHTI.get_emission_constants()[emission_color]
I = (Ir + 1j*Ii) * exp(1j*phase_offset)
theta = MIGHTI.tanht2angle(tang_alts, icon_alt)
RE = 6371 # TODO
startpath = params['startpath']
endpath = params['endpath']
sigma = 1.0/emission['lam']
# Create a column vector with projected satellite velocity. Remember, we are ignoring horizontal extent for now.
proj_icon_vel = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
proj_icon_vel[i] = icon_velocity * np.dot(icon_ecef_ram_vector, look_ecef)
# Transform velocity to phase
# dphi = 2*pi*OPD*sigma*v/c (Eqn 1 of Englert et al 2007 Appl Opt.)
# Use mean(opd) for now, but eventually it will be actual OPD once we include horizontal extent.
opd = linspace(startpath,endpath,npixel)
icon_vel_phase = 2*pi*mean(opd[Nignore:-Nignore])*sigma*proj_icon_vel/c
# Subtract phase from the interferogram (Change this when horizontal extent is included)
corr = exp(-1j*icon_vel_phase)
for jj in range(npixel):
I[:,jj] = I[:,jj]*corr
# Define grid. Bottom of each layer is defined by tangent height of observation.
rbottom = MIGHTI.angle2tanht(theta, icon_alt)
# Define top of each layer.
rtop = rbottom.copy()
rtop[:-1] = rbottom[1:]
rtop[-1] = rbottom[-1] + (rtop[1]-rbottom[1])
# Define midpt of each layer
rmid = (rbottom + rtop)/2
# Build observation matrix
D = zeros((Ntheta, len(rmid)))
for i in range(Ntheta):
for j in range(len(rmid)):
th = theta[i]
rb = rbottom[j]
rt = rtop[j]
sb = cos(th)**2 - 1 + ((RE+rb)/(RE+icon_alt))**2
st = cos(th)**2 - 1 + ((RE+rt)/(RE+icon_alt))**2
if sb < 0: # there is no intersection of LOS with altitude rb. Set term to 0.
# Note: this might be due to numerical rounding for tangent altitude.
# Do the same thing either way.
sb = 0.
if st < 0: # there is no intersection of LOS with altitude rt. Set term to 0.
st = 0.
D[i,j] = 2*(RE+icon_alt) * ( sqrt(st) - sqrt(sb) )
# Quick check to see if phase is near the pi/-pi crossover
# TODO: revamp this, including zero-wind removal
init_phase = zeros((Ntheta))
for j in range(Ntheta):
irow = I[j,:]
phase = angle(irow)
phaseu = unwrap(phase[Nignore:-Nignore])
init_phase[j] = phaseu[0]
ampl = abs(irow)
if max(ampl) < min_amp:
init_phase[j] = nan
if any(abs(init_phase) > 0.8*pi):
print 'WARNING: phase near pi/-pi crossover. Consider changing phase_offset'
if any(diff(init_phase) > 0.8*2*pi):
print 'WARNING: phase pi/-pi crossover detected. Consider changing phase_offset'
P = nan*zeros(len(rmid)) # analyzed phase of each shell
A = nan*zeros(len(rmid)) # analyzed intensity of each shell
Ip = nan*zeros(shape(I),dtype=complex) # matrix to hold onion-peeled, distance-normalized interferogram
# Calculate local-horizontal projection factors
B = nan*zeros(shape(D)) # matrix to hold cosine correction factors
for i in range(Ntheta):
for j in range(len(rmid)):
# Calculate b_ij = cos(angle between ray and shell tangent)
th = theta[i]
r = rmid[j]
B[i,j] = (RE+icon_alt)/(RE+r) * sin(th) # this ought to be <= 1, or there's no intersection
#B[i,j] = 1
# Onion-peel interferogram
Ip = linalg.solve(D,I)
for j in range(Ntheta):
r = rmid[j]
irow = Ip[j,:]
phase = angle(irow)
ampl = abs(irow)
if nanmax(ampl) > min_amp:
# average phase and then take delta. Need unwrapping for this.
phaseu = unwrap(phase[Nignore:-Nignore])
#phaseu = unwrap(phaseu)
meanphase = mean(phaseu)
dphase = meanphase - zero_phase
opd = linspace(startpath,endpath,npixel)[Nignore:-Nignore]
# Method B: multiply by mean(1/opd). These are different, but only slightly
#mean_recip_opd = mean(1/opd)
#vj = c * dphase / (2*pi*sigma) * mean_recip_opd
P[j] = dphase
A[j] = ampl[Nignore:-Nignore].mean()
# Convert phase to velocity
opd = linspace(startpath,endpath,npixel)
meanopd = mean(opd[Nignore:-Nignore])
V = c * P / (2*pi*sigma) * 1/meanopd
V[rmid < min_alt[emission_color]] = nan
V[rmid > max_alt[emission_color]] = nan
# Calculate local azimuth angles (i.e., at tangent point)
satlatlonalt = array([icon_lat, icon_lon, icon_alt])
local_az = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
look_az, look_ze = ICON.ecef_to_azze(satlatlonalt, look_ecef) # look direction in az, ze
tang_latlonalt = ICON.tangent_point(satlatlonalt, look_az, look_ze) # tangent point of observation
loc_az, loc_ze = ICON.ecef_to_azze(tang_latlonalt, look_ecef) # local (tangent point) direction in az, ze
local_az[i] = loc_az
if show_plot:
plot(V, rmid, '%s-' % emission_color[0])
xlabel('Velocity [m/s]')
ylabel('Altitude [km]')
if l21fn:
np.savez(l21fn,
tang_alt_start= tang_alt_start,
tang_alt_end = tang_alt_end,
tang_alt = tang_alts,
tang_lat_start= tang_lat_start,
tang_lat_end = tang_lat_end,
tang_lat = tang_lats,
tang_lon_start= tang_lon_start,
tang_lon_end = tang_lon_end,
tang_lon = tang_lons,
emission_color= emission_color,
icon_alt_start= icon_alt_start,
icon_alt_end= icon_alt_end,
icon_alt = icon_alt,
icon_lat_start= icon_lat_start,
icon_lat_end= icon_lat_end,
icon_lat = icon_lat,
icon_lon_start= icon_lon_start,
icon_lon_end= icon_lon_end,
icon_lon = icon_lon,
mighti_ecef_vectors_start= mighti_ecef_vectors_start,
mighti_ecef_vectors_end= mighti_ecef_vectors_end,
mighti_ecef_vectors = mighti_ecef_vectors,
icon_ecef_ram_vector_start= icon_ecef_ram_vector_start,
icon_ecef_ram_vector_end= icon_ecef_ram_vector_end,
icon_ecef_ram_vector = icon_ecef_ram_vector,
icon_velocity_start= icon_velocity_start,
icon_velocity_end= icon_velocity_end,
icon_velocity = icon_velocity,
datetime_created= datetime.now(),
source_files = [l1uiucfn],
time= time,
los_wind = V,
alt_los_wind = rmid, # TEMPORARY?
local_az = local_az,
)
npzfile.close()
uiucl1_fn = '/home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz'
out_fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
level21(uiucl1_fn,out_fn)
L21_fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
truthfn = '/home/bhardin2/MIGHTI/truth_winds_known_airglow.npz'
npzfile = load(truthfn)
truth_alts = npzfile['tang_alts']
truth_winds = npzfile['truth_winds']
truth_amps = npzfile['truth_amps']
npzfile.close()
subplot(1,2,1)
plot(truth_winds, truth_alts, 'k-', label='Truth')
subplot(1,2,2)
plot(truth_amps, truth_alts, 'k-', label='Truth')
xlabel('True VER')
xticks(xticks()[0][::2])
fn = L21_fn
npzfile = load(fn)
wind = npzfile['los_wind']
alt_of_wind = npzfile['alt_los_wind']
npzfile.close()
subplot(1,2,1)
plot(wind, alt_of_wind, 'r.', markersize=3, label='Recon.')
ylabel('Altitude [km]')
xlabel('LoS Velocity [m/s]')
legend(loc='best',numpoints=1,prop={'size':8},fancybox=True)
tight_layout()
wind_naive = wind.copy()
l1uiucfn = '/home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz'
l21fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
show_plot = True
#def level21(l1uiucfn, l21fn, show_plot=True):
'''
This attemps to do everything in the notebook above. Set l21fn='' to not save anything
'''
Nignore = 20 # ignore first and last few samples due to wraparound ringing (Can this be fixed by zero-padding?)
# ^ This is replicated in L1 code, but that's ok. As long as this one is larger.
phase_offset = -pi # This constant is added to all phases so that there is no chance of a pi/-pi crossover.
# In practice, we'll have to see how the interferometer turns out before deciding on this.
c = 299792458.0 # m/s, speed of light
# Specify ranges for plotting (even though the whole image is analyzed)
min_alt = {'red': 100, 'green': 87}
max_alt = {'red': 400, 'green': 200}
min_amp = 0.0 # if amplitude of fringe is below this, don't even try to analyze it
# Zero wind/phase (TODO: how will this be done for real, and what's the best way to simulate it?)
zero_phase = 252.07801858 + phase_offset# - 0.00196902 # last term added 2015-05-18 for vertical wind study
npzfile = load(l1uiucfn)
# Extract all information from the UIUC L1 file
Ii = npzfile['Ii']
Ir = npzfile['Ir']
emission_color = str(npzfile['emission_color'])
icon_alt_end = npzfile['icon_alt_end']
icon_alt_start = npzfile['icon_alt_start']
icon_lat_end = npzfile['icon_lat_end']
icon_lat_start = npzfile['icon_lat_start']
icon_lon_end = npzfile['icon_lon_end']
icon_lon_start = npzfile['icon_lon_start']
icon_velocity_start = npzfile['icon_velocity_start']
icon_velocity_end = npzfile['icon_velocity_end']
icon_ecef_ram_vector_start = npzfile['icon_ecef_ram_vector_start']
icon_ecef_ram_vector_end = npzfile['icon_ecef_ram_vector_end']
mighti_ecef_vectors_end = npzfile['mighti_ecef_vectors_end']
mighti_ecef_vectors_start = npzfile['mighti_ecef_vectors_start']
tang_alt_end = npzfile['tang_alt_end']
tang_alt_start = npzfile['tang_alt_start']
tang_lat_end = npzfile['tang_lat_end']
tang_lat_start = npzfile['tang_lat_start']
tang_lon_end = npzfile['tang_lon_end']
tang_lon_start = npzfile['tang_lon_start']
datetime_created = npzfile['datetime_created']
source_files = npzfile['source_files']
time = npzfile['time'] # we should really have start time and end time
#print 'Reading file %s' % l1uiucfn
#print 'Created %s' % datetime_created
# Take the midpoint of start and end.
icon_alt = (icon_alt_start+icon_alt_end)/2
icon_lat = (icon_lat_start+icon_lat_end)/2
icon_lon = circular_mean(icon_lon_start, icon_lon_end)
mighti_ecef_vectors = (mighti_ecef_vectors_start + mighti_ecef_vectors_end)/2 # ny by 3
tang_alts = (tang_alt_start + tang_alt_end)/2
tang_lats = (tang_lat_start + tang_lat_end)/2
tang_lons = circular_mean(tang_lon_start, tang_lon_end)
icon_ecef_ram_vector = (icon_ecef_ram_vector_start + icon_ecef_ram_vector_end)/2
icon_velocity = (icon_velocity_start+icon_velocity_end)/2
Ntheta = shape(Ir)[0]
npixel = shape(Ir)[1]
params = MIGHTI.get_instrument_constants()
emission = MIGHTI.get_emission_constants()[emission_color]
I = (Ir + 1j*Ii) * exp(1j*phase_offset)
theta = MIGHTI.tanht2angle(tang_alts, icon_alt)
RE = 6371 # TODO
startpath = params['startpath']
endpath = params['endpath']
sigma = 1.0/emission['lam']
# Create a column vector with projected satellite velocity. Remember, we are ignoring horizontal extent for now.
proj_icon_vel = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
proj_icon_vel[i] = icon_velocity * np.dot(icon_ecef_ram_vector, look_ecef)
# Transform velocity to phase
# dphi = 2*pi*OPD*sigma*v/c (Eqn 1 of Englert et al 2007 Appl Opt.)
# Use mean(opd) for now, but eventually it will be actual OPD once we include horizontal extent.
opd = linspace(startpath,endpath,npixel)
icon_vel_phase = 2*pi*mean(opd[Nignore:-Nignore])*sigma*proj_icon_vel/c
# Subtract phase from the interferogram (Change this when horizontal extent is included)
corr = exp(-1j*icon_vel_phase)
for jj in range(npixel):
I[:,jj] = I[:,jj]*corr
# Define grid. Bottom of each layer is defined by tangent height of observation.
rbottom = MIGHTI.angle2tanht(theta, icon_alt)
# Define top of each layer.
rtop = rbottom.copy()
rtop[:-1] = rbottom[1:]
rtop[-1] = rbottom[-1] + (rtop[1]-rbottom[1])
# Define midpt of each layer
rmid = (rbottom + rtop)/2
# Build observation matrix
D = zeros((Ntheta, len(rmid)))
for i in range(Ntheta):
for j in range(len(rmid)):
th = theta[i]
rb = rbottom[j]
rt = rtop[j]
sb = cos(th)**2 - 1 + ((RE+rb)/(RE+icon_alt))**2
st = cos(th)**2 - 1 + ((RE+rt)/(RE+icon_alt))**2
if sb < 0: # there is no intersection of LOS with altitude rb. Set term to 0.
# Note: this might be due to numerical rounding for tangent altitude.
# Do the same thing either way.
sb = 0.
if st < 0: # there is no intersection of LOS with altitude rt. Set term to 0.
st = 0.
D[i,j] = 2*(RE+icon_alt) * ( sqrt(st) - sqrt(sb) )
def distance_to_shell(icon_alt, th, r, RE, intersection='first'):
'''
Return the distance from the satellite to the altitude r [km], along
the ray with zenith angle th [rad]. RE is the effective earth radius [km].
Return nan if the intersection doesn't exist.
Specify whether to return the first or second intersection along the ray.
'''
sin_alpha = (RE + icon_alt)/(RE + r) * sin(th)
if sin_alpha > 1.0:
return np.nan
s_first = (-sqrt(1-sin_alpha**2) - sin_alpha/tan(th))*(RE+r)
s_second = (sqrt(1-sin_alpha**2) - sin_alpha/tan(th))*(RE+r)
if intersection=='first':
return s_first
else:
return s_second
def project_along_ray(satlatlonalt, az, ze, s):
'''
Starting at the satellite location, looking in a direction (az,ze [deg]),
trace along the ray for a distance s [km]. Return lat, lon, alt of that point
'''
# Convert to radians
zer = ze*np.pi/180.
azr = az*np.pi/180.
# Create unit vector describing the look direction in Vertical-East-North (VEN) coordinates
lookven = np.array([np.cos(zer), np.sin(zer)*np.sin(azr), np.sin(zer)*np.cos(azr)])
# Convert satellite location to ecef
satxyz = ICON.wgs84_to_ecef(satlatlonalt)
# Convert look direction to ecef. This is a unit vector.
lookxyz = ICON.ven_to_ecef(satlatlonalt, lookven)
# Step along this line of sight
xyz = satxyz + s*lookxyz
latlonalt = ICON.ecef_to_wgs84(xyz)
return latlonalt
# Calculate known airglow emission rate (VER) for each entry of the matrix.
# There are some notes on this in my ICON notebook (2015-08-25)
icon_latlonalt = np.array([icon_lat, icon_lon, icon_alt])
VER = zeros((Ntheta,len(rmid)))
for i in range(Ntheta):
for j in range(len(rmid)):
th = theta[i]
ze = th*180./pi
rb = rbottom[j]
rt = rtop[j]
s_first_top = distance_to_shell(icon_alt, th, rt, RE, 'first')
s_second_top = distance_to_shell(icon_alt, th, rt, RE, 'second')
s_first_bot = distance_to_shell(icon_alt, th, rb, RE, 'first')
s_second_bot = distance_to_shell(icon_alt, th, rb, RE, 'second')
#print '%.2f %.2f %.2f %.2f %.2f %.2f' % (rt, rb, s_first_top, s_second_top, \
# s_first_bot, s_second_bot)
if not isnan(s_first_top): # then we know this shell is intersected. Two cases:
if not isnan(s_first_bot): # then this shell is interesected twice.
s_first = (s_first_top + s_first_bot)/2
s_second = (s_second_top + s_second_bot)/2
latlonalt_first = project_along_ray(icon_latlonalt, az, ze, s_first)
latlonalt_second = project_along_ray(icon_latlonalt, az, ze, s_second)
pt_first = pyglow.Point(dt, latlonalt_first[0], latlonalt_first[1], latlonalt_first[2])
ver_first = get_airglow_VER(pt_first)
pt_second = pyglow.Point(dt, latlonalt_second[0], latlonalt_second[1], latlonalt_second[2])
ver_second = get_airglow_VER(pt_second)
VER[i,j] = ver_first + ver_second
else: # then this shell is intersected once
s = (s_first_top + s_second_top)/2
latlonalt = project_along_ray(icon_latlonalt, az, ze, s)
pt = pyglow.Point(dt, latlonalt[0], latlonalt[1], latlonalt[2])
ver = get_airglow_VER(pt)
VER[i,j]= ver
#if not isnan(s_first_top): # then we know this shell is intersected
#else:
# pass # ?
imshow(D,interpolation='none')
<matplotlib.image.AxesImage at 0x7fdd67364a50>
imshow(VER,interpolation='none')
<matplotlib.image.AxesImage at 0x7fdd671ff450>
Dprime = VER*D # element-wise multiplication
imshow(Dprime, interpolation='none')
<matplotlib.image.AxesImage at 0x7fdd6732e890>
# Quick check to see if phase is near the pi/-pi crossover
# TODO: revamp this, including zero-wind removal
init_phase = zeros((Ntheta))
for j in range(Ntheta):
irow = I[j,:]
phase = angle(irow)
phaseu = unwrap(phase[Nignore:-Nignore])
init_phase[j] = phaseu[0]
ampl = abs(irow)
if max(ampl) < min_amp:
init_phase[j] = nan
if any(abs(init_phase) > 0.8*pi):
print 'WARNING: phase near pi/-pi crossover. Consider changing phase_offset'
if any(diff(init_phase) > 0.8*2*pi):
print 'WARNING: phase pi/-pi crossover detected. Consider changing phase_offset'
P = nan*zeros(len(rmid)) # analyzed phase of each shell
A = nan*zeros(len(rmid)) # analyzed intensity of each shell
Ip = nan*zeros(shape(I),dtype=complex) # matrix to hold onion-peeled, distance-normalized interferogram
# Calculate local-horizontal projection factors
# This isn't used in the standard processing
B = nan*zeros(shape(D)) # matrix to hold cosine correction factors
for i in range(Ntheta):
for j in range(len(rmid)):
# Calculate b_ij = cos(angle between ray and shell tangent)
th = theta[i]
r = rmid[j]
B[i,j] = (RE+icon_alt)/(RE+r) * sin(th) # this ought to be <= 1, or there's no intersection
#B[i,j] = 1
# Onion-peel interferogram
Ip = linalg.solve(D,I)
Ipprime = linalg.solve(Dprime,I)
pcolormesh(real(Ip))
<matplotlib.collections.QuadMesh at 0x7fdd66f1dc90>
pcolormesh(real(Ipprime))
<matplotlib.collections.QuadMesh at 0x7fdd66ebfa90>
# Analyze onion-peeled interferogram to get phase and amplitude
for j in range(Ntheta):
r = rmid[j]
irow = Ipprime[j,:]
phase = angle(irow)
ampl = abs(irow)
if nanmax(ampl) > min_amp:
# average phase and then take delta. Need unwrapping for this.
phaseu = unwrap(phase[Nignore:-Nignore])
#phaseu = unwrap(phaseu)
meanphase = mean(phaseu)
dphase = meanphase - zero_phase
opd = linspace(startpath,endpath,npixel)[Nignore:-Nignore]
# Method B: multiply by mean(1/opd). These are different, but only slightly
#mean_recip_opd = mean(1/opd)
#vj = c * dphase / (2*pi*sigma) * mean_recip_opd
P[j] = dphase
A[j] = ampl[Nignore:-Nignore].mean()
# Convert phase to velocity
opd = linspace(startpath,endpath,npixel)
meanopd = mean(opd[Nignore:-Nignore])
V = c * P / (2*pi*sigma) * 1/meanopd
V[rmid < min_alt[emission_color]] = nan
V[rmid > max_alt[emission_color]] = nan
# Calculate local azimuth angles (i.e., at tangent point)
satlatlonalt = array([icon_lat, icon_lon, icon_alt])
local_az = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
look_az, look_ze = ICON.ecef_to_azze(satlatlonalt, look_ecef) # look direction in az, ze
tang_latlonalt = ICON.tangent_point(satlatlonalt, look_az, look_ze) # tangent point of observation
loc_az, loc_ze = ICON.ecef_to_azze(tang_latlonalt, look_ecef) # local (tangent point) direction in az, ze
local_az[i] = loc_az
if show_plot:
plot(V, rmid, '%s-' % emission_color[0])
xlabel('Velocity [m/s]')
ylabel('Altitude [km]')
if l21fn:
np.savez(l21fn,
tang_alt_start= tang_alt_start,
tang_alt_end = tang_alt_end,
tang_alt = tang_alts,
tang_lat_start= tang_lat_start,
tang_lat_end = tang_lat_end,
tang_lat = tang_lats,
tang_lon_start= tang_lon_start,
tang_lon_end = tang_lon_end,
tang_lon = tang_lons,
emission_color= emission_color,
icon_alt_start= icon_alt_start,
icon_alt_end= icon_alt_end,
icon_alt = icon_alt,
icon_lat_start= icon_lat_start,
icon_lat_end= icon_lat_end,
icon_lat = icon_lat,
icon_lon_start= icon_lon_start,
icon_lon_end= icon_lon_end,
icon_lon = icon_lon,
mighti_ecef_vectors_start= mighti_ecef_vectors_start,
mighti_ecef_vectors_end= mighti_ecef_vectors_end,
mighti_ecef_vectors = mighti_ecef_vectors,
icon_ecef_ram_vector_start= icon_ecef_ram_vector_start,
icon_ecef_ram_vector_end= icon_ecef_ram_vector_end,
icon_ecef_ram_vector = icon_ecef_ram_vector,
icon_velocity_start= icon_velocity_start,
icon_velocity_end= icon_velocity_end,
icon_velocity = icon_velocity,
datetime_created= datetime.now(),
source_files = [l1uiucfn],
time= time,
los_wind = V,
alt_los_wind = rmid, # TEMPORARY?
local_az = local_az,
)
npzfile.close()
L21_fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
truthfn = '/home/bhardin2/MIGHTI/truth_winds_known_airglow.npz'
npzfile = load(truthfn)
truth_alts = npzfile['tang_alts']
truth_winds = npzfile['truth_winds']
truth_amps = npzfile['truth_amps']
npzfile.close()
subplot(1,2,1)
plot(truth_winds, truth_alts, 'k-', label='Truth')
subplot(1,2,2)
plot(truth_amps, truth_alts, 'k-', label='Truth')
xlabel('True VER')
xticks(xticks()[0][::2])
fn = L21_fn
npzfile = load(fn)
wind = npzfile['los_wind']
alt_of_wind = npzfile['alt_los_wind']
npzfile.close()
subplot(1,2,1)
plot(wind, alt_of_wind, 'r.', markersize=3, label='Recon.')
ylabel('Altitude [km]')
xlabel('LoS Velocity [m/s]')
legend(loc='best',numpoints=1,prop={'size':8},fancybox=True)
tight_layout()
Test using:
npzfile = load(truthfn)
truth_alts = npzfile['tang_alts']
truth_winds = npzfile['truth_winds']
truth_amps = npzfile['truth_amps']
npzfile.close()
plot(truth_winds, truth_alts, 'k-', label='Truth')
fn = L21_fn
npzfile = load(fn)
wind = npzfile['los_wind']
alt_of_wind = npzfile['alt_los_wind']
npzfile.close()
plot(wind_naive, alt_of_wind, 'b.-', markersize=3, label='Orig Recon.')
plot(wind, alt_of_wind, 'r.-', markersize=3, label='New Recon.')
ylabel('Altitude [km]')
xlabel('LoS Velocity [m/s]')
legend(loc='best',numpoints=1,prop={'size':6},fancybox=True)
tight_layout()
# Ignore satellite motion for now. (Include velocity in phase, though).
dt = datetime(2013,9,23,2,0,0) # UT
icon_alt = 550.
icon_lat = 20.5
icon_lon = 180. # daytime
icon_velocity = 0.0 # this will likely not be implemented
az = 90. # so that we're only measuring zonal wind
ze_top = 103
ze_bot = 109
ny = 50
nk = 101
#ny = 50
#nk = 501
impose_spherical_symmetry_winds = True
impose_spherical_symmetry_temps = True
impose_spherical_symmetry_ver = False
satlla = [icon_lat, icon_lon, icon_alt]
# Let's say that ICON is going purely east. This shouldn't matter, since velocity is zero.
icon_ecef_ram_vector = ICON.ven_to_ecef(satlla, [0, 1, 0])
# LOAD MIGHTI CONSTANTS/PARAMETERS
emission_color = 'red' # 'red' or 'green'
day = True
emissions = MIGHTI.get_emission_constants()
true_params = MIGHTI.get_instrument_constants()
true_params['exptime'] = 60. # sec
true_params['lam'] = emissions[emission_color]['lam']
true_params['frq'] = emissions[emission_color]['frq']
true_params['mass'] = emissions[emission_color]['mass']
if day: # 10% reduction in aperture size during "day", and shorter exposure time
true_params['aperture_area'] = true_params['aperture_area'] * 0.1
true_params['exptime'] = 30.
ray_length = 6000./nk
print '%.2f km steps' % ray_length
tanlla_top = ICON.tangent_point(satlla, az, ze_top)
tanlla_bot = ICON.tangent_point(satlla, az, ze_bot)
zevec = linspace(ze_bot, ze_top, ny)
mighti_ecef_vectors = zeros((ny,3))
alts_along_ray = zeros((nk,ny))
lats_along_ray = zeros((nk,ny))
lons_along_ray = zeros((nk,ny))
tang_alts = zeros(ny)
tang_lats = zeros(ny)
tang_lons = zeros(ny)
for i in range(ny):
ze = zevec[i]
# Determine tangent point
tang_pt = ICON.tangent_point(satlla, az, ze)
tang_alts[i] = tang_pt[2]
tang_lats[i] = tang_pt[0]
tang_lons[i] = tang_pt[1]
# Determine the ECEF look direction and record it
mighti_ecef_vectors[i,:] = ICON.azze_to_ecef(satlla, az, ze)
# Project the line of sight and record winds, temps, and amplitudes along the ray
xyz_proj,lla_proj = ICON.project_line_of_sight(satlla, az, ze, \
step_size = ray_length, total_distance=ray_length*nk)
alts_along_ray[:,i] = lla_proj[2,:]
lats_along_ray[:,i] = lla_proj[0,:]
lons_along_ray[:,i] = lla_proj[1,:]
print '%.1f - %.1f km' % (tang_alts[-1], tang_alts[0])
59.41 km steps 372.4 - 172.4 km
i = 0
figure(figsize=(9,3))
subplot(1,3,1)
plot(lats_along_ray[:,i],'k')
ylabel('lats')
subplot(1,3,2)
plot(lons_along_ray[:,i],'k')
ylabel('lons')
subplot(1,3,3)
plot(alts_along_ray[:,i],'k')
ylabel('alts')
tight_layout()
def get_airglow_VER(pt):
#VER = exp(-0.5*((altk - 250)/(50))**2)
VER = MIGHTI.get_redline_airglow(pt)
if pt.lon > 202.:
VER = 0.01
return VER
def get_wind(pt):
pt.run_hwm14()
return pt.u,pt.v,0.0
def get_temperature(pt):
pt.run_msis()
return pt.Tn_msis
# Build the three quantities needed by forward model: VER, LoS wind, and temp
emission_along_ray_r = zeros((nk,ny))
u_along_ray = zeros((nk,ny))
v_along_ray = zeros((nk,ny))
w_along_ray = zeros((nk,ny))
winds_along_ray = zeros((nk,ny)) # LoS
temps_along_ray = zeros((nk,ny))
ven_along_ray = zeros((nk,ny,3))
for i in range(ny):
look_xyz = mighti_ecef_vectors[i,:]
for k in range(nk):
latk = lats_along_ray[k,i]
lonk = lons_along_ray[k,i]
altk = alts_along_ray[k,i]
##### local VEN
ven_look = ICON.ecef_to_ven([latk, lonk, altk], look_xyz)
##### winds
if impose_spherical_symmetry_winds:
pt = pyglow.Point(dt, icon_lat, icon_lon, altk)
else:
pt = pyglow.Point(dt, latk, lonk, altk)
u,v,w = get_wind(pt)
u_along_ray[k,i] = u
v_along_ray[k,i] = v
w_along_ray[k,i] = w
winds_along_ray[k,i] = dot(ven_look,[w,u,v])
##### temperature
if impose_spherical_symmetry_temps:
pt = pyglow.Point(dt, icon_lat, icon_lon, altk)
else:
pt = pyglow.Point(dt, latk, lonk, altk)
T = get_temperature(pt)
temps_along_ray[k,i] = T
##### VER
if impose_spherical_symmetry_ver:
pt = pyglow.Point(dt, icon_lat, icon_lon, altk)
else:
pt = pyglow.Point(dt, latk, lonk, altk)
VER = get_airglow_VER(pt)
emission_along_ray_r[k,i] = VER*ray_length*1e3*1e6/1e10 # cm, km, 10^10 ph
clear_output(wait=True)
time_module.sleep(0.01)
print '%03i/%03i' % (i+1,ny)
sys.stdout.flush()
050/050
Test using:
i = 2
figure(figsize=(9,3))
subplot(1,3,1)
plot(winds_along_ray[:,i],'k')
ylabel('LoS wind [m/s]')
xlabel('Steps along ray')
subplot(1,3,2)
plot(temps_along_ray[:,i],'k')
ylabel('Temperature [K]')
xlabel('Steps along ray')
subplot(1,3,3)
plot(emission_along_ray_r[:,i],'k')
ylabel('VER [ph/cm^3/s]')
xlabel('Steps along ray')
tight_layout()
nx = true_params['npixelx']
ny = shape(winds_along_ray)[1] # number of rows of interferogram
nk = shape(winds_along_ray)[0] # number of steps along ray
Iraw = np.zeros((ny,nx))
for i in range(ny):
for k in range(nk):
amp = emission_along_ray_r[k,i]
vel = winds_along_ray[k,i]
temp = temps_along_ray[k,i]
true_params['V'] = vel
true_params['T'] = temp
true_params['I'] = amp
ccdslice = MIGHTI.interferogram(true_params)
Iraw[i,:] += ccdslice
#Inoisy = MIGHTI.add_noise(Iraw, true_params) # make sure units are right
Inoisy = Iraw.copy()
Ir = zeros(shape(Inoisy))
Ii = zeros(shape(Inoisy))
for i in range(shape(Inoisy)[0]):
# Filter with Hann window (in frequency) surrounding the peak
f = Inoisy[i,:]
F = np.fft.fft(f)
N = len(F)
n = arange(N)
# Create filter as per Ken Marr's email 2013/10/29
peaki = abs(F[5:floor(N/2)]).argmax() + 5
width1 = 20 # width of Hann window
width2 = 5 # width of plateau
hann = np.hanning(width1)
# Create full filter
H = hstack((zeros(peaki-width1/2-(width2-1)/2),
hann[:width1/2],
ones(width2),
hann[width1/2:],
zeros(N - peaki - width1/2 - (width2-1)/2 - 1)))
ap = hanning(N)
f = f - f.mean()
fap = f*ap
F = np.fft.fft(fap)
F2 = F * H
f2 = np.fft.ifft(F2)
Ir[i,:] = np.real(f2)
Ii[i,:] = np.imag(f2)
# Save L1 UIUC file
# Assume no change from start to end of exposure.
fn = '/home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz'
np.savez(fn,
Ir=Ir,
Ii=Ii,
tang_alt_start= tang_alts,
tang_alt_end = tang_alts,
tang_lat_start= tang_lats,
tang_lat_end = tang_lats,
tang_lon_start= tang_lons,
tang_lon_end = tang_lons,
emission_color= 'red',
icon_alt_start= icon_alt,
icon_alt_end= icon_alt,
icon_lat_start= icon_lat,
icon_lat_end= icon_lat,
icon_lon_start= icon_lon,
icon_lon_end= icon_lon,
mighti_ecef_vectors_start= mighti_ecef_vectors,
mighti_ecef_vectors_end= mighti_ecef_vectors,
icon_ecef_ram_vector_start= icon_ecef_ram_vector,
icon_ecef_ram_vector_end= icon_ecef_ram_vector,
icon_velocity_start= icon_velocity,
icon_velocity_end= icon_velocity,
datetime_created= datetime.now(),
source_files = [],
time = dt,)
print 'Saved to %s' % fn
Saved to /home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz
# Create a column vector with projected satellite velocity.
# Remember, we are ignoring horizontal extent for now.
proj_icon_vel = zeros(ny)
for i in range(ny):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
proj_icon_vel[i] = icon_velocity * np.dot(icon_ecef_ram_vector, look_ecef)
tang_point_along_ray = zeros(ny)
for i in range(ny):
kstar = argmin(alts_along_ray[:,i])
tang_point_along_ray[i] = kstar
truth_winds = zeros(ny)
truth_amps = zeros(ny)
for i in range(ny):
kstar = tang_point_along_ray[i]
truth_winds[i] = winds_along_ray[kstar,i] - proj_icon_vel[i]
truth_amps[i] = emission_along_ray_r[kstar,i]
subplot(1,2,1)
plot(truth_winds,tang_alts,'k.-')
subplot(1,2,2)
plot(truth_amps,tang_alts,'k')
tfn = '/home/bhardin2/MIGHTI/truth_winds_known_airglow.npz'
np.savez(tfn,
tang_alts=tang_alts,truth_winds=truth_winds,\
truth_amps=truth_amps)
print 'Saved to %s' % tfn
Saved to /home/bhardin2/MIGHTI/truth_winds_known_airglow.npz
from Scientific.IO.NetCDF import NetCDFFile as Dataset
from datetime import datetime, timedelta
from pyglow import pyglow
from mpl_toolkits.basemap import Basemap
import os
import glob
from scipy.interpolate import griddata
import subprocess
import MIGHTI
import ICON
def unwrap(x):
'''
Phase-unwrap a signal in [-pi,pi] which is increasing
'''
dx = diff(x)
xnew = zeros(len(x))
xnew[0] = x[0]
idx = dx < 0 # 0, or -pi ???
dx[idx] = dx[idx] + 2*pi
xnew[1:] = xnew[0] + cumsum(dx)
return xnew
def circular_mean(angle0,angle1):
'''
Find the mean angle, taking into account 0/360 crossover.
Input and output angles in degrees.
'''
return 180/pi*angle((exp(1j*angle0*pi/180.) + exp(1j*angle1*pi/180.))/2)
def level21(l1uiucfn, l21fn, show_plot=True):
'''
This attemps to do everything in the notebook above. Set l21fn='' to not save anything
'''
Nignore = 20 # ignore first and last few samples due to wraparound ringing (Can this be fixed by zero-padding?)
# ^ This is replicated in L1 code, but that's ok. As long as this one is larger.
phase_offset = -pi # This constant is added to all phases so that there is no chance of a pi/-pi crossover.
# In practice, we'll have to see how the interferometer turns out before deciding on this.
c = 299792458.0 # m/s, speed of light
# Specify ranges for plotting (even though the whole image is analyzed)
min_alt = {'red': 100, 'green': 87}
max_alt = {'red': 400, 'green': 200}
min_amp = 0.0 # if amplitude of fringe is below this, don't even try to analyze it
# Zero wind/phase (TODO: how will this be done for real, and what's the best way to simulate it?)
zero_phase = 252.07801858 + phase_offset# - 0.00196902 # last term added 2015-05-18 for vertical wind study
npzfile = load(l1uiucfn)
# Extract all information from the UIUC L1 file
Ii = npzfile['Ii']
Ir = npzfile['Ir']
emission_color = str(npzfile['emission_color'])
icon_alt_end = npzfile['icon_alt_end']
icon_alt_start = npzfile['icon_alt_start']
icon_lat_end = npzfile['icon_lat_end']
icon_lat_start = npzfile['icon_lat_start']
icon_lon_end = npzfile['icon_lon_end']
icon_lon_start = npzfile['icon_lon_start']
icon_velocity_start = npzfile['icon_velocity_start']
icon_velocity_end = npzfile['icon_velocity_end']
icon_ecef_ram_vector_start = npzfile['icon_ecef_ram_vector_start']
icon_ecef_ram_vector_end = npzfile['icon_ecef_ram_vector_end']
mighti_ecef_vectors_end = npzfile['mighti_ecef_vectors_end']
mighti_ecef_vectors_start = npzfile['mighti_ecef_vectors_start']
tang_alt_end = npzfile['tang_alt_end']
tang_alt_start = npzfile['tang_alt_start']
tang_lat_end = npzfile['tang_lat_end']
tang_lat_start = npzfile['tang_lat_start']
tang_lon_end = npzfile['tang_lon_end']
tang_lon_start = npzfile['tang_lon_start']
datetime_created = npzfile['datetime_created']
source_files = npzfile['source_files']
time = npzfile['time'] # we should really have start time and end time
#print 'Reading file %s' % l1uiucfn
#print 'Created %s' % datetime_created
# Take the midpoint of start and end.
icon_alt = (icon_alt_start+icon_alt_end)/2
icon_lat = (icon_lat_start+icon_lat_end)/2
icon_lon = circular_mean(icon_lon_start, icon_lon_end)
mighti_ecef_vectors = (mighti_ecef_vectors_start + mighti_ecef_vectors_end)/2 # ny by 3
tang_alts = (tang_alt_start + tang_alt_end)/2
tang_lats = (tang_lat_start + tang_lat_end)/2
tang_lons = circular_mean(tang_lon_start, tang_lon_end)
icon_ecef_ram_vector = (icon_ecef_ram_vector_start + icon_ecef_ram_vector_end)/2
icon_velocity = (icon_velocity_start+icon_velocity_end)/2
Ntheta = shape(Ir)[0]
npixel = shape(Ir)[1]
params = MIGHTI.get_instrument_constants()
emission = MIGHTI.get_emission_constants()[emission_color]
I = (Ir + 1j*Ii) * exp(1j*phase_offset)
theta = MIGHTI.tanht2angle(tang_alts, icon_alt)
RE = 6371 # TODO
startpath = params['startpath']
endpath = params['endpath']
sigma = 1.0/emission['lam']
# Create a column vector with projected satellite velocity. Remember, we are ignoring horizontal extent for now.
proj_icon_vel = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
proj_icon_vel[i] = icon_velocity * np.dot(icon_ecef_ram_vector, look_ecef)
# Transform velocity to phase
# dphi = 2*pi*OPD*sigma*v/c (Eqn 1 of Englert et al 2007 Appl Opt.)
# Use mean(opd) for now, but eventually it will be actual OPD once we include horizontal extent.
opd = linspace(startpath,endpath,npixel)
icon_vel_phase = 2*pi*mean(opd[Nignore:-Nignore])*sigma*proj_icon_vel/c
# Subtract phase from the interferogram (Change this when horizontal extent is included)
corr = exp(-1j*icon_vel_phase)
for jj in range(npixel):
I[:,jj] = I[:,jj]*corr
# Define grid. Bottom of each layer is defined by tangent height of observation.
rbottom = MIGHTI.angle2tanht(theta, icon_alt)
# Define top of each layer.
rtop = rbottom.copy()
rtop[:-1] = rbottom[1:]
rtop[-1] = rbottom[-1] + (rtop[1]-rbottom[1])
# Define midpt of each layer
rmid = (rbottom + rtop)/2
# Build observation matrix
D = zeros((Ntheta, len(rmid)))
for i in range(Ntheta):
for j in range(len(rmid)):
th = theta[i]
rb = rbottom[j]
rt = rtop[j]
sb = cos(th)**2 - 1 + ((RE+rb)/(RE+icon_alt))**2
st = cos(th)**2 - 1 + ((RE+rt)/(RE+icon_alt))**2
if sb < 0: # there is no intersection of LOS with altitude rb. Set term to 0.
# Note: this might be due to numerical rounding for tangent altitude.
# Do the same thing either way.
sb = 0.
if st < 0: # there is no intersection of LOS with altitude rt. Set term to 0.
st = 0.
D[i,j] = 2*(RE+icon_alt) * ( sqrt(st) - sqrt(sb) )
# Quick check to see if phase is near the pi/-pi crossover
# TODO: revamp this, including zero-wind removal
init_phase = zeros((Ntheta))
for j in range(Ntheta):
irow = I[j,:]
phase = angle(irow)
phaseu = unwrap(phase[Nignore:-Nignore])
init_phase[j] = phaseu[0]
ampl = abs(irow)
if max(ampl) < min_amp:
init_phase[j] = nan
if any(abs(init_phase) > 0.8*pi):
print 'WARNING: phase near pi/-pi crossover. Consider changing phase_offset'
if any(diff(init_phase) > 0.8*2*pi):
print 'WARNING: phase pi/-pi crossover detected. Consider changing phase_offset'
P = nan*zeros(len(rmid)) # analyzed phase of each shell
A = nan*zeros(len(rmid)) # analyzed intensity of each shell
Ip = nan*zeros(shape(I),dtype=complex) # matrix to hold onion-peeled, distance-normalized interferogram
# Calculate local-horizontal projection factors
B = nan*zeros(shape(D)) # matrix to hold cosine correction factors
for i in range(Ntheta):
for j in range(len(rmid)):
# Calculate b_ij = cos(angle between ray and shell tangent)
th = theta[i]
r = rmid[j]
B[i,j] = (RE+icon_alt)/(RE+r) * sin(th) # this ought to be <= 1, or there's no intersection
#B[i,j] = 1
# Onion-peel interferogram
Ip = linalg.solve(D,I)
for j in range(Ntheta):
r = rmid[j]
irow = Ip[j,:]
phase = angle(irow)
ampl = abs(irow)
if nanmax(ampl) > min_amp:
# average phase and then take delta. Need unwrapping for this.
phaseu = unwrap(phase[Nignore:-Nignore])
#phaseu = unwrap(phaseu)
meanphase = mean(phaseu)
dphase = meanphase - zero_phase
opd = linspace(startpath,endpath,npixel)[Nignore:-Nignore]
# Method B: multiply by mean(1/opd). These are different, but only slightly
#mean_recip_opd = mean(1/opd)
#vj = c * dphase / (2*pi*sigma) * mean_recip_opd
P[j] = dphase
A[j] = ampl[Nignore:-Nignore].mean()
# Convert phase to velocity
opd = linspace(startpath,endpath,npixel)
meanopd = mean(opd[Nignore:-Nignore])
V = c * P / (2*pi*sigma) * 1/meanopd
V[rmid < min_alt[emission_color]] = nan
V[rmid > max_alt[emission_color]] = nan
# Calculate local azimuth angles (i.e., at tangent point)
satlatlonalt = array([icon_lat, icon_lon, icon_alt])
local_az = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
look_az, look_ze = ICON.ecef_to_azze(satlatlonalt, look_ecef) # look direction in az, ze
tang_latlonalt = ICON.tangent_point(satlatlonalt, look_az, look_ze) # tangent point of observation
loc_az, loc_ze = ICON.ecef_to_azze(tang_latlonalt, look_ecef) # local (tangent point) direction in az, ze
local_az[i] = loc_az
if show_plot:
plot(V, rmid, '%s-' % emission_color[0])
xlabel('Velocity [m/s]')
ylabel('Altitude [km]')
if l21fn:
np.savez(l21fn,
tang_alt_start= tang_alt_start,
tang_alt_end = tang_alt_end,
tang_alt = tang_alts,
tang_lat_start= tang_lat_start,
tang_lat_end = tang_lat_end,
tang_lat = tang_lats,
tang_lon_start= tang_lon_start,
tang_lon_end = tang_lon_end,
tang_lon = tang_lons,
emission_color= emission_color,
icon_alt_start= icon_alt_start,
icon_alt_end= icon_alt_end,
icon_alt = icon_alt,
icon_lat_start= icon_lat_start,
icon_lat_end= icon_lat_end,
icon_lat = icon_lat,
icon_lon_start= icon_lon_start,
icon_lon_end= icon_lon_end,
icon_lon = icon_lon,
mighti_ecef_vectors_start= mighti_ecef_vectors_start,
mighti_ecef_vectors_end= mighti_ecef_vectors_end,
mighti_ecef_vectors = mighti_ecef_vectors,
icon_ecef_ram_vector_start= icon_ecef_ram_vector_start,
icon_ecef_ram_vector_end= icon_ecef_ram_vector_end,
icon_ecef_ram_vector = icon_ecef_ram_vector,
icon_velocity_start= icon_velocity_start,
icon_velocity_end= icon_velocity_end,
icon_velocity = icon_velocity,
datetime_created= datetime.now(),
source_files = [l1uiucfn],
time= time,
los_wind = V,
alt_los_wind = rmid, # TEMPORARY?
local_az = local_az,
)
npzfile.close()
uiucl1_fn = '/home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz'
out_fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
level21(uiucl1_fn,out_fn)
L21_fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
truthfn = '/home/bhardin2/MIGHTI/truth_winds_known_airglow.npz'
npzfile = load(truthfn)
truth_alts = npzfile['tang_alts']
truth_winds = npzfile['truth_winds']
truth_amps = npzfile['truth_amps']
npzfile.close()
subplot(1,2,1)
plot(truth_winds, truth_alts, 'k-', label='Truth')
subplot(1,2,2)
plot(truth_amps, truth_alts, 'k-', label='Truth')
xlabel('True VER')
xticks(xticks()[0][::2])
fn = L21_fn
npzfile = load(fn)
wind = npzfile['los_wind']
alt_of_wind = npzfile['alt_los_wind']
npzfile.close()
subplot(1,2,1)
plot(wind, alt_of_wind, 'r.', markersize=3, label='Recon.')
ylabel('Altitude [km]')
xlabel('LoS Velocity [m/s]')
legend(loc='best',numpoints=1,prop={'size':8},fancybox=True)
tight_layout()
wind_naive = wind.copy()
l1uiucfn = '/home/bhardin2/MIGHTI/MIGHTI_L1_UIUC_red_known_airglow.npz'
l21fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
show_plot = True
#def level21(l1uiucfn, l21fn, show_plot=True):
'''
This attemps to do everything in the notebook above. Set l21fn='' to not save anything
'''
Nignore = 20 # ignore first and last few samples due to wraparound ringing (Can this be fixed by zero-padding?)
# ^ This is replicated in L1 code, but that's ok. As long as this one is larger.
phase_offset = -pi # This constant is added to all phases so that there is no chance of a pi/-pi crossover.
# In practice, we'll have to see how the interferometer turns out before deciding on this.
c = 299792458.0 # m/s, speed of light
# Specify ranges for plotting (even though the whole image is analyzed)
min_alt = {'red': 100, 'green': 87}
max_alt = {'red': 400, 'green': 200}
min_amp = 0.0 # if amplitude of fringe is below this, don't even try to analyze it
# Zero wind/phase (TODO: how will this be done for real, and what's the best way to simulate it?)
zero_phase = 252.07801858 + phase_offset# - 0.00196902 # last term added 2015-05-18 for vertical wind study
npzfile = load(l1uiucfn)
# Extract all information from the UIUC L1 file
Ii = npzfile['Ii']
Ir = npzfile['Ir']
emission_color = str(npzfile['emission_color'])
icon_alt_end = npzfile['icon_alt_end']
icon_alt_start = npzfile['icon_alt_start']
icon_lat_end = npzfile['icon_lat_end']
icon_lat_start = npzfile['icon_lat_start']
icon_lon_end = npzfile['icon_lon_end']
icon_lon_start = npzfile['icon_lon_start']
icon_velocity_start = npzfile['icon_velocity_start']
icon_velocity_end = npzfile['icon_velocity_end']
icon_ecef_ram_vector_start = npzfile['icon_ecef_ram_vector_start']
icon_ecef_ram_vector_end = npzfile['icon_ecef_ram_vector_end']
mighti_ecef_vectors_end = npzfile['mighti_ecef_vectors_end']
mighti_ecef_vectors_start = npzfile['mighti_ecef_vectors_start']
tang_alt_end = npzfile['tang_alt_end']
tang_alt_start = npzfile['tang_alt_start']
tang_lat_end = npzfile['tang_lat_end']
tang_lat_start = npzfile['tang_lat_start']
tang_lon_end = npzfile['tang_lon_end']
tang_lon_start = npzfile['tang_lon_start']
datetime_created = npzfile['datetime_created']
source_files = npzfile['source_files']
time = npzfile['time'] # we should really have start time and end time
#print 'Reading file %s' % l1uiucfn
#print 'Created %s' % datetime_created
# Take the midpoint of start and end.
icon_alt = (icon_alt_start+icon_alt_end)/2
icon_lat = (icon_lat_start+icon_lat_end)/2
icon_lon = circular_mean(icon_lon_start, icon_lon_end)
mighti_ecef_vectors = (mighti_ecef_vectors_start + mighti_ecef_vectors_end)/2 # ny by 3
tang_alts = (tang_alt_start + tang_alt_end)/2
tang_lats = (tang_lat_start + tang_lat_end)/2
tang_lons = circular_mean(tang_lon_start, tang_lon_end)
icon_ecef_ram_vector = (icon_ecef_ram_vector_start + icon_ecef_ram_vector_end)/2
icon_velocity = (icon_velocity_start+icon_velocity_end)/2
Ntheta = shape(Ir)[0]
npixel = shape(Ir)[1]
params = MIGHTI.get_instrument_constants()
emission = MIGHTI.get_emission_constants()[emission_color]
I = (Ir + 1j*Ii) * exp(1j*phase_offset)
theta = MIGHTI.tanht2angle(tang_alts, icon_alt)
RE = 6371 # TODO
startpath = params['startpath']
endpath = params['endpath']
sigma = 1.0/emission['lam']
# Create a column vector with projected satellite velocity. Remember, we are ignoring horizontal extent for now.
proj_icon_vel = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
proj_icon_vel[i] = icon_velocity * np.dot(icon_ecef_ram_vector, look_ecef)
# Transform velocity to phase
# dphi = 2*pi*OPD*sigma*v/c (Eqn 1 of Englert et al 2007 Appl Opt.)
# Use mean(opd) for now, but eventually it will be actual OPD once we include horizontal extent.
opd = linspace(startpath,endpath,npixel)
icon_vel_phase = 2*pi*mean(opd[Nignore:-Nignore])*sigma*proj_icon_vel/c
# Subtract phase from the interferogram (Change this when horizontal extent is included)
corr = exp(-1j*icon_vel_phase)
for jj in range(npixel):
I[:,jj] = I[:,jj]*corr
# Define grid. Bottom of each layer is defined by tangent height of observation.
rbottom = MIGHTI.angle2tanht(theta, icon_alt)
# Define top of each layer.
rtop = rbottom.copy()
rtop[:-1] = rbottom[1:]
rtop[-1] = rbottom[-1] + (rtop[1]-rbottom[1])
# Define midpt of each layer
rmid = (rbottom + rtop)/2
# Build observation matrix
D = zeros((Ntheta, len(rmid)))
for i in range(Ntheta):
for j in range(len(rmid)):
th = theta[i]
rb = rbottom[j]
rt = rtop[j]
sb = cos(th)**2 - 1 + ((RE+rb)/(RE+icon_alt))**2
st = cos(th)**2 - 1 + ((RE+rt)/(RE+icon_alt))**2
if sb < 0: # there is no intersection of LOS with altitude rb. Set term to 0.
# Note: this might be due to numerical rounding for tangent altitude.
# Do the same thing either way.
sb = 0.
if st < 0: # there is no intersection of LOS with altitude rt. Set term to 0.
st = 0.
D[i,j] = 2*(RE+icon_alt) * ( sqrt(st) - sqrt(sb) )
# Calculate known airglow emission rate (VER) for each entry of the matrix.
# There are some notes on this in my ICON notebook (2015-08-25)
icon_latlonalt = np.array([icon_lat, icon_lon, icon_alt])
VER = zeros((Ntheta,len(rmid)))
for i in range(Ntheta):
for j in range(len(rmid)):
th = theta[i]
ze = th*180./pi
rb = rbottom[j]
rt = rtop[j]
s_first_top = distance_to_shell(icon_alt, th, rt, RE, 'first')
s_second_top = distance_to_shell(icon_alt, th, rt, RE, 'second')
s_first_bot = distance_to_shell(icon_alt, th, rb, RE, 'first')
s_second_bot = distance_to_shell(icon_alt, th, rb, RE, 'second')
#print '%.2f %.2f %.2f %.2f %.2f %.2f' % (rt, rb, s_first_top, s_second_top, \
# s_first_bot, s_second_bot)
if not isnan(s_first_top): # then we know this shell is intersected. Two cases:
if not isnan(s_first_bot): # then this shell is interesected twice.
s_first = (s_first_top + s_first_bot)/2
s_second = (s_second_top + s_second_bot)/2
latlonalt_first = project_along_ray(icon_latlonalt, az, ze, s_first)
latlonalt_second = project_along_ray(icon_latlonalt, az, ze, s_second)
pt_first = pyglow.Point(dt, latlonalt_first[0], latlonalt_first[1], latlonalt_first[2])
ver_first = get_airglow_VER(pt_first)
pt_second = pyglow.Point(dt, latlonalt_second[0], latlonalt_second[1], latlonalt_second[2])
ver_second = get_airglow_VER(pt_second)
VER[i,j] = ver_first + ver_second
else: # then this shell is intersected once
s = (s_first_top + s_second_top)/2
latlonalt = project_along_ray(icon_latlonalt, az, ze, s)
pt = pyglow.Point(dt, latlonalt[0], latlonalt[1], latlonalt[2])
ver = get_airglow_VER(pt)
VER[i,j]= ver
#if not isnan(s_first_top): # then we know this shell is intersected
#else:
# pass # ?
imshow(VER,interpolation='none')
<matplotlib.image.AxesImage at 0x7fdd66e12550>
Dprime = VER*D # element-wise multiplication
imshow(Dprime, interpolation='none')
<matplotlib.image.AxesImage at 0x7fdd66c5ba90>
cond(Dprime)
679.93663146008032
# Quick check to see if phase is near the pi/-pi crossover
# TODO: revamp this, including zero-wind removal
init_phase = zeros((Ntheta))
for j in range(Ntheta):
irow = I[j,:]
phase = angle(irow)
phaseu = unwrap(phase[Nignore:-Nignore])
init_phase[j] = phaseu[0]
ampl = abs(irow)
if max(ampl) < min_amp:
init_phase[j] = nan
if any(abs(init_phase) > 0.8*pi):
print 'WARNING: phase near pi/-pi crossover. Consider changing phase_offset'
if any(diff(init_phase) > 0.8*2*pi):
print 'WARNING: phase pi/-pi crossover detected. Consider changing phase_offset'
P = nan*zeros(len(rmid)) # analyzed phase of each shell
A = nan*zeros(len(rmid)) # analyzed intensity of each shell
Ip = nan*zeros(shape(I),dtype=complex) # matrix to hold onion-peeled, distance-normalized interferogram
# Calculate local-horizontal projection factors
# This isn't used in the standard processing
B = nan*zeros(shape(D)) # matrix to hold cosine correction factors
for i in range(Ntheta):
for j in range(len(rmid)):
# Calculate b_ij = cos(angle between ray and shell tangent)
th = theta[i]
r = rmid[j]
B[i,j] = (RE+icon_alt)/(RE+r) * sin(th) # this ought to be <= 1, or there's no intersection
#B[i,j] = 1
# Onion-peel interferogram
Ip = linalg.solve(D,I)
Ipprime = linalg.solve(Dprime,I)
# Analyze onion-peeled interferogram to get phase and amplitude
for j in range(Ntheta):
r = rmid[j]
irow = Ipprime[j,:]
phase = angle(irow)
ampl = abs(irow)
if nanmax(ampl) > min_amp:
# average phase and then take delta. Need unwrapping for this.
phaseu = unwrap(phase[Nignore:-Nignore])
#phaseu = unwrap(phaseu)
meanphase = mean(phaseu)
dphase = meanphase - zero_phase
opd = linspace(startpath,endpath,npixel)[Nignore:-Nignore]
# Method B: multiply by mean(1/opd). These are different, but only slightly
#mean_recip_opd = mean(1/opd)
#vj = c * dphase / (2*pi*sigma) * mean_recip_opd
P[j] = dphase
A[j] = ampl[Nignore:-Nignore].mean()
# Convert phase to velocity
opd = linspace(startpath,endpath,npixel)
meanopd = mean(opd[Nignore:-Nignore])
V = c * P / (2*pi*sigma) * 1/meanopd
V[rmid < min_alt[emission_color]] = nan
V[rmid > max_alt[emission_color]] = nan
# Calculate local azimuth angles (i.e., at tangent point)
satlatlonalt = array([icon_lat, icon_lon, icon_alt])
local_az = zeros(Ntheta)
for i in range(Ntheta):
look_ecef = mighti_ecef_vectors[i,:] # look direction of this pixel in ECEF
look_az, look_ze = ICON.ecef_to_azze(satlatlonalt, look_ecef) # look direction in az, ze
tang_latlonalt = ICON.tangent_point(satlatlonalt, look_az, look_ze) # tangent point of observation
loc_az, loc_ze = ICON.ecef_to_azze(tang_latlonalt, look_ecef) # local (tangent point) direction in az, ze
local_az[i] = loc_az
if show_plot:
plot(V, rmid, '%s-' % emission_color[0])
xlabel('Velocity [m/s]')
ylabel('Altitude [km]')
if l21fn:
np.savez(l21fn,
tang_alt_start= tang_alt_start,
tang_alt_end = tang_alt_end,
tang_alt = tang_alts,
tang_lat_start= tang_lat_start,
tang_lat_end = tang_lat_end,
tang_lat = tang_lats,
tang_lon_start= tang_lon_start,
tang_lon_end = tang_lon_end,
tang_lon = tang_lons,
emission_color= emission_color,
icon_alt_start= icon_alt_start,
icon_alt_end= icon_alt_end,
icon_alt = icon_alt,
icon_lat_start= icon_lat_start,
icon_lat_end= icon_lat_end,
icon_lat = icon_lat,
icon_lon_start= icon_lon_start,
icon_lon_end= icon_lon_end,
icon_lon = icon_lon,
mighti_ecef_vectors_start= mighti_ecef_vectors_start,
mighti_ecef_vectors_end= mighti_ecef_vectors_end,
mighti_ecef_vectors = mighti_ecef_vectors,
icon_ecef_ram_vector_start= icon_ecef_ram_vector_start,
icon_ecef_ram_vector_end= icon_ecef_ram_vector_end,
icon_ecef_ram_vector = icon_ecef_ram_vector,
icon_velocity_start= icon_velocity_start,
icon_velocity_end= icon_velocity_end,
icon_velocity = icon_velocity,
datetime_created= datetime.now(),
source_files = [l1uiucfn],
time= time,
los_wind = V,
alt_los_wind = rmid, # TEMPORARY?
local_az = local_az,
)
npzfile.close()
L21_fn = '/home/bhardin2/MIGHTI/MIGHTI_L21_UIUC_red_known_airglow.npz'
truthfn = '/home/bhardin2/MIGHTI/truth_winds_known_airglow.npz'
npzfile = load(truthfn)
truth_alts = npzfile['tang_alts']
truth_winds = npzfile['truth_winds']
truth_amps = npzfile['truth_amps']
npzfile.close()
subplot(1,2,1)
plot(truth_winds, truth_alts, 'k-', label='Truth')
subplot(1,2,2)
plot(truth_amps, truth_alts, 'k-', label='Truth')
xlabel('True VER')
xticks(xticks()[0][::2])
fn = L21_fn
npzfile = load(fn)
wind = npzfile['los_wind']
alt_of_wind = npzfile['alt_los_wind']
npzfile.close()
subplot(1,2,1)
plot(wind, alt_of_wind, 'r.', markersize=3, label='Recon.')
ylabel('Altitude [km]')
xlabel('LoS Velocity [m/s]')
legend(loc='best',numpoints=1,prop={'size':8},fancybox=True)
tight_layout()
npzfile = load(truthfn)
truth_alts = npzfile['tang_alts']
truth_winds = npzfile['truth_winds']
truth_amps = npzfile['truth_amps']
npzfile.close()
plot(truth_winds, truth_alts, 'k-', label='Truth')
fn = L21_fn
npzfile = load(fn)
wind = npzfile['los_wind']
alt_of_wind = npzfile['alt_los_wind']
npzfile.close()
plot(wind_naive, alt_of_wind, 'b.-', markersize=3, label='Orig Recon.')
plot(wind, alt_of_wind, 'r.-', markersize=3, label='New Recon.')
ylabel('Altitude [km]')
xlabel('LoS Velocity [m/s]')
legend(loc='best',numpoints=1,prop={'size':6},fancybox=True)
tight_layout()
#xlim((-80,-65))
Major problems under certain conditions (not shown).
import subprocess
import shutil
nb_name = 'MIGHTI_Known_VER_20150826.ipynb' # There's probably a way to get this programmatically
cmd = ['ipython', 'nbconvert', '--to', 'slides', nb_name, \
'--reveal-prefix', '"http://cdn.jsdelivr.net/reveal.js/2.6.2"',\
'--template','output_toggle']
# The --template command points to a custom template which opens and closes the input code cells with a click
subprocess.call(cmd)
html_name = '%s.slides.html' % (nb_name.split('.')[0])
shutil.copy(html_name, '/home/bhardin2/public_html/slideshows/')