def __init__(self, tau, dim, Fs, N=None, seed=None): if not (seed is None): np.random.seed(seed) if N is None: N = int(tau * Fs * 200) self.N = utils.optimize_fftsize(N, max_prime=5) f = np.fft.fftfreq(self.N, 1./Fs) a = 1 / (tau**2) spec = np.sqrt(np.pi / a) * np.exp(-np.pi**2 * f**2 / a) s_f = (np.random.normal(size=self.N) + 1j * np.random.normal(size=self.N)) s = np.fft.ifft(s_f * np.sqrt(spec)) self.s = s / np.sqrt(np.mean(np.abs(s)**2)) self.ind0 = (N * np.random.uniform(size=dim)).astype(int) self.Fs= Fs
def skim_process(cfg_file, raw_output_file): ################### # INITIALIZATIONS # ################### # CONFIGURATION FILE cfg = tpio.ConfigFile(cfg_file) info = utils.PrInfo(cfg.sim.verbosity, "processor") # Say hello info.msg(time.strftime("Starting: %Y-%m-%d %H:%M:%S", time.localtime())) # PROCESSING az_weighting = cfg.processing.az_weighting doppler_bw = cfg.processing.doppler_bw plot_format = cfg.processing.plot_format plot_tex = cfg.processing.plot_tex plot_save = cfg.processing.plot_save plot_path = cfg.processing.plot_path plot_raw = cfg.processing.plot_raw plot_rcmc_dopp = cfg.processing.plot_rcmc_dopp plot_rcmc_time = cfg.processing.plot_rcmc_time plot_image_valid = cfg.processing.plot_image_valid doppler_demod = cfg.processing.doppler_demod pp_file = os.path.join(cfg.sim.path, cfg.sim.pp_file) # radar f0 = cfg.radar.f0 prf = cfg.radar.prf # num_ch = cfg.radar.num_ch alt = cfg.radar.alt v_ground = cfg.radar.v_ground # CALCULATE PARAMETERS l0 = const.c / f0 if v_ground == 'auto': v_ground = geo.orbit_to_vel(alt, ground=True) rg_sampling = cfg.radar.Fs # Range freqency axis f_axis = np.linspace(0, rg_sampling, cfg.radar.n_rg) wavenum_scale = f_axis * 4 * np.pi / const.c * np.sin( np.radians(cfg.radar.inc_angle)) # RAW DATA raw_file = tpio.RawFile(raw_output_file, 'r') raw_data = raw_file.get('raw_data*') info.msg("Raw data max: %f" % (np.max(np.abs(raw_data)))) dop_ref = raw_file.get('dop_ref') sr0 = raw_file.get('sr0') azimuth = raw_file.get('azimuth') raw_file.close() #n_az # OTHER INITIALIZATIONS # Create plots directory plot_path = os.path.dirname(pp_file) + os.sep + plot_path if plot_save: if not os.path.exists(plot_path): os.makedirs(plot_path) ######################## # PROCESSING MAIN LOOP # ######################## # Optimize matrix sizes az_size_orig, rg_size_orig = raw_data[0].shape optsize = utils.optimize_fftsize(raw_data[0].shape) # optsize = [optsize[0], optsize[1]] data = np.zeros(optsize, dtype=complex) data[0:az_size_orig, 0:rg_size_orig] = raw_data[0] # Doppler demodulation according to geometric Doppler if doppler_demod: info.msg("Doppler demodulation") t_vec = (np.arange(optsize[0]) / prf).reshape((optsize[0], 1)) data[:, 0:rg_size_orig] = (data[:, 0:rg_size_orig] * np.exp( (-2j * np.pi) * t_vec * dop_ref.reshape((1, rg_size_orig)))) # Pulse pair info.msg("Range over-sampling") data_ovs = range_oversample(data) info.msg("Pulse-pair processing") dop_pp_avg, dop_pha_avg, coh = pulse_pair( data_ovs[0:az_size_orig, 0:2 * rg_size_orig], prf) krv, mean_int_profile, int_spe, phase_spec = rar_spectra( data_ovs[0:az_size_orig, 0:2 * rg_size_orig], 2 * rg_sampling, rgsmth=8) kxv = krv * np.sin(np.radians(cfg.radar.inc_angle)) range_spectrum(data[0:az_size_orig, 0:rg_size_orig], rg_sampling, plot_path) info.msg("Mean DCA (pulse-pair average): %f Hz" % (np.mean(dop_pp_avg))) info.msg("Mean DCA (pulse-pair phase average): %f Hz" % (np.mean(dop_pha_avg))) info.msg("Mean coherence: %f " % (np.mean(coh))) # Unfocused SAR info.msg("Unfocused SAR") int_unfcs, data_ufcs = unfocused_sar( data_ovs[0:az_size_orig, 0:2 * rg_size_orig], cfg.processing.n_sar) krv2, sar_int_spec = sar_spectra(int_unfcs, 2 * rg_sampling, rgsmth=8) # Some delta-k on focused sar data info.msg("Unfocused SAR delta-k spectrum") dkr, dk_avg, dk_signal = sar_delta_k(data_ufcs, 2 * rg_sampling, dksmoth=8) dk_pulse_pairs, dk_omega = sar_delta_k_omega(dk_signal, cfg.processing.n_sar / prf, dksmoth=16) # For verification, comment out # dkr_sl, dk_avg_sl, dk_signal_sl = sar_delta_k_slow(data_ufcs, 2 * rg_sampling, dksmoth=8) # dk_pulse_pairs_sl, dk_omega_sl = sar_delta_k_omega(dk_signal_sl, cfg.processing.n_sar/prf, dksmoth=32) info.msg( time.strftime("Processing done [%Y-%m-%d %H:%M:%S]", time.localtime())) if plot_raw: plt.figure() plt.imshow(np.real(raw_data[0]), vmin=-np.max(np.abs(raw_data[0])), vmax=np.max(np.abs(raw_data[0])), origin='lower', aspect=np.float(raw_data[0].shape[1]) / np.float(raw_data[0].shape[0]), cmap='viridis') #plt.title() plt.xlabel("Range [samples]") plt.ylabel("Azimuth [samples") plt.savefig(plot_path + os.sep + 'plot_raw_real.%s' % plot_format, dpi=150) plt.close() plt.figure() plt.imshow(np.abs(raw_data[0]), vmin=0, vmax=np.max(np.abs(raw_data[0])), origin='lower', aspect=np.float(raw_data[0].shape[1]) / np.float(raw_data[0].shape[0]), cmap='viridis') #plt.title() plt.xlabel("Range [samples]") plt.ylabel("Azimuth [samples") plt.savefig(plot_path + os.sep + 'plot_raw_abs.%s' % plot_format, dpi=150) plt.close() plt.figure() plt.imshow(np.fft.fftshift(int_unfcs, axes=(0, )), origin='lower', aspect='auto', cmap='viridis') # plt.title() plt.xlabel("Range [samples]") plt.ylabel("Doppler [samples") plt.savefig(plot_path + os.sep + 'ufcs_int.%s' % plot_format, dpi=150) plt.close() plt.figure() plt.plot(mean_int_profile) plt.xlabel("Range samples [Pixels]") plt.ylabel("Intensity") plt.savefig(plot_path + os.sep + 'mean_int.%s' % plot_format) plt.close() plt.figure() plt.plot(np.fft.fftshift(kxv), np.fft.fftshift(int_spe)) plt.ylim((int_spe[20:np.int(cfg.radar.n_rg) - 20].min() / 2, int_spe[20:np.int(cfg.radar.n_rg) - 20].max() * 1.5)) plt.xlim((0, kxv.max())) plt.xlabel("$k_x$ [rad/m]") plt.ylabel("$S_I$") plt.savefig(plot_path + os.sep + 'int_spec.%s' % plot_format) plt.close() plt.figure() plt.plot(np.fft.fftshift(kxv), np.fft.fftshift(sar_int_spec)) plt.ylim((sar_int_spec[20:np.int(cfg.radar.n_rg) - 20].min() / 2, sar_int_spec[20:np.int(cfg.radar.n_rg) - 20].max() * 1.5)) plt.xlim((0, kxv.max())) plt.xlabel("$k_x$ [rad/m]") plt.ylabel("$S_I$") plt.savefig(plot_path + os.sep + 'sar_int_spec.%s' % plot_format) plt.close() plt.figure() plt.plot(np.fft.fftshift(kxv), np.fft.fftshift(phase_spec)) plt.ylim((phase_spec[20:np.int(cfg.radar.n_rg) - 20].min() / 2, phase_spec[20:np.int(cfg.radar.n_rg) - 20].max() * 1.5)) plt.xlabel("$k_x$ [rad/m]") plt.xlim((0, kxv.max())) plt.ylabel("$S_{Doppler}$") plt.savefig(plot_path + os.sep + 'pp_phase_spec.%s' % plot_format) plt.figure() dkx = dkr * np.sin(np.radians(cfg.radar.inc_angle)) plt.plot(dkx, dk_avg) plt.ylim((dk_avg[20:dkx.size - 20].min() / 2, dk_avg[20:dkx.size - 20].max() * 1.5)) plt.xlim((0.1, dkx.max())) plt.xlabel("$\Delta k_x$ [rad/m]") plt.ylabel("$S_I$") plt.savefig(plot_path + os.sep + 'sar_delta_k_spec.%s' % plot_format) plt.close() # plt.figure() # dkx_sl = dkr_sl * np.sin(np.radians(cfg.radar.inc_angle)) # plt.plot(dkx_sl, dk_avg_sl) # plt.ylim((dk_avg_sl[20:dkx.size-20].min()/2, # dk_avg_sl[20:dkx.size-20].max()*1.5)) # plt.xlim((0, dkx.max())) # plt.xlabel("$\Delta k_x$ [rad/m]") # plt.ylabel("$S_I$") # plt.savefig(plot_path + os.sep + 'sar_delta_k_spec_slow.%s' % plot_format) # plt.close() plt.figure() # plt.plot(dkx, dk_omega[0], label="lag=1") plt.plot(dkx, dk_omega[1], label="lag=2") # plt.plot(dkx, dk_omega_sl[0] + 1, label="slow-lag=1") # plt.plot(dkx, dk_omega_sl[1] + 1, label="slow-lag=2") plt.plot(dkx, dk_omega[3], label="lag=4") # plt.plot(dkx, dk_omega[-1], label="lag=max") plt.ylim((-20, 20)) #plt.ylim((dk_avg[20:dkx.size - 20].min() / 2, # dk_avg[20:dkx.size - 20].max() * 1.5)) plt.xlim((0.05, 0.8)) plt.xlabel("$\Delta k_x$ [rad/m]") plt.ylabel("$\omega$ [rad/s]") plt.legend(loc=0) plt.savefig(plot_path + os.sep + 'sar_delta_k_omega.%s' % plot_format) plt.close() info.msg("Saving output to %s" % pp_file) np.savez(pp_file, dop_pp_avg=dop_pp_avg, dop_pha_avg=dop_pha_avg, coh=coh, ufcs_intensity=int_unfcs, mean_int_profile=mean_int_profile, int_spec=int_spe, sar_int_spec=sar_int_spec, ppphase_spec=phase_spec, kx=kxv, dk_spec=dk_avg, dk_omega=dk_omega, dkx=dkx) info.msg(time.strftime("All done [%Y-%m-%d %H:%M:%S]", time.localtime()))
def sarraw(cfg_file, output_file, ocean_file, reuse_ocean_file, errors_file, reuse_errors_file): ################### # INITIALIZATIONS # ################### ## MPI SETUP comm = MPI.COMM_WORLD size, rank = comm.Get_size(), comm.Get_rank() ## WELCOME if rank == 0: print( '-------------------------------------------------------------------' ) print((time.strftime("- OCEANSAR SAR RAW GENERATOR: %Y-%m-%d %H:%M:%S", time.localtime()))) print('- Copyright (c) Gerard Marull Paretas, Paco Lopez Dekker') print( '-------------------------------------------------------------------' ) ## CONFIGURATION FILE # Note: variables are 'copied' to reduce code verbosity cfg = tpio.ConfigFile(cfg_file) # RAW wh_tol = cfg.srg.wh_tol nesz = cfg.srg.nesz use_hmtf = cfg.srg.use_hmtf scat_spec_enable = cfg.srg.scat_spec_enable scat_spec_mode = cfg.srg.scat_spec_mode scat_bragg_enable = cfg.srg.scat_bragg_enable scat_bragg_model = cfg.srg.scat_bragg_model scat_bragg_d = cfg.srg.scat_bragg_d scat_bragg_spec = cfg.srg.scat_bragg_spec scat_bragg_spread = cfg.srg.scat_bragg_spread # SAR inc_angle = np.deg2rad(cfg.sar.inc_angle) f0 = cfg.sar.f0 pol = cfg.sar.pol if pol == 'DP': do_hh = True do_vv = True elif pol == 'hh': do_hh = True do_vv = False else: do_hh = False do_vv = True prf = cfg.sar.prf num_ch = int(cfg.sar.num_ch) ant_L = cfg.sar.ant_L alt = cfg.sar.alt v_ground = cfg.sar.v_ground rg_bw = cfg.sar.rg_bw over_fs = cfg.sar.over_fs sigma_n_tx = cfg.sar.sigma_n_tx phase_n_tx = np.deg2rad(cfg.sar.phase_n_tx) sigma_beta_tx = cfg.sar.sigma_beta_tx phase_beta_tx = np.deg2rad(cfg.sar.phase_beta_tx) sigma_n_rx = cfg.sar.sigma_n_rx phase_n_rx = np.deg2rad(cfg.sar.phase_n_rx) sigma_beta_rx = cfg.sar.sigma_beta_rx phase_beta_rx = np.deg2rad(cfg.sar.phase_beta_rx) # OCEAN / OTHERS ocean_dt = cfg.ocean.dt add_point_target = False use_numba = True n_sinc_samples = 8 sinc_ovs = 20 chan_sinc_vec = raw.calc_sinc_vec(n_sinc_samples, sinc_ovs, Fs=over_fs) # OCEAN SURFACE if rank == 0: print('Initializing ocean surface...') surface_full = OceanSurface() # Setup compute values compute = ['D', 'Diff', 'Diff2'] if use_hmtf: compute.append('hMTF') # Try to reuse initialized surface if reuse_ocean_file: try: surface_full.load(ocean_file, compute) except RuntimeError: pass if (not reuse_ocean_file) or (not surface_full.initialized): surface_full.init(cfg.ocean.Lx, cfg.ocean.Ly, cfg.ocean.dx, cfg.ocean.dy, cfg.ocean.cutoff_wl, cfg.ocean.spec_model, cfg.ocean.spread_model, np.deg2rad(cfg.ocean.wind_dir), cfg.ocean.wind_fetch, cfg.ocean.wind_U, cfg.ocean.current_mag, np.deg2rad(cfg.ocean.current_dir), cfg.ocean.swell_enable, cfg.ocean.swell_ampl, np.deg2rad(cfg.ocean.swell_dir), cfg.ocean.swell_wl, compute, cfg.ocean.opt_res, cfg.ocean.fft_max_prime, choppy_enable=cfg.ocean.choppy_enable) surface_full.save(ocean_file) else: surface_full = None # Initialize surface balancer surface = OceanSurfaceBalancer(surface_full, ocean_dt) # CALCULATE PARAMETERS if rank == 0: print('Initializing simulation parameters...') # SR/GR/INC Matrixes sr0 = geosar.inc_to_sr(inc_angle, alt) gr0 = geosar.inc_to_gr(inc_angle, alt) gr = surface.x + gr0 sr, inc, _ = geosar.gr_to_geo(gr, alt) sr -= np.min(sr) #inc = np.repeat(inc[np.newaxis, :], surface.Ny, axis=0) #sr = np.repeat(sr[np.newaxis, :], surface.Ny, axis=0) #gr = np.repeat(gr[np.newaxis, :], surface.Ny, axis=0) #Let's try to safe some memory and some operations inc = inc.reshape(1, inc.size) sr = sr.reshape(1, sr.size) gr = gr.reshape(1, gr.size) sin_inc = np.sin(inc) cos_inc = np.cos(inc) # lambda, K, resolution, time, etc. l0 = const.c / f0 k0 = 2. * np.pi * f0 / const.c sr_res = const.c / (2. * rg_bw) if cfg.sar.L_total: ant_L = ant_L / np.float(num_ch) d_chan = ant_L else: if np.float(cfg.sar.Spacing) != 0: d_chan = np.float(cfg.sar.Spacing) else: d_chan = ant_L if v_ground == 'auto': v_ground = geosar.orbit_to_vel(alt, ground=True) t_step = 1. / prf t_span = (1.5 * (sr0 * l0 / ant_L) + surface.Ly) / v_ground az_steps = np.int(np.floor(t_span / t_step)) # Number of RG samples max_sr = np.max(sr) + wh_tol + (np.max(surface.y_full) + (t_span / 2.) * v_ground)**2. / (2. * sr0) min_sr = np.min(sr) - wh_tol rg_samp_orig = np.int(np.ceil(((max_sr - min_sr) / sr_res) * over_fs)) rg_samp = np.int(utils.optimize_fftsize(rg_samp_orig)) # Other initializations if do_hh: proc_raw_hh = np.zeros([num_ch, az_steps, rg_samp], dtype=np.complex) if do_vv: proc_raw_vv = np.zeros([num_ch, az_steps, rg_samp], dtype=np.complex) t_last_rcs_bragg = -1. last_progress = -1 NRCS_avg_vv = np.zeros(az_steps, dtype=np.float) NRCS_avg_hh = np.zeros(az_steps, dtype=np.float) ## RCS MODELS # Specular if scat_spec_enable: if scat_spec_mode == 'kodis': rcs_spec = rcs.RCSKodis(inc, k0, surface.dx, surface.dy) elif scat_spec_mode == 'fa' or scat_spec_mode == 'spa': spec_ph0 = np.random.uniform(0., 2. * np.pi, size=[surface.Ny, surface.Nx]) rcs_spec = rcs.RCSKA(scat_spec_mode, k0, surface.x, surface.y, surface.dx, surface.dy) else: raise NotImplementedError( 'RCS mode %s for specular scattering not implemented' % scat_spec_mode) # Bragg if scat_bragg_enable: phase_bragg = np.zeros([2, surface.Ny, surface.Nx]) bragg_scats = np.zeros([2, surface.Ny, surface.Nx], dtype=np.complex) # dop_phase_p = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) # dop_phase_m = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) tau_c = closure.grid_coherence(cfg.ocean.wind_U, surface.dx, f0) rndscat_p = closure.randomscat_ts(tau_c, (surface.Ny, surface.Nx), prf) rndscat_m = closure.randomscat_ts(tau_c, (surface.Ny, surface.Nx), prf) # NOTE: This ignores slope, may be changed k_b = 2. * k0 * sin_inc c_b = sin_inc * np.sqrt(const.g / k_b + 0.072e-3 * k_b) if scat_bragg_model == 'romeiser97': current_dir = np.deg2rad(cfg.ocean.current_dir) current_vec = (cfg.ocean.current_mag * np.array( [np.cos(current_dir), np.sin(current_dir)])) U_dir = np.deg2rad(cfg.ocean.wind_dir) U_vec = (cfg.ocean.wind_U * np.array([np.cos(U_dir), np.sin(U_dir)])) U_eff_vec = U_vec - current_vec rcs_bragg = rcs.RCSRomeiser97( k0, inc, pol, surface.dx, surface.dy, linalg.norm(U_eff_vec), np.arctan2(U_eff_vec[1], U_eff_vec[0]), surface.wind_fetch, scat_bragg_spec, scat_bragg_spread, scat_bragg_d) else: raise NotImplementedError( 'RCS model %s for Bragg scattering not implemented' % scat_bragg_model) surface_area = surface.dx * surface.dy * surface.Nx * surface.Ny ################### # SIMULATION LOOP # ################### if rank == 0: print('Computing profiles...') for az_step in np.arange(az_steps, dtype=np.int): ## AZIMUTH & SURFACE UPDATE t_now = az_step * t_step az_now = (t_now - t_span / 2.) * v_ground # az = np.repeat((surface.y - az_now)[:, np.newaxis], surface.Nx, axis=1) az = (surface.y - az_now).reshape((surface.Ny, 1)) surface.t = t_now ## COMPUTE RCS FOR EACH MODEL # Note: SAR processing is range independent as slant range is fixed sin_az = az / sr0 az_proj_angle = np.arcsin(az / gr0) # Note: Projected displacements are added to slant range sr_surface = (sr - cos_inc * surface.Dz + az / 2 * sin_az + surface.Dx * sin_inc + surface.Dy * sin_az) if do_hh: scene_hh = np.zeros( [int(surface.Ny), int(surface.Nx)], dtype=np.complex) if do_vv: scene_vv = np.zeros( [int(surface.Ny), int(surface.Nx)], dtype=np.complex) # Point target if add_point_target and rank == 0: sr_pt = (sr[0, surface.Nx / 2] + az[surface.Ny / 2, 0] / 2 * sin_az[surface.Ny / 2, surface.Nx / 2]) pt_scat = (100. * np.exp(-1j * 2. * k0 * sr_pt)) if do_hh: scene_hh[surface.Ny / 2, surface.Nx / 2] = pt_scat if do_vv: scene_vv[surface.Ny / 2, surface.Nx / 2] = pt_scat sr_surface[surface.Ny / 2, surface.Nx / 2] = sr_pt # Specular if scat_spec_enable: if scat_spec_mode == 'kodis': Esn_sp = np.sqrt(4. * np.pi) * rcs_spec.field( az_proj_angle, sr_surface, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy) if do_hh: scene_hh += Esn_sp if do_vv: scene_vv += Esn_sp else: # FIXME if do_hh: pol_tmp = 'hh' Esn_sp = ( np.exp(-1j * (2. * k0 * sr_surface)) * (4. * np.pi)**1.5 * rcs_spec.field( 1, 1, pol_tmp[0], pol_tmp[1], inc, inc, az_proj_angle, az_proj_angle + np.pi, surface.Dz, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy)) scene_hh += Esn_sp if do_vv: pol_tmp = 'vv' Esn_sp = ( np.exp(-1j * (2. * k0 * sr_surface)) * (4. * np.pi)**1.5 * rcs_spec.field( 1, 1, pol_tmp[0], pol_tmp[1], inc, inc, az_proj_angle, az_proj_angle + np.pi, surface.Dz, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy)) scene_vv += Esn_sp NRCS_avg_hh[az_step] += (np.sum(np.abs(Esn_sp)**2) / surface_area) NRCS_avg_vv[az_step] += NRCS_avg_hh[az_step] # Bragg if scat_bragg_enable: if (t_now - t_last_rcs_bragg) > ocean_dt: if scat_bragg_model == 'romeiser97': if pol == 'DP': RCS_bragg_hh, RCS_bragg_vv = rcs_bragg.rcs( az_proj_angle, surface.Diffx, surface.Diffy) elif pol == 'hh': RCS_bragg_hh = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) else: RCS_bragg_vv = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) if use_hmtf: # Fix Bad MTF points surface.hMTF[np.where(surface.hMTF < -1)] = -1 if do_hh: RCS_bragg_hh[0] *= (1 + surface.hMTF) RCS_bragg_hh[1] *= (1 + surface.hMTF) if do_vv: RCS_bragg_vv[0] *= (1 + surface.hMTF) RCS_bragg_vv[1] *= (1 + surface.hMTF) t_last_rcs_bragg = t_now if do_hh: scat_bragg_hh = np.sqrt(RCS_bragg_hh) NRCS_bragg_hh_instant_avg = np.sum(RCS_bragg_hh) / surface_area NRCS_avg_hh[az_step] += NRCS_bragg_hh_instant_avg if do_vv: scat_bragg_vv = np.sqrt(RCS_bragg_vv) NRCS_bragg_vv_instant_avg = np.sum(RCS_bragg_vv) / surface_area NRCS_avg_vv[az_step] += NRCS_bragg_vv_instant_avg # Doppler phases (Note: Bragg radial velocity taken constant!) surf_phase = -(2 * k0) * sr_surface cap_phase = (2 * k0) * t_step * c_b * (az_step + 1) phase_bragg[0] = surf_phase - cap_phase # + dop_phase_p phase_bragg[1] = surf_phase + cap_phase # + dop_phase_m bragg_scats[0] = rndscat_m.scats(t_now) bragg_scats[1] = rndscat_p.scats(t_now) if do_hh: scene_hh += ne.evaluate( 'sum(scat_bragg_hh * exp(1j*phase_bragg) * bragg_scats, axis=0)' ) if do_vv: scene_vv += ne.evaluate( 'sum(scat_bragg_vv * exp(1j*phase_bragg) * bragg_scats, axis=0)' ) ## ANTENNA PATTERN if cfg.sar.L_total: beam_pattern = sinc_1tx_nrx(sin_az, ant_L * num_ch, f0, num_ch, field=True) else: beam_pattern = sinc_1tx_nrx(sin_az, ant_L, f0, 1, field=True) ## GENERATE CHANEL PROFILES for ch in np.arange(num_ch, dtype=np.int): if do_hh: scene_bp = scene_hh * beam_pattern # Add channel phase & compute profile scene_bp *= np.exp(-1j * k0 * d_chan * ch * sin_az) if use_numba: raw.chan_profile_numba(sr_surface.flatten(), scene_bp.flatten(), sr_res / (over_fs), min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_hh[ch][az_step]) else: raw.chan_profile_weave(sr_surface.flatten(), scene_bp.flatten(), sr_res / (over_fs), min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_hh[ch][az_step]) if do_vv: scene_bp = scene_vv * beam_pattern # Add channel phase & compute profile scene_bp *= np.exp(-1j * k0 * d_chan * ch * sin_az) if use_numba: raw.chan_profile_numba(sr_surface.flatten(), scene_bp.flatten(), sr_res / (over_fs), min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_vv[ch][az_step]) else: raw.chan_profile_weave(sr_surface.flatten(), scene_bp.flatten(), sr_res / (over_fs), min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_vv[ch][az_step]) # SHOW PROGRESS (%) current_progress = np.int((100 * az_step) / az_steps) if current_progress != last_progress: last_progress = current_progress print(('SP,%d,%d,%d' % (rank, size, current_progress))) # MERGE RESULTS if do_hh: total_raw_hh = np.empty_like(proc_raw_hh) if rank == 0 else None comm.Reduce(proc_raw_hh, total_raw_hh, op=MPI.SUM, root=0) if do_vv: total_raw_vv = np.empty_like(proc_raw_vv) if rank == 0 else None comm.Reduce(proc_raw_vv, total_raw_vv, op=MPI.SUM, root=0) ## PROCESS REDUCED RAW DATA & SAVE (ROOT) if rank == 0: print('Processing and saving results...') # Filter and decimate #range_filter = np.ones_like(total_raw) #range_filter[:, :, rg_samp/(2*2*cfg.sar.over_fs):-rg_samp/(2*2*cfg.sar.over_fs)] = 0 #total_raw = np.fft.ifft(range_filter*np.fft.fft(total_raw)) if do_hh: total_raw_hh = total_raw_hh[:, :, :rg_samp_orig] if do_vv: total_raw_vv = total_raw_vv[:, :, :rg_samp_orig] # Calibration factor (projected antenna pattern integrated in azimuth) az_axis = np.arange(-t_span / 2. * v_ground, t_span / 2. * v_ground, sr0 * const.c / (np.pi * f0 * ant_L * 10.)) if cfg.sar.L_total: pattern = sinc_1tx_nrx(az_axis / sr0, ant_L * num_ch, f0, num_ch, field=True) else: pattern = sinc_1tx_nrx(az_axis / sr0, ant_L, f0, 1, field=True) cal_factor = (1. / np.sqrt( np.trapz(np.abs(pattern)**2., az_axis) * sr_res / np.sin(inc_angle))) if do_hh: noise = (utils.db2lin(nesz, amplitude=True) / np.sqrt(2.) * (np.random.normal(size=total_raw_hh.shape) + 1j * np.random.normal(size=total_raw_hh.shape))) total_raw_hh = total_raw_hh * cal_factor + noise if do_vv: noise = (utils.db2lin(nesz, amplitude=True) / np.sqrt(2.) * (np.random.normal(size=total_raw_vv.shape) + 1j * np.random.normal(size=total_raw_vv.shape))) total_raw_vv = total_raw_vv * cal_factor + noise # Add slow-time error # if use_errors: # if do_hh: # total_raw_hh *= errors.beta_noise # if do_vv: # total_raw_vv *= errors.beta_noise # Save RAW data (and other properties, used by 3rd party software) if do_hh and do_vv: rshp = (1, ) + total_raw_hh.shape total_raw = np.concatenate( (total_raw_hh.reshape(rshp), total_raw_vv.reshape(rshp))) rshp = (1, ) + NRCS_avg_hh.shape NRCS_avg = np.concatenate( (NRCS_avg_hh.reshape(rshp), NRCS_avg_vv.reshape(rshp))) elif do_hh: rshp = (1, ) + total_raw_hh.shape total_raw = total_raw_hh.reshape(rshp) rshp = (1, ) + NRCS_avg_hh.shape NRCS_avg = NRCS_avg_hh.reshape(rshp) else: rshp = (1, ) + total_raw_vv.shape total_raw = total_raw_vv.reshape(rshp) rshp = (1, ) + NRCS_avg_vv.shape NRCS_avg = NRCS_avg_vv.reshape(rshp) raw_file = tpio.RawFile(output_file, 'w', total_raw.shape) raw_file.set('inc_angle', np.rad2deg(inc_angle)) raw_file.set('f0', f0) raw_file.set('num_ch', num_ch) raw_file.set('ant_L', ant_L) raw_file.set('prf', prf) raw_file.set('v_ground', v_ground) raw_file.set('orbit_alt', alt) raw_file.set('sr0', sr0) raw_file.set('rg_sampling', rg_bw * over_fs) raw_file.set('rg_bw', rg_bw) raw_file.set('raw_data*', total_raw) raw_file.set('NRCS_avg', NRCS_avg) raw_file.close() print((time.strftime("Finished [%Y-%m-%d %H:%M:%S]", time.localtime())))
def fastraw(cfg_file, output_file, ocean_file, reuse_ocean_file, errors_file, reuse_errors_file, plot_save=True): ################### # INITIALIZATIONS # ################### ## MPI SETUP comm = MPI.COMM_WORLD size, rank = comm.Get_size(), comm.Get_rank() ## WELCOME if rank == 0: print('-------------------------------------------------------------------') print(time.strftime("- OCEANSAR FAST RAW SAR GENERATOR: %Y-%m-%d %H:%M:%S", time.localtime())) print('-------------------------------------------------------------------') ## CONFIGURATION FILE # Note: variables are 'copied' to reduce code verbosity cfg = tpio.ConfigFile(cfg_file) # RAW wh_tol = cfg.srg.wh_tol nesz = cfg.srg.nesz use_hmtf = cfg.srg.use_hmtf scat_spec_enable = cfg.srg.scat_spec_enable scat_spec_mode = cfg.srg.scat_spec_mode scat_bragg_enable = cfg.srg.scat_bragg_enable scat_bragg_model = cfg.srg.scat_bragg_model scat_bragg_d = cfg.srg.scat_bragg_d scat_bragg_spec = cfg.srg.scat_bragg_spec scat_bragg_spread = cfg.srg.scat_bragg_spread # SAR inc_angle = np.deg2rad(cfg.sar.inc_angle) f0 = cfg.sar.f0 pol = cfg.sar.pol squint_r = np.degrees(cfg.sar.squint) if pol == 'DP': do_hh = True do_vv = True elif pol == 'hh': do_hh = True do_vv = False else: do_hh = False do_vv = True prf = cfg.sar.prf num_ch = int(cfg.sar.num_ch) ant_l = cfg.sar.ant_L alt = cfg.sar.alt v_ground = cfg.sar.v_ground rg_bw = cfg.sar.rg_bw over_fs = cfg.sar.over_fs sigma_n_tx = cfg.sar.sigma_n_tx phase_n_tx = np.deg2rad(cfg.sar.phase_n_tx) sigma_beta_tx = cfg.sar.sigma_beta_tx phase_beta_tx = np.deg2rad(cfg.sar.phase_beta_tx) sigma_n_rx = cfg.sar.sigma_n_rx phase_n_rx = np.deg2rad(cfg.sar.phase_n_rx) sigma_beta_rx = cfg.sar.sigma_beta_rx phase_beta_rx = np.deg2rad(cfg.sar.phase_beta_rx) # OCEAN / OTHERS ocean_dt = cfg.ocean.dt add_point_target = False use_numba = True n_sinc_samples = 8 sinc_ovs = 20 chan_sinc_vec = raw.calc_sinc_vec(n_sinc_samples, sinc_ovs, Fs=over_fs) # OCEAN SURFACE print('Initializing ocean surface...') surface = OceanSurface() # Setup compute values compute = ['D', 'Diff', 'Diff2'] if use_hmtf: compute.append('hMTF') # Try to reuse initialized surface if reuse_ocean_file: try: surface.load(ocean_file, compute) except RuntimeError: pass if (not reuse_ocean_file) or (not surface.initialized): if hasattr(cfg.ocean, 'use_buoy_data'): if cfg.ocean.use_buoy_data: bdataf = cfg.ocean.buoy_data_file date = datetime.datetime(np.int(cfg.ocean.year), np.int(cfg.ocean.month), np.int(cfg.ocean.day), np.int(cfg.ocean.hour), np.int(cfg.ocean.minute), 0) date, bdata = tpio.load_buoydata(bdataf, date) buoy_spec = tpio.BuoySpectra(bdata, heading=cfg.sar.heading, depth=cfg.ocean.depth) dirspectrum_func = buoy_spec.Sk2 # Since the wind direction is included in the buoy data wind_dir = 0 else: dirspectrum_func = None wind_dir = np.deg2rad(cfg.ocean.wind_dir) else: dirspectrum_func = None wind_dir = np.deg2rad(cfg.ocean.wind_dir) surface.init(cfg.ocean.Lx, cfg.ocean.Ly, cfg.ocean.dx, cfg.ocean.dy, cfg.ocean.cutoff_wl, cfg.ocean.spec_model, cfg.ocean.spread_model, wind_dir, cfg.ocean.wind_fetch, cfg.ocean.wind_U, cfg.ocean.current_mag, np.deg2rad(cfg.ocean.current_dir), cfg.ocean.dir_swell_dir, cfg.ocean.freq_r, cfg.ocean.sigf, cfg.ocean.sigs, cfg.ocean.Hs, cfg.ocean.swell_dir_enable, cfg.ocean.swell_enable, cfg.ocean.swell_ampl, np.deg2rad(cfg.ocean.swell_dir), cfg.ocean.swell_wl, compute, cfg.ocean.opt_res, cfg.ocean.fft_max_prime, choppy_enable=cfg.ocean.choppy_enable, depth=cfg.ocean.depth, dirspectrum_func=dirspectrum_func) surface.save(ocean_file) # Now we plot the directional spectrum # self.wave_dirspec[good_k] = dirspectrum_func(self.kx[good_k], self.ky[good_k]) plt.figure() plt.imshow(np.fft.fftshift(surface.wave_dirspec), extent=[surface.kx.min(), surface.kx.max(), surface.ky.min(), surface.ky.max()], origin='lower', cmap='inferno_r') plt.grid(True) pltax = plt.gca() pltax.set_xlim((-0.1, 0.1)) pltax.set_ylim((-0.1, 0.1)) narr_length = 0.08 # np.min([surface_full.kx.max(), surface_full.ky.max()]) pltax.arrow(0, 0, -narr_length * np.sin(np.radians(cfg.sar.heading)), narr_length * np.cos(np.radians(cfg.sar.heading)), fc="k", ec="k") plt.xlabel('$k_x$ [rad/m]') plt.ylabel('$k_y$ [rad/m]') plt.colorbar() #plt.show() # Create plots directory plot_path = os.path.dirname(output_file) + os.sep + 'raw_plots' if plot_save: if not os.path.exists(plot_path): os.makedirs(plot_path) plt.savefig(os.path.join(plot_path, 'input_dirspectrum.png')) plt.close() # CALCULATE PARAMETERS if rank == 0: print('Initializing simulation parameters...') # SR/GR/INC Matrixes sr0 = geosar.inc_to_sr(inc_angle, alt) gr0 = geosar.inc_to_gr(inc_angle, alt) gr = surface.x + gr0 sr, inc, _ = geosar.gr_to_geo(gr, alt) sr -= np.min(sr) inc = inc.reshape(1, inc.size) sr = sr.reshape(1, sr.size) gr = gr.reshape(1, gr.size) sin_inc = np.sin(inc) cos_inc = np.cos(inc) # lambda, K, resolution, time, etc. l0 = const.c/f0 k0 = 2.*np.pi*f0/const.c sr_res = const.c/(2.*rg_bw) if cfg.sar.L_total: ant_l = ant_l/np.float(num_ch) d_chan = ant_l else: if np.float(cfg.sar.Spacing) != 0: d_chan = np.float(cfg.sar.Spacing) else: d_chan = ant_l if v_ground == 'auto': v_ground = geosar.orbit_to_vel(alt, ground=True) t_step = 1./prf t_span = (1.5*(sr0*l0/ant_l) + surface.Ly)/v_ground az_steps = np.int(np.floor(t_span/t_step)) # Number of RG samples max_sr = np.max(sr) + wh_tol + (np.max(surface.y) + (t_span/2.)*v_ground)**2./(2.*sr0) min_sr = np.min(sr) - wh_tol rg_samp_orig = np.int(np.ceil(((max_sr - min_sr)/sr_res)*over_fs)) rg_samp = np.int(utils.optimize_fftsize(rg_samp_orig)) # Other initializations if do_hh: proc_raw_hh = np.zeros([num_ch, az_steps, rg_samp], dtype=np.complex) if do_vv: proc_raw_vv = np.zeros([num_ch, az_steps, rg_samp], dtype=np.complex) t_last_rcs_bragg = -1. last_progress = -1 nrcs_avg_vv = np.zeros(az_steps, dtype=np.float) nrcs_avg_hh = np.zeros(az_steps, dtype=np.float) ## RCS MODELS # Specular if scat_spec_enable: if scat_spec_mode == 'kodis': rcs_spec = rcs.RCSKodis(inc, k0, surface.dx, surface.dy) elif scat_spec_mode == 'fa' or scat_spec_mode == 'spa': spec_ph0 = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) rcs_spec = rcs.RCSKA(scat_spec_mode, k0, surface.x, surface.y, surface.dx, surface.dy) else: raise NotImplementedError('RCS mode %s for specular scattering not implemented' % scat_spec_mode) # Bragg if scat_bragg_enable: phase_bragg = np.zeros([2, surface.Ny, surface.Nx]) bragg_scats = np.zeros([2, surface.Ny, surface.Nx], dtype=np.complex) # dop_phase_p = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) # dop_phase_m = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) tau_c = closure.grid_coherence(cfg.ocean.wind_U,surface.dx, f0) rndscat_p = closure.randomscat_ts(tau_c, (surface.Ny, surface.Nx), prf) rndscat_m = closure.randomscat_ts(tau_c, (surface.Ny, surface.Nx), prf) # NOTE: This ignores slope, may be changed k_b = 2.*k0*sin_inc c_b = sin_inc*np.sqrt(const.g/k_b + 0.072e-3*k_b) if scat_bragg_model == 'romeiser97': current_dir = np.deg2rad(cfg.ocean.current_dir) current_vec = (cfg.ocean.current_mag * np.array([np.cos(current_dir), np.sin(current_dir)])) U_dir = np.deg2rad(cfg.ocean.wind_dir) U_vec = (cfg.ocean.wind_U * np.array([np.cos(U_dir), np.sin(U_dir)])) U_eff_vec = U_vec - current_vec rcs_bragg = rcs.RCSRomeiser97(k0, inc, pol, surface.dx, surface.dy, linalg.norm(U_eff_vec), np.arctan2(U_eff_vec[1], U_eff_vec[0]), surface.wind_fetch, scat_bragg_spec, scat_bragg_spread, scat_bragg_d) else: raise NotImplementedError('RCS model %s for Bragg scattering not implemented' % scat_bragg_model) surface_area = surface.dx * surface.dy * surface.Nx * surface.Ny ################### # SIMULATION LOOP # ################### if rank == 0: print('Computing profiles...') for az_step in np.arange(az_steps, dtype=np.int): # AZIMUTH & SURFACE UPDATE t_now = az_step * t_step az_now = (t_now - t_span/2.)*v_ground # az = np.repeat((surface.y - az_now)[:, np.newaxis], surface.Nx, axis=1) az = (surface.y - az_now).reshape((surface.Ny, 1)) surface.t = t_now # COMPUTE RCS FOR EACH MODEL # Note: SAR processing is range independent as slant range is fixed sin_az = az / sr0 az_proj_angle = np.arcsin(az / gr0) # Note: Projected displacements are added to slant range sr_surface = (sr - cos_inc*surface.Dz + az/2*sin_az + surface.Dx*sin_inc + surface.Dy*sin_az) if do_hh: scene_hh = np.zeros([int(surface.Ny), int(surface.Nx)], dtype=np.complex) if do_vv: scene_vv = np.zeros([int(surface.Ny), int(surface.Nx)], dtype=np.complex) # Point target if add_point_target and rank == 0: sr_pt = (sr[0, surface.Nx/2] + az[surface.Ny/2, 0]/2 * sin_az[surface.Ny/2, surface.Nx/2]) pt_scat = (100. * np.exp(-1j * 2. * k0 * sr_pt)) if do_hh: scene_hh[surface.Ny/2, surface.Nx/2] = pt_scat if do_vv: scene_vv[surface.Ny/2, surface.Nx/2] = pt_scat sr_surface[surface.Ny/2, surface.Nx/2] = sr_pt # Specular if scat_spec_enable: if scat_spec_mode == 'kodis': Esn_sp = np.sqrt(4.*np.pi)*rcs_spec.field(az_proj_angle, sr_surface, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy) if do_hh: scene_hh += Esn_sp if do_vv: scene_vv += Esn_sp else: # FIXME if do_hh: pol_tmp = 'hh' Esn_sp = (np.exp(-1j*(2.*k0*sr_surface)) * (4.*np.pi)**1.5 * rcs_spec.field(1, 1, pol_tmp[0], pol_tmp[1], inc, inc, az_proj_angle, az_proj_angle + np.pi, surface.Dz, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy)) scene_hh += Esn_sp if do_vv: pol_tmp = 'vv' Esn_sp = (np.exp(-1j*(2.*k0*sr_surface)) * (4.*np.pi)**1.5 * rcs_spec.field(1, 1, pol_tmp[0], pol_tmp[1], inc, inc, az_proj_angle, az_proj_angle + np.pi, surface.Dz, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy)) scene_vv += Esn_sp nrcs_avg_hh[az_step] += (np.sum(np.abs(Esn_sp)**2) / surface_area) nrcs_avg_vv[az_step] += nrcs_avg_hh[az_step] # Bragg if scat_bragg_enable: if (t_now - t_last_rcs_bragg) > ocean_dt: if scat_bragg_model == 'romeiser97': if pol == 'DP': rcs_bragg_hh, rcs_bragg_vv = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) elif pol=='hh': rcs_bragg_hh = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) else: rcs_bragg_vv = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) if use_hmtf: # Fix Bad MTF points surface.hMTF[np.where(surface.hMTF < -1)] = -1 if do_hh: rcs_bragg_hh[0] *= (1 + surface.hMTF) rcs_bragg_hh[1] *= (1 + surface.hMTF) if do_vv: rcs_bragg_vv[0] *= (1 + surface.hMTF) rcs_bragg_vv[1] *= (1 + surface.hMTF) t_last_rcs_bragg = t_now if do_hh: scat_bragg_hh = np.sqrt(rcs_bragg_hh) nrcs_bragg_hh_instant_avg = np.sum(rcs_bragg_hh) / surface_area nrcs_avg_hh[az_step] += nrcs_bragg_hh_instant_avg if do_vv: scat_bragg_vv = np.sqrt(rcs_bragg_vv) nrcs_bragg_vv_instant_avg = np.sum(rcs_bragg_vv) / surface_area nrcs_avg_vv[az_step] += nrcs_bragg_vv_instant_avg # Doppler phases (Note: Bragg radial velocity taken constant!) surf_phase = - (2 * k0) * sr_surface cap_phase = (2 * k0) * t_step * c_b * (az_step + 1) phase_bragg[0] = surf_phase - cap_phase # + dop_phase_p phase_bragg[1] = surf_phase + cap_phase # + dop_phase_m bragg_scats[0] = rndscat_m.scats(t_now) bragg_scats[1] = rndscat_p.scats(t_now) if do_hh: scene_hh += ne.evaluate('sum(scat_bragg_hh * exp(1j*phase_bragg) * bragg_scats, axis=0)') if do_vv: scene_vv += ne.evaluate('sum(scat_bragg_vv * exp(1j*phase_bragg) * bragg_scats, axis=0)') # ANTENNA PATTERN # FIXME: this assume co-located Tx and Tx, so it will not work for true bistatic configurations if cfg.sar.L_total: beam_pattern = sinc_1tx_nrx(sin_az, ant_l * num_ch, f0, num_ch, field=True) else: beam_pattern = sinc_1tx_nrx(sin_az, ant_l, f0, 1, field=True) # GENERATE CHANEL PROFILES for ch in np.arange(num_ch, dtype=np.int): if do_hh: scene_bp = scene_hh * beam_pattern # Add channel phase & compute profile scene_bp *= np.exp(-1j*k0*d_chan*ch*sin_az) if use_numba: raw.chan_profile_numba(sr_surface.flatten(), scene_bp.flatten(), sr_res / over_fs, min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_hh[ch][az_step]) else: raw.chan_profile_weave(sr_surface.flatten(), scene_bp.flatten(), sr_res / over_fs, min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_hh[ch][az_step]) if do_vv: scene_bp = scene_vv * beam_pattern # Add channel phase & compute profile scene_bp *= np.exp(-1j*k0*d_chan*ch*sin_az) if use_numba: raw.chan_profile_numba(sr_surface.flatten(), scene_bp.flatten(), sr_res / over_fs, min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_vv[ch][az_step]) else: raw.chan_profile_weave(sr_surface.flatten(), scene_bp.flatten(), sr_res / over_fs, min_sr, chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_vv[ch][az_step]) # SHOW PROGRESS (%) current_progress = np.int((100 * az_step) / az_steps) if current_progress != last_progress: last_progress = current_progress print('SP,%d,%d,%d' % (rank, size, current_progress)) # PROCESS REDUCED RAW DATA & SAVE (ROOT) if rank == 0: print('Processing and saving results...') # Filter and decimate #range_filter = np.ones_like(total_raw) #range_filter[:, :, rg_samp/(2*2*cfg.sar.over_fs):-rg_samp/(2*2*cfg.sar.over_fs)] = 0 #total_raw = np.fft.ifft(range_filter*np.fft.fft(total_raw)) if do_hh: proc_raw_hh = proc_raw_hh[:, :, :rg_samp_orig] if do_vv: proc_raw_vv = proc_raw_vv[:, :, :rg_samp_orig] # Calibration factor (projected antenna pattern integrated in azimuth) az_axis = np.arange(-t_span/2.*v_ground, t_span/2.*v_ground, sr0*const.c/(np.pi*f0*ant_l*10.)) if cfg.sar.L_total: pattern = sinc_1tx_nrx(az_axis/sr0, ant_l * num_ch, f0, num_ch, field=True) else: pattern = sinc_1tx_nrx(az_axis/sr0, ant_l, f0, 1, field=True) cal_factor = (1. / np.sqrt(np.trapz(np.abs(pattern)**2., az_axis) * sr_res/np.sin(inc_angle))) if do_hh: noise = (utils.db2lin(nesz, amplitude=True) / np.sqrt(2.) * (np.random.normal(size=proc_raw_hh.shape) + 1j*np.random.normal(size=proc_raw_hh.shape))) total_raw_hh = proc_raw_hh * cal_factor + noise if do_vv: noise = (utils.db2lin(nesz, amplitude=True) / np.sqrt(2.) * (np.random.normal(size=proc_raw_vv.shape) + 1j*np.random.normal(size=proc_raw_vv.shape))) total_raw_vv = proc_raw_vv * cal_factor + noise # Add slow-time error # if use_errors: # if do_hh: # total_raw_hh *= errors.beta_noise # if do_vv: # total_raw_vv *= errors.beta_noise # Save RAW data (and other properties, used by 3rd party software) if do_hh and do_vv: rshp = (1,) + proc_raw_hh.shape proc_raw = np.concatenate((proc_raw_hh.reshape(rshp), proc_raw_vv.reshape(rshp))) rshp = (1,) + nrcs_avg_hh.shape NRCS_avg = np.concatenate((nrcs_avg_hh.reshape(rshp), nrcs_avg_vv.reshape(rshp))) elif do_hh: rshp = (1,) + proc_raw_hh.shape proc_raw = proc_raw_hh.reshape(rshp) rshp = (1,) + nrcs_avg_hh.shape NRCS_avg = nrcs_avg_hh.reshape(rshp) else: rshp = (1,) + proc_raw_vv.shape proc_raw = proc_raw_vv.reshape(rshp) rshp = (1,) + nrcs_avg_vv.shape NRCS_avg = nrcs_avg_vv.reshape(rshp) raw_file = tpio.RawFile(output_file, 'w', proc_raw.shape) raw_file.set('inc_angle', np.rad2deg(inc_angle)) raw_file.set('f0', f0) raw_file.set('num_ch', num_ch) raw_file.set('ant_l', ant_l) raw_file.set('prf', prf) raw_file.set('v_ground', v_ground) raw_file.set('orbit_alt', alt) raw_file.set('sr0', sr0) raw_file.set('rg_sampling', rg_bw*over_fs) raw_file.set('rg_bw', rg_bw) raw_file.set('raw_data*', proc_raw) raw_file.set('NRCS_avg', NRCS_avg) raw_file.close() print(time.strftime("Finished [%Y-%m-%d %H:%M:%S]", time.localtime()))
def skimraw(cfg_file, output_file, ocean_file, reuse_ocean_file, errors_file, reuse_errors_file, plot_save=True): ################### # INITIALIZATIONS # ################### # MPI SETUP comm = MPI.COMM_WORLD size, rank = comm.Get_size(), comm.Get_rank() # WELCOME if rank == 0: print( '-------------------------------------------------------------------' ) print( time.strftime("- OCEANSAR SKIM RAW GENERATOR: %Y-%m-%d %H:%M:%S", time.localtime())) # print('- Copyright (c) Gerard Marull Paretas, Paco Lopez Dekker') print( '-------------------------------------------------------------------' ) # CONFIGURATION FILE # Note: variables are 'copied' to reduce code verbosity cfg = tpio.ConfigFile(cfg_file) info = utils.PrInfo(cfg.sim.verbosity, "SKIM raw") # RAW wh_tol = cfg.srg.wh_tol nesz = cfg.srg.nesz use_hmtf = cfg.srg.use_hmtf scat_spec_enable = cfg.srg.scat_spec_enable scat_spec_mode = cfg.srg.scat_spec_mode scat_bragg_enable = cfg.srg.scat_bragg_enable scat_bragg_model = cfg.srg.scat_bragg_model scat_bragg_d = cfg.srg.scat_bragg_d scat_bragg_spec = cfg.srg.scat_bragg_spec scat_bragg_spread = cfg.srg.scat_bragg_spread # SAR inc_angle = np.deg2rad(cfg.radar.inc_angle) f0 = cfg.radar.f0 pol = cfg.radar.pol squint_r = np.radians(90 - cfg.radar.azimuth) if pol == 'DP': do_hh = True do_vv = True elif pol == 'hh': do_hh = True do_vv = False else: do_hh = False do_vv = True prf = cfg.radar.prf num_ch = int(cfg.radar.num_ch) ant_L = cfg.radar.ant_L alt = cfg.radar.alt v_ground = cfg.radar.v_ground rg_bw = cfg.radar.rg_bw over_fs = cfg.radar.Fs / cfg.radar.rg_bw sigma_n_tx = cfg.radar.sigma_n_tx phase_n_tx = np.deg2rad(cfg.radar.phase_n_tx) sigma_beta_tx = cfg.radar.sigma_beta_tx phase_beta_tx = np.deg2rad(cfg.radar.phase_beta_tx) sigma_n_rx = cfg.radar.sigma_n_rx phase_n_rx = np.deg2rad(cfg.radar.phase_n_rx) sigma_beta_rx = cfg.radar.sigma_beta_rx phase_beta_rx = np.deg2rad(cfg.radar.phase_beta_rx) # OCEAN / OTHERS ocean_dt = cfg.ocean.dt if hasattr(cfg.sim, "cal_targets"): if cfg.sim.cal_targets is False: add_point_target = False # This for debugging point_target_floats = True # Not really needed, but makes coding easier later else: print("Adding cal targets") add_point_target = True if cfg.sim.cal_targets.lower() == 'floating': point_target_floats = True else: point_target_floats = False else: add_point_target = False # This for debugging point_target_floats = True n_sinc_samples = 10 sinc_ovs = 20 chan_sinc_vec = raw.calc_sinc_vec(n_sinc_samples, sinc_ovs, Fs=over_fs) # Set win direction with respect to beam # I hope the following line is correct, maybe sign is wrong wind_dir = cfg.radar.azimuth - cfg.ocean.wind_dir # OCEAN SURFACE if rank == 0: print('Initializing ocean surface...') surface_full = OceanSurface() # Setup compute values compute = ['D', 'Diff', 'Diff2'] if use_hmtf: compute.append('hMTF') # Try to reuse initialized surface if reuse_ocean_file: try: surface_full.load(ocean_file, compute) except RuntimeError: pass if (not reuse_ocean_file) or (not surface_full.initialized): if hasattr(cfg.ocean, 'use_buoy_data'): if cfg.ocean.use_buoy_data: bdataf = cfg.ocean.buoy_data_file date = datetime.datetime(np.int(cfg.ocean.year), np.int(cfg.ocean.month), np.int(cfg.ocean.day), np.int(cfg.ocean.hour), np.int(cfg.ocean.minute), 0) date, bdata = tpio.load_buoydata(bdataf, date) # FIX-ME: direction needs to consider also azimuth of beam buoy_spec = tpio.BuoySpectra(bdata, heading=cfg.radar.heading, depth=cfg.ocean.depth) dirspectrum_func = buoy_spec.Sk2 # Since the wind direction is included in the buoy data wind_dir = 0 else: dirspectrum_func = None if cfg.ocean.swell_dir_enable: dir_swell_spec = s_spec.ardhuin_swell_spec else: dir_swell_spec = None wind_dir = np.deg2rad(wind_dir) else: if cfg.ocean.swell_dir_enable: dir_swell_spec = s_spec.ardhuin_swell_spec else: dir_swell_spec = None dirspectrum_func = None wind_dir = np.deg2rad(wind_dir) surface_full.init( cfg.ocean.Lx, cfg.ocean.Ly, cfg.ocean.dx, cfg.ocean.dy, cfg.ocean.cutoff_wl, cfg.ocean.spec_model, cfg.ocean.spread_model, wind_dir, cfg.ocean.wind_fetch, cfg.ocean.wind_U, cfg.ocean.current_mag, np.deg2rad(cfg.radar.azimuth - cfg.ocean.current_dir), cfg.radar.azimuth - cfg.ocean.dir_swell_dir, cfg.ocean.freq_r, cfg.ocean.sigf, cfg.ocean.sigs, cfg.ocean.Hs, cfg.ocean.swell_dir_enable, cfg.ocean.swell_enable, cfg.ocean.swell_ampl, np.deg2rad(cfg.radar.azimuth - cfg.ocean.swell_dir), cfg.ocean.swell_wl, compute, cfg.ocean.opt_res, cfg.ocean.fft_max_prime, choppy_enable=cfg.ocean.choppy_enable, depth=cfg.ocean.depth, dirspectrum_func=dirspectrum_func, dir_swell_spec=dir_swell_spec) surface_full.save(ocean_file) # Now we plot the directional spectrum # self.wave_dirspec[good_k] = dirspectrum_func(self.kx[good_k], self.ky[good_k]) plt.figure() plt.imshow(np.fft.fftshift(surface_full.wave_dirspec), extent=[ surface_full.kx.min(), surface_full.kx.max(), surface_full.ky.min(), surface_full.ky.max() ], origin='lower', cmap='inferno_r') plt.grid(True) pltax = plt.gca() pltax.set_xlim((-1, 1)) pltax.set_ylim((-1, 1)) Narr_length = 0.08 # np.min([surface_full.kx.max(), surface_full.ky.max()]) pltax.arrow(0, 0, -Narr_length * np.sin(np.radians(cfg.radar.heading)), Narr_length * np.cos(np.radians(cfg.radar.heading)), fc="k", ec="k") plt.xlabel('$k_x$ [rad/m]') plt.ylabel('$k_y$ [rad/m]') plt.colorbar() #plt.show() # Create plots directory plot_path = os.path.dirname(output_file) + os.sep + 'raw_plots' if plot_save: if not os.path.exists(plot_path): os.makedirs(plot_path) plt.savefig(os.path.join(plot_path, 'input_dirspectrum.png')) plt.close() if cfg.ocean.swell_dir_enable: plt.figure() plt.imshow(np.fft.fftshift(np.abs(surface_full.swell_dirspec)), extent=[ surface_full.kx.min(), surface_full.kx.max(), surface_full.ky.min(), surface_full.ky.max() ], origin='lower', cmap='inferno_r') plt.grid(True) pltax = plt.gca() pltax.set_xlim((-0.1, 0.1)) pltax.set_ylim((-0.1, 0.1)) Narr_length = 0.08 # np.min([surface_full.kx.max(), surface_full.ky.max()]) pltax.arrow( 0, 0, -Narr_length * np.sin(np.radians(cfg.radar.heading)), Narr_length * np.cos(np.radians(cfg.radar.heading)), fc="k", ec="k") plt.xlabel('$k_x$ [rad/m]') plt.ylabel('$k_y$ [rad/m]') plt.colorbar() #plt.show() # Create plots directory plot_path = os.path.dirname(output_file) + os.sep + 'raw_plots' if plot_save: if not os.path.exists(plot_path): os.makedirs(plot_path) plt.savefig( os.path.join(plot_path, 'input_dirspectrum_combined.png')) plt.close() else: surface_full = None # Initialize surface balancer surface = OceanSurfaceBalancer(surface_full, ocean_dt) # CALCULATE PARAMETERS if rank == 0: print('Initializing simulation parameters...') # SR/GR/INC Matrixes sr0 = geosar.inc_to_sr(inc_angle, alt) gr0 = geosar.inc_to_gr(inc_angle, alt) gr = surface.x + gr0 sr, inc, _ = geosar.gr_to_geo(gr, alt) print(sr.dtype) look = geosar.inc_to_look(inc, alt) min_sr = np.min(sr) # sr -= np.min(sr) #inc = np.repeat(inc[np.newaxis, :], surface.Ny, axis=0) #sr = np.repeat(sr[np.newaxis, :], surface.Ny, axis=0) #gr = np.repeat(gr[np.newaxis, :], surface.Ny, axis=0) #Let's try to safe some memory and some operations inc = inc.reshape(1, inc.size) look = look.reshape(1, inc.size) sr = sr.reshape(1, sr.size) gr = gr.reshape(1, gr.size) sin_inc = np.sin(inc) cos_inc = np.cos(inc) # lambda, K, resolution, time, etc. l0 = const.c / f0 k0 = 2. * np.pi * f0 / const.c sr_res = const.c / (2. * rg_bw) sr_smp = const.c / (2 * cfg.radar.Fs) if cfg.radar.L_total: ant_L = ant_L / np.float(num_ch) if v_ground == 'auto': v_ground = geosar.orbit_to_vel(alt, ground=True) v_orb = geosar.orbit_to_vel(alt, ground=False) else: v_orb = v_ground t_step = 1. / prf az_steps = int(cfg.radar.n_pulses) t_span = az_steps / prf rg_samp = np.int(utils.optimize_fftsize(cfg.radar.n_rg)) #min_sr = np.mean(sr) - rg_samp / 2 * sr_smp print(sr_smp) max_sr = np.mean(sr) + rg_samp / 2 * sr_smp sr_prof = (np.arange(rg_samp) - rg_samp / 2) * sr_smp + np.mean(sr) gr_prof, inc_prof, look_prof, b_prof = geosar.sr_to_geo(sr_prof, alt) look_prof = look_prof.reshape((1, look_prof.size)) sr_prof = sr_prof.reshape((1, look_prof.size)) dop_ref = 2 * v_orb * np.sin(look_prof) * np.sin(squint_r) / l0 print("skim_raw: Doppler Centroid is %f Hz" % (np.mean(dop_ref))) if cfg.srg.two_scale_Doppler: # We will compute less surface realizations n_pulses_b = utils.optimize_fftsize(int( cfg.srg.surface_coh_time * prf)) / 2 print("skim_raw: down-sampling rate =%i" % (n_pulses_b)) # n_pulses_b = 4 az_steps_ = int(np.ceil(az_steps / n_pulses_b)) t_step = t_step * n_pulses_b # Maximum length in azimuth that we can consider to have the same geometric Doppler dy_integ = cfg.srg.phase_err_tol / (2 * k0 * v_ground / min_sr * cfg.srg.surface_coh_time) surface_dy = surface.y[1] - surface.y[0] ny_integ = (dy_integ / surface.dy) print("skim_raw: ny_integ=%f" % (ny_integ)) if ny_integ < 1: ny_integ = 1 else: ny_integ = int(2**np.floor(np.log2(ny_integ))) info.msg("skim_raw: size of intermediate radar data: %f MB" % (8 * ny_integ * az_steps_ * rg_samp * 1e-6), importance=1) info.msg("skim_raw: ny_integ=%i" % (ny_integ), importance=1) if do_hh: proc_raw_hh = np.zeros( [az_steps_, int(surface.Ny / ny_integ), rg_samp], dtype=np.complex) proc_raw_hh_step = np.zeros([surface.Ny, rg_samp], dtype=np.complex) if do_vv: proc_raw_vv = np.zeros( [az_steps_, int(surface.Ny / ny_integ), rg_samp], dtype=np.complex) proc_raw_vv_step = np.zeros([surface.Ny, rg_samp], dtype=np.complex) # Doppler centroid # sin(a+da) = sin(a) + cos(a)*da - 1/2*sin(a)*da**2 az = surface.y.reshape((surface.Ny, 1)) # FIX-ME: this is a coarse approximation da = az / gr_prof sin_az = np.sin( squint_r) + np.cos(squint_r) * da - 0.5 * np.sin(squint_r) * da**2 dop0 = 2 * v_orb * np.sin(look_prof) * sin_az / l0 # az / 2 * sin_sr _az # az_now = (t_now - t_span / 2.) * v_ground * np.cos(squint_r) # az = np.repeat((surface.y - az_now)[:, np.newaxis], surface.Nx, axis=1) # az = (surface.y - az_now).reshape((surface.Ny, 1)) # print("Max az: %f" % (np.max(az))) #dop0 = np.mean(np.reshape(dop0, (surface.Ny/ny_integ, ny_integ, rg_samp)), axis=1) s_int = np.int(surface.Ny / ny_integ) dop0 = np.mean(np.reshape(dop0, (s_int, np.int(ny_integ), rg_samp)), axis=1) else: az_steps_ = az_steps if do_hh: proc_raw_hh = np.zeros([az_steps, rg_samp], dtype=np.complex) if do_vv: proc_raw_vv = np.zeros([az_steps, rg_samp], dtype=np.complex) t_last_rcs_bragg = -1. last_progress = -1 NRCS_avg_vv = np.zeros(az_steps, dtype=np.float) NRCS_avg_hh = np.zeros(az_steps, dtype=np.float) ## RCS MODELS # Specular if scat_spec_enable: if scat_spec_mode == 'kodis': rcs_spec = rcs.RCSKodis(inc, k0, surface.dx, surface.dy) elif scat_spec_mode == 'fa' or scat_spec_mode == 'spa': spec_ph0 = np.random.uniform(0., 2. * np.pi, size=[surface.Ny, surface.Nx]) rcs_spec = rcs.RCSKA(scat_spec_mode, k0, surface.x, surface.y, surface.dx, surface.dy) else: raise NotImplementedError( 'RCS mode %s for specular scattering not implemented' % scat_spec_mode) # Bragg if scat_bragg_enable: phase_bragg = np.zeros([2, surface.Ny, surface.Nx]) bragg_scats = np.zeros([2, surface.Ny, surface.Nx], dtype=np.complex) # dop_phase_p = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) # dop_phase_m = np.random.uniform(0., 2.*np.pi, size=[surface.Ny, surface.Nx]) tau_c = closure.grid_coherence(cfg.ocean.wind_U, surface.dx, f0) rndscat_p = closure.randomscat_ts(tau_c, (surface.Ny, surface.Nx), prf) rndscat_m = closure.randomscat_ts(tau_c, (surface.Ny, surface.Nx), prf) # NOTE: This ignores slope, may be changed k_b = 2. * k0 * sin_inc c_b = sin_inc * np.sqrt(const.g / k_b + 0.072e-3 * k_b) if scat_bragg_model == 'romeiser97': current_dir = np.deg2rad(cfg.ocean.current_dir) current_vec = (cfg.ocean.current_mag * np.array( [np.cos(current_dir), np.sin(current_dir)])) U_dir = np.deg2rad(cfg.ocean.wind_dir) U_vec = (cfg.ocean.wind_U * np.array([np.cos(U_dir), np.sin(U_dir)])) U_eff_vec = U_vec - current_vec rcs_bragg = rcs.RCSRomeiser97( k0, inc, pol, surface.dx, surface.dy, linalg.norm(U_eff_vec), np.arctan2(U_eff_vec[1], U_eff_vec[0]), surface.wind_fetch, scat_bragg_spec, scat_bragg_spread, scat_bragg_d) else: raise NotImplementedError( 'RCS model %s for Bragg scattering not implemented' % scat_bragg_model) surface_area = surface.dx * surface.dy * surface.Nx * surface.Ny ################### # SIMULATION LOOP # ################### if rank == 0: print('Computing profiles...') for az_step in np.arange(az_steps_, dtype=np.int): # AZIMUTH & SURFACE UPDATE t_now = az_step * t_step az_now = (t_now - t_span / 2.) * v_ground * np.cos(squint_r) # az = np.repeat((surface.y - az_now)[:, np.newaxis], surface.Nx, axis=1) az = (surface.y - az_now).reshape((surface.Ny, 1)) surface.t = t_now if az_step == 0: # Check wave-height info.msg( "Standard deviation of wave-height (peak-to-peak; i.e. x2): %f" % (2 * np.std(surface.Dz))) #if az_step == 0: # print("Max Dx: %f" % (np.max(surface.Dx))) # print("Max Dy: %f" % (np.max(surface.Dy))) # print("Max Dz: %f" % (np.max(surface.Dz))) # print("Max Diffx: %f" % (np.max(surface.Diffx))) # print("Max Diffy: %f" % (np.max(surface.Diffy))) # print("Max Diffxx: %f" % (np.max(surface.Diffxx))) # print("Max Diffyy: %f" % (np.max(surface.Diffyy))) # print("Max Diffxy: %f" % (np.max(surface.Diffxy))) # COMPUTE RCS FOR EACH MODEL # Note: SAR processing is range independent as slant range is fixed sin_az = az / sr az_proj_angle = np.arcsin(az / gr0) # Note: Projected displacements are added to slant range if point_target_floats is False: # This can only happen if point targets are enabled surface.Dx[int(surface.Ny / 2), int(surface.Nx / 2)] = 0 surface.Dy[int(surface.Ny / 2), int(surface.Nx / 2)] = 0 surface.Dz[int(surface.Ny / 2), int(surface.Nx / 2)] = 0 if cfg.srg.two_scale_Doppler: # slant-range for phase sr_surface = (sr - cos_inc * surface.Dz + surface.Dx * sin_inc + surface.Dy * sin_az) if cfg.srg.rcm: # add non common rcm sr_surface4rcm = sr_surface + az / 2 * sin_az else: sr_surface4rcm = sr_surface else: # FIXME: check if global shift is included, in case we care about slow simulations # slant-range for phase and Doppler sr_surface = (sr - cos_inc * surface.Dz + az / 2 * sin_az + surface.Dx * sin_inc + surface.Dy * sin_az) sr_surface4rcm = sr_surface if do_hh: scene_hh = np.zeros( [int(surface.Ny), int(surface.Nx)], dtype=np.complex) if do_vv: scene_vv = np.zeros( [int(surface.Ny), int(surface.Nx)], dtype=np.complex) # Specular if scat_spec_enable: if scat_spec_mode == 'kodis': Esn_sp = np.sqrt(4. * np.pi) * rcs_spec.field( az_proj_angle, sr_surface, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy) if do_hh: scene_hh += Esn_sp if do_vv: scene_vv += Esn_sp else: # FIXME if do_hh: pol_tmp = 'hh' Esn_sp = ( np.exp(-1j * (2. * k0 * sr_surface)) * (4. * np.pi)**1.5 * rcs_spec.field( 1, 1, pol_tmp[0], pol_tmp[1], inc, inc, az_proj_angle, az_proj_angle + np.pi, surface.Dz, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy)) scene_hh += Esn_sp if do_vv: pol_tmp = 'vv' Esn_sp = ( np.exp(-1j * (2. * k0 * sr_surface)) * (4. * np.pi)**1.5 * rcs_spec.field( 1, 1, pol_tmp[0], pol_tmp[1], inc, inc, az_proj_angle, az_proj_angle + np.pi, surface.Dz, surface.Diffx, surface.Diffy, surface.Diffxx, surface.Diffyy, surface.Diffxy)) scene_vv += Esn_sp NRCS_avg_hh[az_step] += (np.sum(np.abs(Esn_sp)**2) / surface_area) NRCS_avg_vv[az_step] += NRCS_avg_hh[az_step] # Bragg if scat_bragg_enable: if (t_now - t_last_rcs_bragg) > ocean_dt: if scat_bragg_model == 'romeiser97': if pol == 'DP': RCS_bragg_hh, RCS_bragg_vv = rcs_bragg.rcs( az_proj_angle, surface.Diffx, surface.Diffy) elif pol == 'hh': RCS_bragg_hh = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) else: RCS_bragg_vv = rcs_bragg.rcs(az_proj_angle, surface.Diffx, surface.Diffy) if use_hmtf: # Fix Bad MTF points surface.hMTF[np.where(surface.hMTF < -1)] = -1 if do_hh: RCS_bragg_hh[0] *= (1 + surface.hMTF) RCS_bragg_hh[1] *= (1 + surface.hMTF) if do_vv: RCS_bragg_vv[0] *= (1 + surface.hMTF) RCS_bragg_vv[1] *= (1 + surface.hMTF) t_last_rcs_bragg = t_now if do_hh: scat_bragg_hh = np.sqrt(RCS_bragg_hh) NRCS_bragg_hh_instant_avg = np.sum(RCS_bragg_hh) / surface_area NRCS_avg_hh[az_step] += NRCS_bragg_hh_instant_avg if do_vv: scat_bragg_vv = np.sqrt(RCS_bragg_vv) NRCS_bragg_vv_instant_avg = np.sum(RCS_bragg_vv) / surface_area NRCS_avg_vv[az_step] += NRCS_bragg_vv_instant_avg # Doppler phases (Note: Bragg radial velocity taken constant!) surf_phase = -(2 * k0) * sr_surface cap_phase = (2 * k0) * t_step * c_b * (az_step + 1) phase_bragg[0] = surf_phase - cap_phase # + dop_phase_p phase_bragg[1] = surf_phase + cap_phase # + dop_phase_m bragg_scats[0] = rndscat_m.scats(t_now) bragg_scats[1] = rndscat_p.scats(t_now) if do_hh: scene_hh += ne.evaluate( 'sum(scat_bragg_hh * exp(1j*phase_bragg) * bragg_scats, axis=0)' ) if do_vv: scene_vv += ne.evaluate( 'sum(scat_bragg_vv * exp(1j*phase_bragg) * bragg_scats, axis=0)' ) if add_point_target: # Now we replace scattering at center by fixed value pt_y = int(surface.Ny / 2) pt_x = int(surface.Nx / 2) if do_hh: scene_hh[pt_y, pt_x] = 1000 * np.exp( -1j * 2 * k0 * sr_surface[pt_y, pt_x]) if do_vv: scene_vv[pt_y, pt_x] = 1000 * np.exp( -1j * 2 * k0 * sr_surface[pt_y, pt_x]) ## ANTENNA PATTERN ## FIXME: this assume co-located Tx and Tx, so it will not work for true bistatic configurations if cfg.radar.L_total: beam_pattern = sinc_1tx_nrx(sin_az, ant_L * num_ch, f0, num_ch, field=True) else: beam_pattern = sinc_1tx_nrx(sin_az, ant_L, f0, 1, field=True) # GENERATE CHANEL PROFILES if cfg.srg.two_scale_Doppler: sr_surface_ = sr_surface4rcm if do_hh: proc_raw_hh_step[:, :] = 0 proc_raw_hh_ = proc_raw_hh_step scene_bp_hh = scene_hh * beam_pattern if do_vv: proc_raw_vv_step[:, :] = 0 proc_raw_vv_ = proc_raw_vv_step scene_bp_vv = scene_vv * beam_pattern else: sr_surface_ = sr_surface4rcm.flatten() if do_hh: proc_raw_hh_ = proc_raw_hh[az_step] scene_bp_hh = (scene_hh * beam_pattern).flatten() if do_vv: proc_raw_vv_ = proc_raw_vv[az_step] scene_bp_vv = (scene_vv * beam_pattern).flatten() if do_hh: raw.chan_profile_numba(sr_surface_, scene_bp_hh, sr_smp, sr_prof.min(), chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_hh_, rg_only=cfg.srg.two_scale_Doppler) if do_vv: raw.chan_profile_numba(sr_surface_, scene_bp_vv, sr_smp, sr_prof.min(), chan_sinc_vec, n_sinc_samples, sinc_ovs, proc_raw_vv_, rg_only=cfg.srg.two_scale_Doppler) if cfg.srg.two_scale_Doppler: #Integrate in azimuth s_int = np.int(surface.Ny / ny_integ) if do_hh: proc_raw_hh[az_step] = np.sum(np.reshape( proc_raw_hh_, (s_int, ny_integ, rg_samp)), axis=1) info.msg("Max abs(HH): %f" % np.max(np.abs(proc_raw_hh[az_step])), importance=1) if do_vv: #print(proc_raw_vv.shape) proc_raw_vv[az_step] = np.sum(np.reshape( proc_raw_vv_, (s_int, ny_integ, rg_samp)), axis=1) info.msg("Max abs(VV): %f" % np.max(np.abs(proc_raw_vv[az_step])), importance=1) # SHOW PROGRESS (%) current_progress = np.int((100 * az_step) / az_steps_) if current_progress != last_progress: last_progress = current_progress info.msg('SP,%d,%d,%d%%' % (rank, size, current_progress), importance=1) if cfg.srg.two_scale_Doppler: # No we have to up-sample and add Doppler info.msg("skim_raw: Dopplerizing and upsampling") print(dop0.max()) print(n_pulses_b) print(prf) if do_hh: proc_raw_hh = upsample_and_dopplerize(proc_raw_hh, dop0, n_pulses_b, prf) if do_vv: proc_raw_vv = upsample_and_dopplerize(proc_raw_vv, dop0, n_pulses_b, prf) # MERGE RESULTS if do_hh: total_raw_hh = np.empty_like(proc_raw_hh) if rank == 0 else None comm.Reduce(proc_raw_hh, total_raw_hh, op=MPI.SUM, root=0) if do_vv: total_raw_vv = np.empty_like(proc_raw_vv) if rank == 0 else None comm.Reduce(proc_raw_vv, total_raw_vv, op=MPI.SUM, root=0) ## PROCESS REDUCED RAW DATA & SAVE (ROOT) if rank == 0: info.msg('calibrating and saving results...') # Filter and decimate #range_filter = np.ones_like(total_raw) #range_filter[:, :, rg_samp/(2*2*cfg.radar.over_fs):-rg_samp/(2*2*cfg.radar.over_fs)] = 0 #total_raw = np.fft.ifft(range_filter*np.fft.fft(total_raw)) if do_hh: total_raw_hh = total_raw_hh[:, :cfg.radar.n_rg] if do_vv: total_raw_vv = total_raw_vv[:, :cfg.radar.n_rg] # Calibration factor (projected antenna pattern integrated in azimuth) az_axis = np.arange(-t_span / 2. * v_ground, t_span / 2. * v_ground, sr0 * const.c / (np.pi * f0 * ant_L * 10.)) if cfg.radar.L_total: pattern = sinc_1tx_nrx(az_axis / sr0, ant_L * num_ch, f0, num_ch, field=True) else: pattern = sinc_1tx_nrx(az_axis / sr0, ant_L, f0, 1, field=True) cal_factor = (1. / np.sqrt( np.trapz(np.abs(pattern)**2., az_axis) * sr_res / np.sin(inc_angle))) if do_hh: noise = (utils.db2lin(nesz, amplitude=True) / np.sqrt(2.) * (np.random.normal(size=total_raw_hh.shape) + 1j * np.random.normal(size=total_raw_hh.shape))) total_raw_hh = total_raw_hh * cal_factor + noise if do_vv: noise = (utils.db2lin(nesz, amplitude=True) / np.sqrt(2.) * (np.random.normal(size=total_raw_vv.shape) + 1j * np.random.normal(size=total_raw_vv.shape))) total_raw_vv = total_raw_vv * cal_factor + noise # Add slow-time error # if use_errors: # if do_hh: # total_raw_hh *= errors.beta_noise # if do_vv: # total_raw_vv *= errors.beta_noise # Save RAW data if do_hh and do_vv: rshp = (1, ) + total_raw_hh.shape total_raw = np.concatenate( (total_raw_hh.reshape(rshp), total_raw_vv.reshape(rshp))) rshp = (1, ) + NRCS_avg_hh.shape NRCS_avg = np.concatenate( (NRCS_avg_hh.reshape(rshp), NRCS_avg_vv.reshape(rshp))) elif do_hh: rshp = (1, ) + total_raw_hh.shape total_raw = total_raw_hh.reshape(rshp) rshp = (1, ) + NRCS_avg_hh.shape NRCS_avg = NRCS_avg_hh.reshape(rshp) else: rshp = (1, ) + total_raw_vv.shape total_raw = total_raw_vv.reshape(rshp) rshp = (1, ) + NRCS_avg_vv.shape NRCS_avg = NRCS_avg_vv.reshape(rshp) raw_file = tpio.SkimRawFile(output_file, 'w', total_raw.shape) raw_file.set('inc_angle', np.rad2deg(inc_angle)) raw_file.set('f0', f0) # raw_file.set('num_ch', num_ch) raw_file.set('ant_L', ant_L) raw_file.set('prf', prf) raw_file.set('v_ground', v_ground) raw_file.set('orbit_alt', alt) raw_file.set('sr0', sr0) raw_file.set('rg_sampling', rg_bw * over_fs) raw_file.set('rg_bw', rg_bw) raw_file.set('raw_data*', total_raw) raw_file.set('NRCS_avg', NRCS_avg) raw_file.set('azimuth', cfg.radar.azimuth) raw_file.set('dop_ref', dop_ref) raw_file.close() print(time.strftime("Finished [%Y-%m-%d %H:%M:%S]", time.localtime()))
def init(self, Lx, Ly, dx, dy, cutoff_wl, spec_model, spread_model, wind_dir, wind_fetch, wind_U, current_mag, current_dir, swell_enable=False, swell_ampl=0., swell_dir=0., swell_wl=0., compute=[], opt_res=True, fft_max_prime=2, choppy_enable=False, dirspectrum_func=None, depth=None): """ Initialize surface with parameters :param Lx: Scene X size (m) :param Ly: Scene Y size (m) :param dx: Scene X resolution (m) :param dy: Scene Y resolution (m) :param cutoff_wl: Spectrum wavelength cut-off (m) - None/'auto' to set it automatically :param spec_model: Omnidirectional Spectrum model :param spread_model: Spreading function model :param wind_dir: Wind direction (rad) :param wind_fetch: Wind fetch (m) :param wind_U: Wind speed (m/s) :param current_mag: Current magnitude :param current_dir: Current direction (rad) :param swell_enable: EN/DIS Swell :param swell_ampl: Swell amplitude (m) :param swell_dir: Swell direction (rad) :param swell_wl: Swell peak wavelength (m) :param compute: List with values to compute - 'D': EN/DIS Computation of Wavefield (Dx,Dy,Dz) - 'Diff': EN/DIS Computation of space 1st derivatives (slopes) - 'Diff2': EN/DIS Computation of space 2nd derivatives - 'V': EN/DIS Computation of time 1st derivative (velocities) - 'A': EN/DIS Computation of time 2nd derivative (accelerations) - 'hMTF': EN/DIS Computation of Hydrodynamic MTF :param opt_res: Automatically adjust resolution to have optimal matrix sizes :param fft_max_prime: Maximum prime factor allowed in matrix sizes :param choppy_enable: EN/DIS Choppy waves :param dirspectrum_func: optional external directional wavespectrum """ ## INITIALIZE CLASS VARIABLES # Save surface properties self.Lx = Lx self.Ly = Ly self.dx = dx self.dy = dy self.wind_dir = wind_dir self.wind_fetch = wind_fetch self.wind_U = wind_U self.current_mag = current_mag self.current_dir = current_dir self.swell_enable = swell_enable self.swell_ampl = swell_ampl self.swell_dir = swell_dir self.swell_wl = swell_wl self.compute = compute self.choppy_enable = choppy_enable ## INITIALIZE MESHGRIDS, SPECTRUM, ETC. # Grid dimensions self.Nx = np.int(self.Lx / self.dx) self.Ny = np.int(self.Ly / self.dy) if opt_res: self.Nx = np.int(utils.optimize_fftsize(self.Nx, fft_max_prime)) self.Ny = np.int(utils.optimize_fftsize(self.Ny, fft_max_prime)) self.dx = self.Lx / np.float(self.Nx) self.dy = self.Ly / np.float(self.Ny) # X-Y vector self.x = np.linspace(-self.Lx / 2., self.Lx / 2., self.Nx) self.y = np.linspace(-self.Ly / 2., self.Ly / 2., self.Ny) # Currents self.current = self.current_mag * np.array( [np.cos(self.current_dir), np.sin(self.current_dir)]) U_eff_vec = (self.wind_U * np.array([np.cos(self.wind_dir), np.sin(self.wind_dir)]) - self.current) self.wind_U_eff = linalg.norm(U_eff_vec) self.wind_dir_eff = np.arctan2(U_eff_vec[1], U_eff_vec[0]) # Maximum Kx, Ky (Sampling theorem, 2*pi/(2*res)) kmax_x = np.pi / self.dx kmax_y = np.pi / self.dy # Kx-Ky meshgrid (0:N/2, -N/2:-1) #kx_o = np.linspace(-kmax_x, kmax_x, self.Nx) kx_s = 2 * np.pi * np.fft.fftfreq(self.Nx, self.dx) #ky_o = np.linspace(-kmax_y, kmax_y, self.Ny) ky_s = 2 * np.pi * np.fft.fftfreq(self.Ny, self.dy) self.kx, self.ky = np.meshgrid(kx_s, ky_s) # Kx-Ky resolution kx_res = self.kx[0, 1] - self.kx[0, 0] ky_res = self.ky[1, 0] - self.ky[0, 0] # K-theta meshgrid (Polar, wind direction shifted) self.k = np.sqrt(self.kx**2 + self.ky**2) good_k = np.where(self.k > np.min(np.array([kx_res, ky_res])) / 2.0) self.kxn = np.zeros_like(self.kx) self.kyn = np.zeros_like(self.kx) self.kxn[good_k] = self.kx[good_k] / self.k[good_k] self.kyn[good_k] = self.ky[good_k] / self.k[good_k] self.kinv = np.zeros(self.k.shape) self.kinv[good_k] = 1. / self.k[good_k] #self.theta = np.arctan2(self.ky, self.kx) - self.wind_dir_eff self.theta = np.angle( np.exp(1j * (np.arctan2(self.ky, self.kx) - self.wind_dir_eff))) # omega (Deep water: w(k)^2 = g*k) if depth is None: self.omega = np.sqrt(const.g * self.k) else: self.omega = np.sqrt(const.g * self.k * np.tanh(self.k * depth)) # Compute directional wave spectrum (1/k*S(k)*D(k,theta)) if callable(dirspectrum_func): self.wave_dirspec = np.zeros(self.k.shape) self.wave_dirspec[good_k] = dirspectrum_func( self.kx[good_k], self.ky[good_k]) else: if spec_model not in spec.models: raise NotImplementedError( '%s spectrum function not implemented' % spec_model) if spread_model not in spread.models: raise NotImplementedError( '%s spreading function not implemented' % spread_model) wave_spec = np.zeros(self.k.shape) wave_spec[good_k] = spec.models[spec_model](self.k[good_k], self.wind_U_eff, self.wind_fetch) wave_spread = np.zeros(self.k.shape) wave_spread[good_k] = spread.models[spread_model]( self.k[good_k], self.theta[good_k], self.wind_U_eff, self.wind_fetch) self.wave_dirspec = (self.kinv) * wave_spec * wave_spread # Filter if cutoff is imposed if cutoff_wl and (cutoff_wl != 'auto'): kco_x = 2. * np.pi / cutoff_wl kco_y = 2. * np.pi / cutoff_wl if (kco_x > np.pi / self.dx) or (kco_y > np.pi / self.dy): raise ValueError( 'Cutoff wavelength is too small for the specified grid resolution' ) k_f = np.zeros([self.Ny, self.Nx]) ky_sample = np.ceil((self.Ny / 2) * kco_y / kmax_y) kx_sample = np.ceil((self.Nx / 2) * kco_x / kmax_x) k_f[(k_f.shape[0] / 2 - ky_sample):(k_f.shape[0] / 2 + ky_sample), (k_f.shape[1] / 2 - kx_sample):(k_f.shape[1] / 2 + kx_sample)] = 1. self.wave_dirspec *= np.fft.fftshift(k_f) # Complex Gaussian to randomize spectrum coefficients random_cg = 1. / np.sqrt(2.) * ( np.random.normal(0., 1., size=[self.Ny, self.Nx]) + 1j * np.random.normal(0., 1., size=[self.Ny, self.Nx])) # Swell spectrum (monochromatic) if self.swell_enable: # Swell K, Kx, Ky, omega x, y = np.meshgrid(self.x, self.y) self.swell_k = 2. * np.pi / self.swell_wl self.swell_kx = self.swell_k * np.cos(self.swell_dir) self.swell_ky = self.swell_k * np.sin(self.swell_dir) if depth is None: self.swell_omega = np.sqrt(self.swell_k * const.g) else: self.swell_omega = np.sqrt(self.swell_k * const.g * np.tanh(self.swell_k * depth)) # Swell initial phase (random) self.swell_ph0 = np.random.uniform(0., 2. * np.pi) # Swell in complex domain (monochromatic) self.swell_exp = self.swell_ampl * np.exp( 1j * (self.swell_k * (np.cos(self.swell_dir) * x + np.sin(self.swell_dir) * y) + self.swell_ph0)) # Initialize coefficients self.wave_coefs = self.Nx * self.Ny * np.sqrt( 2. * self.wave_dirspec * kx_res * ky_res) * random_cg # Allocate memory & mark as initialized self.__allocate() self.initialized = True
def sar_focus(cfg_file, raw_output_file, output_file): ################### # INITIALIZATIONS # ################### print( '-------------------------------------------------------------------') print( time.strftime("- OCEANSAR SAR Processor: %Y-%m-%d %H:%M:%S", time.localtime())) print( '-------------------------------------------------------------------') ## CONFIGURATION FILE cfg = tpio.ConfigFile(cfg_file) # PROCESSING az_weighting = cfg.processing.az_weighting doppler_bw = cfg.processing.doppler_bw plot_format = cfg.processing.plot_format plot_tex = cfg.processing.plot_tex plot_save = cfg.processing.plot_save plot_path = cfg.processing.plot_path plot_raw = cfg.processing.plot_raw plot_rcmc_dopp = cfg.processing.plot_rcmc_dopp plot_rcmc_time = cfg.processing.plot_rcmc_time plot_image_valid = cfg.processing.plot_image_valid # SAR f0 = cfg.sar.f0 prf = cfg.sar.prf num_ch = cfg.sar.num_ch alt = cfg.sar.alt v_ground = cfg.sar.v_ground rg_bw = cfg.sar.rg_bw over_fs = cfg.sar.over_fs ## CALCULATE PARAMETERS l0 = const.c / f0 if v_ground == 'auto': v_ground = geo.orbit_to_vel(alt, ground=True) rg_sampling = rg_bw * over_fs ## RAW DATA raw_file = tpio.RawFile(raw_output_file, 'r') raw_data = raw_file.get('raw_data*') sr0 = raw_file.get('sr0') raw_file.close() ## OTHER INITIALIZATIONS # Create plots directory plot_path = os.path.dirname(output_file) + os.sep + plot_path if plot_save: if not os.path.exists(plot_path): os.makedirs(plot_path) slc = [] ######################## # PROCESSING MAIN LOOP # ######################## for ch in np.arange(num_ch): if plot_raw: utils.image(np.real(raw_data[0, ch]), min=-np.max(np.abs(raw_data[0, ch])), max=np.max(np.abs(raw_data[0, ch])), cmap='gray', aspect=np.float(raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_raw_real_%d.%s' % (ch, plot_format), dpi=150) utils.image(np.imag(raw_data[0, ch]), min=-np.max(np.abs(raw_data[0, ch])), max=np.max(np.abs(raw_data[0, ch])), cmap='gray', aspect=np.float(raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_raw_imag_%d.%s' % (ch, plot_format), dpi=150) utils.image(np.abs(raw_data[0, ch]), min=0, max=np.max(np.abs(raw_data[0, ch])), cmap='gray', aspect=np.float(raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_raw_amp_%d.%s' % (ch, plot_format), dpi=150) utils.image(np.angle(raw_data[0, ch]), min=-np.pi, max=np.pi, cmap='gray', aspect=np.float(raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_raw_phase_%d.%s' % (ch, plot_format), dpi=150) # Optimize matrix sizes az_size_orig, rg_size_orig = raw_data[0, ch].shape optsize = utils.optimize_fftsize(raw_data[0, ch].shape) optsize = [raw_data.shape[0], optsize[0], optsize[1]] data = np.zeros(optsize, dtype=complex) data[:, :raw_data[0, ch].shape[0], :raw_data[ 0, ch].shape[1]] = raw_data[:, ch, :, :] az_size, rg_size = data.shape[1:] # RCMC Correction print('Applying RCMC correction... [Channel %d/%d]' % (ch + 1, num_ch)) #fr = np.linspace(-rg_sampling/2., rg_sampling/2., rg_size) fr = (np.arange(rg_size) - rg_size / 2) * rg_sampling / rg_size fr = np.roll(fr, int(-rg_size / 2)) fa = (np.arange(az_size) - az_size / 2) * prf / az_size fa = np.roll(fa, int(-az_size / 2)) #fa[az_size/2:] = fa[az_size/2:] - prf rcmc_fa = sr0 / np.sqrt(1 - (fa * (l0 / 2.) / v_ground)**2.) - sr0 data = np.fft.fft2(data) # for i in np.arange(az_size): # data[i,:] *= np.exp(1j*2*np.pi*2*rcmc_fa[i]/const.c*fr) data = (data * np.exp(4j * np.pi * rcmc_fa.reshape( (1, az_size, 1)) / const.c * fr.reshape((1, 1, rg_size)))) data = np.fft.ifft(data, axis=2) if plot_rcmc_dopp: utils.image(np.abs(data[0]), min=0., max=3. * np.mean(np.abs(data)), cmap='gray', aspect=np.float(rg_size) / np.float(az_size), title='RCMC Data (Range Dopler Domain)', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_rcmc_dopp_%d.%s' % (ch, plot_format)) if plot_rcmc_time: rcmc_time = np.fft.ifft(data[0], axis=0)[:az_size_orig, :rg_size_orig] rcmc_time_max = np.max(np.abs(rcmc_time)) utils.image(np.real(rcmc_time), min=-rcmc_time_max, max=rcmc_time_max, cmap='gray', aspect=np.float(rg_size) / np.float(az_size), title='RCMC Data (Time Domain)', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_rcmc_time_real_%d.%s' % (ch, plot_format)) utils.image(np.imag(rcmc_time), min=-rcmc_time_max, max=rcmc_time_max, cmap='gray', aspect=np.float(rg_size) / np.float(az_size), title='RCMC Data (Time Domain)', usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'plot_rcmc_time_imag_%d.%s' % (ch, plot_format)) # Azimuth compression print('Applying azimuth compression... [Channel %d/%d]' % (ch + 1, num_ch)) n_samp = 2 * (np.int(doppler_bw / (fa[1] - fa[0])) / 2) weighting = az_weighting - (1. - az_weighting) * np.cos( 2 * np.pi * np.linspace(0, 1., n_samp)) # Compensate amplitude loss L_win = np.sum(np.abs(weighting)**2) / weighting.size weighting /= np.sqrt(L_win) if fa.size > n_samp: zeros = np.zeros(az_size) zeros[0:n_samp] = weighting #zeros[:n_samp/2] = weighting[:n_samp/2] #zeros[-n_samp/2:] = weighting[-n_samp/2:] weighting = np.roll(zeros, int(-n_samp / 2)) ph_ac = 4. * np.pi / l0 * sr0 * ( np.sqrt(1. - (fa * l0 / 2. / v_ground)**2.) - 1.) # for i in np.arange(rg_size): # data[:,i] *= np.exp(1j*ph_ac)*weighting data = data * (np.exp(1j * ph_ac) * weighting).reshape((1, az_size, 1)) data = np.fft.ifft(data, axis=1) print('Finishing... [Channel %d/%d]' % (ch + 1, num_ch)) # Reduce to initial dimension data = data[:, :az_size_orig, :rg_size_orig] # Removal of non valid samples n_val_az_2 = np.floor(doppler_bw / 2. / (2. * v_ground**2. / l0 / sr0) * prf / 2.) * 2. # data = raw_data[ch, n_val_az_2:(az_size_orig - n_val_az_2 - 1), :] data = data[:, n_val_az_2:(az_size_orig - n_val_az_2 - 1), :] if plot_image_valid: plt.figure() plt.imshow(np.abs(data[0]), origin='lower', vmin=0, vmax=np.max(np.abs(data)), aspect=np.float(rg_size_orig) / np.float(az_size_orig), cmap='gray') plt.xlabel("Range") plt.ylabel("Azimuth") plt.savefig( os.path.join(plot_path, ('plot_image_valid_%d.%s' % (ch, plot_format)))) slc.append(data) # Save processed data slc = np.array(slc, dtype=np.complex) print("Shape of SLC: " + str(slc.shape), flush=True) proc_file = tpio.ProcFile(output_file, 'w', slc.shape) proc_file.set('slc*', slc) proc_file.close() print('-----------------------------------------') print( time.strftime("Processing finished [%Y-%m-%d %H:%M:%S]", time.localtime())) print('-----------------------------------------')
def sar_focus(cfg_file, raw_output_file, output_file): ################### # INITIALIZATIONS # ################### print( '-------------------------------------------------------------------') print( time.strftime("- OCEANSAR SAR Processor: %Y-%m-%d %H:%M:%S", time.localtime())) print( '-------------------------------------------------------------------') # CONFIGURATION FILE cfg = tpio.ConfigFile(cfg_file) # PROCESSING az_weighting = cfg.processing.az_weighting doppler_bw = cfg.processing.doppler_bw plot_format = cfg.processing.plot_format plot_tex = cfg.processing.plot_tex plot_save = cfg.processing.plot_save plot_path = cfg.processing.plot_path plot_raw = cfg.processing.plot_raw plot_rcmc_dopp = cfg.processing.plot_rcmc_dopp plot_rcmc_time = cfg.processing.plot_rcmc_time plot_image_valid = cfg.processing.plot_image_valid # SAR f0 = cfg.sar.f0 prf = cfg.sar.prf num_ch = cfg.sar.num_ch alt = cfg.sar.alt v_ground = cfg.sar.v_ground rg_bw = cfg.sar.rg_bw over_fs = cfg.sar.over_fs # CALCULATE PARAMETERS l0 = const.c / f0 if v_ground == 'auto': v_ground = geo.orbit_to_vel(alt, ground=True) rg_sampling = rg_bw * over_fs # RAW DATA raw_file = tpio.RawFile(raw_output_file, 'r') raw_data = raw_file.get('raw_data*') sr0 = raw_file.get('sr0') inc_angle = raw_file.get('inc_angle') b_ati = raw_file.get('b_ati') b_xti = raw_file.get('b_xti') raw_file.close() # OTHER INITIALIZATIONS # Create plots directory plot_path = os.path.dirname(output_file) + os.sep + plot_path if plot_save: if not os.path.exists(plot_path): os.makedirs(plot_path) slc = [] ######################## # PROCESSING MAIN LOOP # ######################## for ch in np.arange(num_ch): if plot_raw: plt.figure() plt.imshow(np.real(raw_data[0, ch]), vmin=-np.max(np.abs(raw_data[0, ch])), vmax=np.max(np.abs(raw_data[0, ch])), cmap='gray') plt.savefig(plot_path + os.sep + ('plot_raw_real_%d.%s' % (ch, plot_format))) plt.close() # utils.image(np.real(raw_data[0, ch]), min=-np.max(np.abs(raw_data[0, ch])), max=np.max(np.abs(raw_data[0, ch])), cmap='gray', # aspect=np.float( # raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), # title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', # usetex=plot_tex, # save=plot_save, save_path=plot_path + os.sep + # 'plot_raw_real_%d.%s' % (ch, plot_format), # dpi=150) # utils.image(np.imag(raw_data[0, ch]), min=-np.max(np.abs(raw_data[0, ch])), max=np.max(np.abs(raw_data[0, ch])), cmap='gray', # aspect=np.float( # raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), # title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', # usetex=plot_tex, # save=plot_save, save_path=plot_path + os.sep + # 'plot_raw_imag_%d.%s' % (ch, plot_format), # dpi=150) # utils.image(np.abs(raw_data[0, ch]), min=0, max=np.max(np.abs(raw_data[0, ch])), cmap='gray', # aspect=np.float( # raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), # title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', # usetex=plot_tex, # save=plot_save, save_path=plot_path + os.sep + # 'plot_raw_amp_%d.%s' % (ch, plot_format), # dpi=150) # utils.image(np.angle(raw_data[0, ch]), min=-np.pi, max=np.pi, cmap='gray', # aspect=np.float( # raw_data[0, ch].shape[1]) / np.float(raw_data[0, ch].shape[0]), # title='Raw Data', xlabel='Range samples', ylabel='Azimuth samples', # usetex=plot_tex, save=plot_save, # save_path=plot_path + os.sep + # 'plot_raw_phase_%d.%s' % (ch, plot_format), # dpi=150) # Optimize matrix sizes az_size_orig, rg_size_orig = raw_data[0, ch].shape optsize = utils.optimize_fftsize(raw_data[0, ch].shape) optsize = [raw_data.shape[0], optsize[0], optsize[1]] data = np.zeros(optsize, dtype=complex) data[:, :raw_data[0, ch].shape[0], :raw_data[ 0, ch].shape[1]] = raw_data[:, ch, :, :] az_size, rg_size = data.shape[1:] # RCMC Correction print('Applying RCMC correction... [Channel %d/%d]' % (ch + 1, num_ch)) # fr = np.linspace(-rg_sampling/2., rg_sampling/2., rg_size) # fr = (np.arange(rg_size) - rg_size / 2) * rg_sampling / rg_size # fr = np.roll(fr, int(-rg_size / 2)) fr = np.fft.fftfreq(rg_size, 1 / rg_sampling) # fa = (np.arange(az_size) - az_size / 2) * prf / az_size # fa = np.roll(fa, int(-az_size / 2)) fa = np.fft.fftfreq(az_size, 1 / prf) ## Compensation of ANTENNA PATTERN ## FIXME this will not work for a long separation betwen Tx and Rx!!! sin_az = fa * l0 / (2 * v_ground) if hasattr(cfg.sar, 'ant_L'): ant_L = cfg.sar.ant_L if cfg.sar.L_total: beam_pattern = sinc_1tx_nrx(sin_az, ant_L * num_ch, f0, num_ch, field=True) else: beam_pattern = sinc_1tx_nrx(sin_az, ant_L, f0, 1, field=True) else: ant_l_tx = cfg.sar.ant_L_tx ant_l_rx = cfg.sar.ant_L_rx beam_pattern = (sinc_bp(sin_az, ant_l_tx, f0, field=True) * sinc_bp(sin_az, ant_l_rx, f0, field=True)) #fa[az_size/2:] = fa[az_size/2:] - prf rcmc_fa = sr0 / np.sqrt(1 - (fa * (l0 / 2.) / v_ground)**2.) - sr0 data = np.fft.fft(np.fft.fft(data, axis=-1), axis=-2) # for i in np.arange(az_size): # data[i,:] *= np.exp(1j*2*np.pi*2*rcmc_fa[i]/const.c*fr) data = (data * np.exp(4j * np.pi * rcmc_fa.reshape( (1, az_size, 1)) / const.c * fr.reshape((1, 1, rg_size)))) data = np.fft.ifft(data, axis=2) if plot_rcmc_dopp: plt.figure() plt.imshow(np.fft.fftshift(np.abs(data[0]), axes=0), vmax=np.max(np.abs(data)), cmap='gray', origin='lower') plt.savefig(plot_path + os.sep + ('plot_rcmc_dopp_%d.%s' % (ch, plot_format))) if plot_rcmc_time: rcmc_time = np.fft.ifft(data[0], axis=0)[:az_size_orig, :rg_size_orig] rcmc_time_max = np.max(np.abs(rcmc_time)) plt.figure() plt.imshow(np.real(rcmc_time), vmin=-rcmc_time_max, vmax=rcmc_time_max, cmap='gray', origin='lower') plt.savefig(plot_path + os.sep + ('plot_rcmc_time_real_%d.%s' % (ch, plot_format))) # Azimuth compression print('Applying azimuth compression... [Channel %d/%d]' % (ch + 1, num_ch)) n_samp = 2 * (np.int(doppler_bw / (fa[1] - fa[0])) / 2) weighting = (az_weighting - (1. - az_weighting) * np.cos(2 * np.pi * np.linspace(0, 1., int(n_samp)))) # Compensate amplitude loss L_win = np.sum(np.abs(weighting)**2) / weighting.size weighting /= np.sqrt(L_win) if fa.size > n_samp: zeros = np.zeros(az_size) zeros[0:int(n_samp)] = weighting # zeros[:n_samp/2] = weighting[:n_samp/2] # zeros[-n_samp/2:] = weighting[-n_samp/2:] weighting = np.roll(zeros, int(-n_samp / 2)) weighting = np.where( np.abs(beam_pattern) > 0, weighting / beam_pattern, 0) ph_ac = 4. * np.pi / l0 * sr0 * \ (np.sqrt(1. - (fa * l0 / 2. / v_ground)**2.) - 1.) # for i in np.arange(rg_size): # data[:,i] *= np.exp(1j*ph_ac)*weighting data = data * (np.exp(1j * ph_ac) * weighting).reshape((1, az_size, 1)) data = np.fft.ifft(data, axis=1) print('Finishing... [Channel %d/%d]' % (ch + 1, num_ch)) # Reduce to initial dimension data = data[:, :int(az_size_orig), :int(rg_size_orig)] # Removal of non valid samples n_val_az_2 = np.floor(doppler_bw / 2. / (2. * v_ground**2. / l0 / sr0) * prf / 2.) * 2. # data = raw_data[ch, n_val_az_2:(az_size_orig - n_val_az_2 - 1), :] data = data[:, int(n_val_az_2):int(az_size_orig - n_val_az_2 - 1), :] if plot_image_valid: plt.figure() plt.imshow(np.abs(data[0]), origin='lower', vmin=0, vmax=np.max(np.abs(data)), aspect=np.float(rg_size_orig) / np.float(az_size_orig), cmap='gray') plt.xlabel("Range") plt.ylabel("Azimuth") plt.savefig( os.path.join(plot_path, ('plot_image_valid_%d.%s' % (ch, plot_format)))) slc.append(data) # Save processed data slc = np.array(slc, dtype=np.complex) print("Shape of SLC: " + str(slc.shape), flush=True) proc_file = tpio.ProcFile(output_file, 'w', slc.shape) proc_file.set('slc*', slc) proc_file.set('inc_angle', inc_angle) proc_file.set('f0', f0) proc_file.set('num_ch', num_ch) proc_file.set('ant_L', ant_l_tx) proc_file.set('prf', prf) proc_file.set('v_ground', v_ground) proc_file.set('orbit_alt', alt) proc_file.set('sr0', sr0) proc_file.set('rg_sampling', rg_bw * over_fs) proc_file.set('rg_bw', rg_bw) proc_file.set('b_ati', b_ati) proc_file.set('b_xti', b_xti) proc_file.close() print('-----------------------------------------') print( time.strftime("Processing finished [%Y-%m-%d %H:%M:%S]", time.localtime())) print('-----------------------------------------')