Esempio n. 1
0
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('-----------------------------------------')
Esempio n. 2
0
def ati_process(cfg_file, proc_output_file, ocean_file, output_file):

    print('-------------------------------------------------------------------')
    print(time.strftime("- OCEANSAR ATI Processor: [%Y-%m-%d %H:%M:%S]", time.localtime()))
    print('-------------------------------------------------------------------')

    print('Initializing...')

    ## CONFIGURATION FILE
    cfg = tpio.ConfigFile(cfg_file)

    # SAR
    inc_angle = np.deg2rad(cfg.sar.inc_angle)
    f0 = cfg.sar.f0
    prf = cfg.sar.prf
    num_ch = 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
    pol = cfg.sar.pol
    if pol == 'DP':
        polt = ['hh', 'vv']
    elif pol == 'hh':
        polt = ['hh']
    else:
        polt = ['vv']
    # ATI
    rg_ml = cfg.ati.rg_ml
    az_ml = cfg.ati.az_ml
    ml_win = cfg.ati.ml_win
    plot_save = cfg.ati.plot_save
    plot_path = cfg.ati.plot_path
    plot_format = cfg.ati.plot_format
    plot_tex = cfg.ati.plot_tex
    plot_surface = cfg.ati.plot_surface
    plot_proc_ampl = cfg.ati.plot_proc_ampl
    plot_coh = cfg.ati.plot_coh
    plot_coh_all = cfg.ati.plot_coh_all
    plot_ati_phase = cfg.ati.plot_ati_phase
    plot_ati_phase_all = cfg.ati.plot_ati_phase_all
    plot_vel_hist = cfg.ati.plot_vel_hist
    plot_vel = cfg.ati.plot_vel

    ## CALCULATE PARAMETERS
    if v_ground == 'auto': v_ground = geosar.orbit_to_vel(alt, ground=True)
    k0 = 2.*np.pi*f0/const.c
    rg_sampling = rg_bw*over_fs

    # PROCESSED RAW DATA
    proc_content = tpio.ProcFile(proc_output_file, 'r')
    proc_data = proc_content.get('slc*')
    proc_content.close()

    # OCEAN SURFACE
    surface = OceanSurface()
    surface.load(ocean_file, compute=['D', 'V'])
    surface.t = 0.

    # OUTPUT FILE
    output = open(output_file, 'w')

    # OTHER INITIALIZATIONS
    # Enable TeX
    if plot_tex:
        plt.rc('font', family='serif')
        plt.rc('text', usetex=True)

    # 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)

    # SURFACE VELOCITIES
    grg_grid_spacing = (const.c/2./rg_sampling/np.sin(inc_angle))
    rg_res_fact = grg_grid_spacing / surface.dx
    az_grid_spacing = (v_ground/prf)
    az_res_fact = az_grid_spacing / surface.dy
    res_fact = np.ceil(np.sqrt(rg_res_fact*az_res_fact))

    # SURFACE RADIAL VELOCITY
    v_radial_surf = surface.Vx*np.sin(inc_angle) - surface.Vz*np.cos(inc_angle)
    v_radial_surf_ml = utils.smooth(utils.smooth(v_radial_surf, res_fact * rg_ml, axis=1), res_fact * az_ml, axis=0)
    v_radial_surf_mean = np.mean(v_radial_surf)
    v_radial_surf_std = np.std(v_radial_surf)
    v_radial_surf_ml_std = np.std(v_radial_surf_ml)

    # SURFACE HORIZONTAL VELOCITY
    v_horizo_surf = surface.Vx
    v_horizo_surf_ml = utils.smooth(utils.smooth(v_horizo_surf, res_fact * rg_ml, axis=1), res_fact * az_ml, axis=0)
    v_horizo_surf_mean = np.mean(v_horizo_surf)
    v_horizo_surf_std = np.std(v_horizo_surf)
    v_horizo_surf_ml_std = np.std(v_horizo_surf_ml)

    # Expected mean azimuth shift
    sr0 = geosar.inc_to_sr(inc_angle, alt)
    avg_az_shift = - v_radial_surf_mean / v_ground * sr0
    std_az_shift = v_radial_surf_std / v_ground * sr0
    ##################
    # ATI PROCESSING #
    ##################

    print('Starting ATI processing...')

    # Get dimensions & calculate region of interest
    rg_span = surface.Lx
    az_span = surface.Ly
    rg_size = proc_data[0].shape[2]
    az_size = proc_data[0].shape[1]

    # Note: RG is projected, so plots are Ground Range
    rg_min = 0
    rg_max = np.int(rg_span/(const.c/2./rg_sampling/np.sin(inc_angle)))
    az_min = np.int(az_size/2. + (-az_span/2. + avg_az_shift)/(v_ground/prf))
    az_max = np.int(az_size/2. + (az_span/2. + avg_az_shift)/(v_ground/prf))
    az_guard = np.int(std_az_shift / (v_ground / prf))
    if (az_max - az_min) < (2 * az_guard - 10):
        print('Not enough edge-effect free image')
        return

    # Adaptive coregistration
    if cfg.sar.L_total:
        ant_L = ant_L/np.float(num_ch)
        dist_chan = ant_L/2
    else:
        if np.float(cfg.sar.Spacing) != 0:
            dist_chan = np.float(cfg.sar.Spacing)/2
        else:
            dist_chan = ant_L/2
    # dist_chan = ant_L/num_ch/2.
    print('ATI Spacing: %f' % dist_chan)
    inter_chan_shift_dist = dist_chan/(v_ground/prf)
    # Subsample shift in azimuth
    for chind in range(proc_data.shape[0]):
        shift_dist = - chind * inter_chan_shift_dist
        shift_arr = np.exp(-2j * np.pi * shift_dist *
                           np.roll(np.arange(az_size) - az_size/2,
                                   int(-az_size / 2)) / az_size)
        shift_arr = shift_arr.reshape((1, az_size, 1))
        proc_data[chind] = np.fft.ifft(np.fft.fft(proc_data[chind], axis=1) *
                                       shift_arr, axis=1)

    # First dimension is number of channels, second is number of pols
    ch_dim = proc_data.shape[0:2]
    npol = ch_dim[1]
    proc_data_rshp = [np.prod(ch_dim), proc_data.shape[2], proc_data.shape[3]]
    # Compute extended covariance matrices...
    proc_data = proc_data.reshape(proc_data_rshp)
    # Intensities
    i_all = []
    for chind in range(proc_data.shape[0]):
        this_i = utils.smooth(utils.smooth(np.abs(proc_data[chind])**2., rg_ml, axis=1, window=ml_win),
                              az_ml, axis=0, window=ml_win)
        i_all.append(this_i[az_min:az_max, rg_min:rg_max])
    i_all = np.array(i_all)
    # .reshape((ch_dim) + (az_max - az_min, rg_max - rg_min))
    interfs = []
    cohs = []
    tind = 0
    coh_lut = np.zeros((proc_data.shape[0], proc_data.shape[0]), dtype=int)
    for chind1 in range(proc_data.shape[0]):
        for chind2 in range(chind1 + 1, proc_data.shape[0]):
            coh_lut[chind1, chind2] = tind
            tind = tind + 1
            t_interf = utils.smooth(utils.smooth(proc_data[chind2] *
                                                 np.conj(proc_data[chind1]),
                                                 rg_ml, axis=1, window=ml_win),
                                    az_ml, axis=0, window=ml_win)
            interfs.append(t_interf[az_min:az_max, rg_min:rg_max])
            cohs.append(t_interf[az_min:az_max, rg_min:rg_max] /
                        np.sqrt(i_all[chind1] * i_all[chind2]))

    print('Generating plots and estimating values...')

    # SURFACE HEIGHT
    if plot_surface:
        plt.figure()
        plt.imshow(surface.Dz, cmap="ocean",
                   extent=[0, surface.Lx, 0, surface.Ly], origin='lower')
        plt.title('Surface Height')
        plt.xlabel('Ground range [m]')
        plt.ylabel('Azimuth [m]')
        cbar = plt.colorbar()
        cbar.ax.set_xlabel('[m]')

        if plot_save:
            plt.savefig(plot_path + os.sep + 'plot_surface.' + plot_format,
                        bbox_inches='tight')
            plt.close()
        else:
            plt.show()


    # PROCESSED AMPLITUDE
    if plot_proc_ampl:
        for pind in range(npol):
            save_path = (plot_path + os.sep + 'amp_dB_' + polt[pind]+
                         '.' + plot_format)
            plt.figure()
            plt.imshow(utils.db(i_all[pind]), aspect='equal',
                       origin='lower',
                       vmin=utils.db(np.max(i_all[pind]))-20,
                       extent=[0., rg_span, 0., az_span], interpolation='nearest',
                       cmap='viridis')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("Amplitude")
            plt.colorbar()
            plt.savefig(save_path)

            save_path = (plot_path + os.sep + 'amp_' + polt[pind]+
                         '.' + plot_format)
            int_img = (i_all[pind])**0.5
            vmin = np.mean(int_img) - 3 * np.std(int_img)
            vmax = np.mean(int_img) + 3 * np.std(int_img)
            plt.figure()
            plt.imshow(int_img, aspect='equal',
                       origin='lower',
                       vmin=vmin, vmax=vmax,
                       extent=[0., rg_span, 0., az_span], interpolation='nearest',
                       cmap='viridis')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("Amplitude")
            plt.colorbar()
            plt.savefig(save_path)

    if plot_coh and ch_dim[0] > 1:
        for pind in range(npol):
            save_path = (plot_path + os.sep + 'ATI_coh_' +
                         polt[pind] + polt[pind] +
                         '.' + plot_format)
            coh_ind = coh_lut[(pind, pind + npol)]
            plt.figure()
            plt.imshow(np.abs(cohs[coh_ind]), aspect='equal',
                       origin='lower',
                       vmin=0, vmax=1,
                       extent=[0., rg_span, 0., az_span],
                       cmap='bone')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("ATI Coherence")
            # plt.colorbar()
            plt.savefig(save_path)

    # ATI PHASE

    tau_ati = dist_chan/v_ground

    ati_phases = []
    # Hack to avoid interferogram computation if there are no interferometric channels
    if num_ch > 1:
        npol_ = npol
    else:
        npol_ = 0
    for pind in range(npol_):
        save_path = (plot_path + os.sep + 'ATI_pha_' +
                     polt[pind] + polt[pind] +
                     '.' + plot_format)
        coh_ind = coh_lut[(pind, pind + npol)]
        ati_phase = uwphase(cohs[coh_ind])
        ati_phases.append(ati_phase)
        v_radial_est = -ati_phase / tau_ati / (k0 * 2.)
        if plot_ati_phase:
            phase_mean = np.mean(ati_phase)
            phase_std = np.std(ati_phase)
            vmin = np.max([-np.abs(phase_mean) - 4*phase_std,
                           -np.abs(ati_phase).max()])
            vmax = np.min([np.abs(phase_mean) + 4*phase_std,
                           np.abs(ati_phase).max()])
            plt.figure()
            plt.imshow(ati_phase, aspect='equal',
                       origin='lower',
                       vmin=vmin, vmax=vmax,
                       extent=[0., rg_span, 0., az_span],
                       cmap='hsv')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("ATI Phase")
            plt.colorbar()
            plt.savefig(save_path)

            save_path = (plot_path + os.sep + 'ATI_rvel_' +
                         polt[pind] + polt[pind] +
                         '.' + plot_format)
            vmin = -np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std
            vmax = np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std
            plt.figure()
            plt.imshow(v_radial_est, aspect='equal',
                       origin='lower',
                       vmin=vmin, vmax=vmax,
                       extent=[0., rg_span, 0., az_span],
                       cmap='bwr')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("Estimated Radial Velocity " + polt[pind])
            plt.colorbar()
            plt.savefig(save_path)

    if npol_ == 4:  # Bypass this for now
        # Cross pol interferogram
        coh_ind = coh_lut[(0, 1)]
        save_path = (plot_path + os.sep + 'POL_coh_' +
                     polt[0] + polt[1] +
                     '.' + plot_format)
        utils.image(np.abs(cohs[coh_ind]), max=1, min=0, aspect='equal',
                    cmap='gray', extent=[0., rg_span, 0., az_span],
                    xlabel='Ground range [m]', ylabel='Azimuth [m]',
                    title='XPOL Coherence',
                    usetex=plot_tex, save=plot_save, save_path=save_path)
        save_path = (plot_path + os.sep + 'POL_pha_' +
                     polt[0] + polt[1] +
                     '.' + plot_format)
        ati_phase = uwphase(cohs[coh_ind])
        phase_mean = np.mean(ati_phase)
        phase_std = np.std(ati_phase)
        vmin = np.max([-np.abs(phase_mean) - 4*phase_std, -np.pi])
        vmax = np.min([np.abs(phase_mean) + 4*phase_std, np.pi])
        utils.image(ati_phase, aspect='equal',
                    min=vmin,  max=vmax,
                    cmap=utils.bwr_cmap, extent=[0., rg_span, 0., az_span],
                    xlabel='Ground range [m]', ylabel='Azimuth [m]',
                    title='XPOL Phase', cbar_xlabel='[rad]',
                    usetex=plot_tex, save=plot_save, save_path=save_path)

    if num_ch > 1:
        ati_phases = np.array(ati_phases)

        output.write('--------------------------------------------\n')
        output.write('SURFACE RADIAL VELOCITY - NO SMOOTHING\n')
        output.write('MEAN(SURF. V) = %.4f\n' % v_radial_surf_mean)
        output.write('STD(SURF. V) = %.4f\n' % v_radial_surf_std)
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write('SURFACE RADIAL VELOCITY - SMOOTHING (WIN. SIZE=%dx%d)\n' % (az_ml, rg_ml))
        output.write('MEAN(SURF. V) = %.4f\n' % v_radial_surf_mean)
        output.write('STD(SURF. V) = %.4f\n' % v_radial_surf_ml_std)
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write('SURFACE HORIZONTAL VELOCITY - NO SMOOTHING\n')
        output.write('MEAN(SURF. V) = %.4f\n' % v_horizo_surf_mean)
        output.write('STD(SURF. V) = %.4f\n' % v_horizo_surf_std)
        output.write('--------------------------------------------\n\n')

        if plot_vel_hist:
            # PLOT RADIAL VELOCITY
            plt.figure()

            plt.hist(v_radial_surf.flatten(), 200, normed=True, histtype='step')
            #plt.hist(v_radial_surf_ml.flatten(), 500, normed=True, histtype='step')
            plt.grid(True)
            plt.xlim([-np.abs(v_radial_surf_mean) - 4.*v_radial_surf_std, np.abs(v_radial_surf_mean) + 4.* v_radial_surf_std])
            plt.xlabel('Radial velocity [m/s]')
            plt.ylabel('PDF')
            plt.title('Surface velocity')

            if plot_save:
                plt.savefig(plot_path + os.sep + 'TRUE_radial_vel_hist.' + plot_format)
                plt.close()
            else:
                plt.show()

            plt.figure()
            plt.hist(v_radial_surf_ml.flatten(), 200, normed=True, histtype='step')
            #plt.hist(v_radial_surf_ml.flatten(), 500, normed=True, histtype='step')
            plt.grid(True)
            plt.xlim([-np.abs(v_radial_surf_mean) - 4.*v_radial_surf_std, np.abs(v_radial_surf_mean) + 4.* v_radial_surf_std])
            plt.xlabel('Radial velocity [m/s]')
            plt.ylabel('PDF')
            plt.title('Surface velocity (low pass filtered)')

            if plot_save:
                plt.savefig(plot_path + os.sep + 'TRUE_radial_vel_ml_hist.' + plot_format)
                plt.close()
            else:
                plt.show()

        if plot_vel:

            utils.image(v_radial_surf, aspect='equal', cmap=utils.bwr_cmap, extent=[0., rg_span, 0., az_span],
                        xlabel='Ground range [m]', ylabel='Azimuth [m]', title='Surface Radial Velocity', cbar_xlabel='[m/s]',
                        min=-np.abs(v_radial_surf_mean) - 4.*v_radial_surf_std, max=np.abs(v_radial_surf_mean) + 4.*v_radial_surf_std,
                        usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'TRUE_radial_vel.' + plot_format)
            utils.image(v_radial_surf_ml, aspect='equal', cmap=utils.bwr_cmap, extent=[0., rg_span, 0., az_span],
                        xlabel='Ground range [m]', ylabel='Azimuth [m]', title='Surface Radial Velocity', cbar_xlabel='[m/s]',
                        min=-np.abs(v_radial_surf_mean) - 4.*v_radial_surf_std, max=np.abs(v_radial_surf_mean) + 4.*v_radial_surf_std,
                        usetex=plot_tex, save=plot_save, save_path=plot_path + os.sep + 'TRUE_radial_vel_ml.' + plot_format)

        ##  ESTIMATED VELOCITIES

        # Note: plot limits are taken from surface calculations to keep the same ranges

        # ESTIMATE RADIAL VELOCITY
        v_radial_ests = -ati_phases/tau_ati/(k0*2.)

        # ESTIMATE HORIZONTAL VELOCITY
        v_horizo_ests = -ati_phases/tau_ati/(k0*2.)/np.sin(inc_angle)

        #Trim edges
        v_radial_ests = v_radial_ests[:, az_guard:-az_guard, 5:-5]
        v_horizo_ests = v_horizo_ests[:, az_guard:-az_guard, 5:-5]
        output.write('--------------------------------------------\n')
        output.write('ESTIMATED RADIAL VELOCITY - NO SMOOTHING\n')
        for pind in range(npol):
            output.write("%s Polarization\n" % polt[pind])
            output.write('MEAN(EST. V) = %.4f\n' % np.mean(v_radial_ests[pind]))
            output.write('STD(EST. V) = %.4f\n' % np.std(v_radial_ests[pind]))
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write('ESTIMATED RADIAL VELOCITY - SMOOTHING (WIN. SIZE=%dx%d)\n' % (az_ml, rg_ml))
        for pind in range(npol):
            output.write("%s Polarization\n" % polt[pind])
            output.write('MEAN(EST. V) = %.4f\n' % np.mean(utils.smooth(utils.smooth(v_radial_ests[pind],
                                                                                     rg_ml, axis=1),
                                                                        az_ml, axis=0)))
            output.write('STD(EST. V) = %.4f\n' % np.std(utils.smooth(utils.smooth(v_radial_ests[pind],
                                                                                   rg_ml, axis=1),
                                                                      az_ml, axis=0)))
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write('ESTIMATED HORIZONTAL VELOCITY - NO SMOOTHING\n')
        for pind in range(npol):
            output.write("%s Polarization\n" % polt[pind])
            output.write('MEAN(EST. V) = %.4f\n' % np.mean(v_horizo_ests[pind]))
            output.write('STD(EST. V) = %.4f\n' % np.std(v_horizo_ests[pind]))
        output.write('--------------------------------------------\n\n')

    # Processed NRCS

    NRCS_est_avg = 10*np.log10(np.mean(np.mean(i_all[:, az_guard:-az_guard, 5:-5], axis=-1), axis=-1))
    output.write('--------------------------------------------\n')
    for pind in range(npol):
        output.write("%s Polarization\n" % polt[pind])
        output.write('Estimated mean NRCS = %5.2f\n' % NRCS_est_avg[pind])
    output.write('--------------------------------------------\n\n')

    # Some bookkeeping information
    output.write('--------------------------------------------\n')
    output.write('GROUND RANGE GRID SPACING = %.4f\n' % grg_grid_spacing)
    output.write('AZIMUTH GRID SPACING = %.4f\n' % az_grid_spacing)
    output.write('--------------------------------------------\n\n')

    output.close()

    if plot_vel_hist and num_ch > 1:
        # PLOT RADIAL VELOCITY
        plt.figure()
        plt.hist(v_radial_surf.flatten(), 200, normed=True, histtype='step',
                 label='True')
        for pind in range(npol):
            plt.hist(v_radial_ests[pind].flatten(), 200, normed=True,
                     histtype='step', label=polt[pind])
        plt.grid(True)
        plt.xlim([-np.abs(v_radial_surf_mean) - 4.*v_radial_surf_std,
                  np.abs(v_radial_surf_mean) + 4.*v_radial_surf_std])
        plt.xlabel('Radial velocity [m/s]')
        plt.ylabel('PDF')
        plt.title('Estimated velocity')
        plt.legend()

        if plot_save:
            plt.savefig(plot_path + os.sep + 'ATI_radial_vel_hist.' + plot_format)
            plt.close()
        else:
            plt.show()

    # Save some statistics to npz file
    #
    if num_ch > 1:
        filenpz = os.path.join(os.path.dirname(output_file), 'ati_stats.npz')
        # Mean coh
        cohs = np.array(cohs)[:, az_guard:-az_guard, 5:-5]

        np.savez(filenpz,
                 nrcs=NRCS_est_avg,
                 v_r_dop=np.mean(np.mean(v_radial_ests, axis=-1), axis=-1),
                 v_r_surf = v_radial_surf_mean,
                 v_r_surf_std = v_radial_surf_std,
                 coh_mean= np.mean(np.mean(cohs, axis=-1), axis=-1),
                 abscoh_mean=np.mean(np.mean(np.abs(cohs), axis=-1), axis=-1),
                 coh_lut=coh_lut,
                 pols=polt)
    print('----------------------------------------')
    print(time.strftime("ATI Processing finished [%Y-%m-%d %H:%M:%S]", time.localtime()))
    print('----------------------------------------')
Esempio n. 3
0
def ati_process(cfg_file, insar_output_file, ocean_file, output_file):

    print(
        '-------------------------------------------------------------------')
    print(
        time.strftime("- OCEANSAR ATI Processor: [%Y-%m-%d %H:%M:%S]",
                      time.localtime()))
    print(
        '-------------------------------------------------------------------')

    print('Initializing...')

    ## CONFIGURATION FILE
    cfg = tpio.ConfigFile(cfg_file)

    # SAR
    pol = cfg.sar.pol
    if pol == 'DP':
        polt = ['hh', 'vv']
    elif pol == 'hh':
        polt = ['hh']
    else:
        polt = ['vv']
    # ATI

    ml_win = cfg.ati.ml_win
    plot_save = cfg.ati.plot_save
    plot_path = cfg.ati.plot_path
    plot_format = cfg.ati.plot_format
    plot_tex = cfg.ati.plot_tex
    plot_surface = cfg.ati.plot_surface
    plot_proc_ampl = cfg.ati.plot_proc_ampl
    plot_coh = cfg.ati.plot_coh
    plot_coh_all = cfg.ati.plot_coh_all
    plot_ati_phase = cfg.ati.plot_ati_phase
    plot_ati_phase_all = cfg.ati.plot_ati_phase_all
    plot_vel_hist = cfg.ati.plot_vel_hist
    plot_vel = cfg.ati.plot_vel

    # PROCESSED InSAR L1b DATA
    insar_data = tpio.L1bFile(insar_output_file, 'r')
    i_all = insar_data.get('ml_intensity')
    cohs = insar_data.get('ml_coherence') * np.exp(
        1j * insar_data.get('ml_phase'))
    coh_lut = insar_data.get('coh_lut')
    sr0 = insar_data.get('sr0')
    inc_angle = insar_data.get('inc_angle')
    b_ati = insar_data.get('b_ati')
    b_xti = insar_data.get('b_xti')
    f0 = insar_data.get('f0')
    az_sampling = insar_data.get('az_sampling')
    num_ch = insar_data.get('num_ch')
    rg_sampling = insar_data.get('rg_sampling')
    v_ground = insar_data.get('v_ground')
    alt = insar_data.get('orbit_alt')
    inc_angle = np.deg2rad(insar_data.get('inc_angle'))
    rg_ml = insar_data.get('rg_ml')
    az_ml = insar_data.get('az_ml')
    insar_data.close()

    # CALCULATE PARAMETERS
    k0 = 2. * np.pi * f0 / const.c

    # OCEAN SURFACE
    surface = OceanSurface()
    surface.load(ocean_file, compute=['D', 'V'])
    surface.t = 0.

    # OUTPUT FILE
    output = open(output_file, 'w')

    # OTHER INITIALIZATIONS
    # Enable TeX
    if plot_tex:
        plt.rc('font', family='serif')
        plt.rc('text', usetex=True)

    # 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)

    # SURFACE VELOCITIES
    grg_grid_spacing = (const.c / 2. / rg_sampling / np.sin(inc_angle))
    rg_res_fact = grg_grid_spacing / surface.dx
    az_grid_spacing = (v_ground / az_sampling)
    az_res_fact = az_grid_spacing / surface.dy
    res_fact = np.ceil(np.sqrt(rg_res_fact * az_res_fact))

    # SURFACE RADIAL VELOCITY
    v_radial_surf = surface.Vx * np.sin(inc_angle) - surface.Vz * np.cos(
        inc_angle)
    v_radial_surf_ml = utils.smooth(utils.smooth(v_radial_surf,
                                                 res_fact * rg_ml,
                                                 axis=1),
                                    res_fact * az_ml,
                                    axis=0)
    v_radial_surf_mean = np.mean(v_radial_surf)
    v_radial_surf_std = np.std(v_radial_surf)
    v_radial_surf_ml_std = np.std(v_radial_surf_ml)

    # SURFACE HORIZONTAL VELOCITY
    v_horizo_surf = surface.Vx
    v_horizo_surf_ml = utils.smooth(utils.smooth(v_horizo_surf,
                                                 res_fact * rg_ml,
                                                 axis=1),
                                    res_fact * az_ml,
                                    axis=0)
    v_horizo_surf_mean = np.mean(v_horizo_surf)
    v_horizo_surf_std = np.std(v_horizo_surf)
    v_horizo_surf_ml_std = np.std(v_horizo_surf_ml)

    # Expected mean azimuth shift
    sr0 = geosar.inc_to_sr(inc_angle, alt)
    avg_az_shift = -v_radial_surf_mean / v_ground * sr0
    std_az_shift = v_radial_surf_std / v_ground * sr0

    az_guard = np.int(std_az_shift / (v_ground / az_sampling))
    ##################
    # ATI PROCESSING #
    ##################

    print('Starting ATI processing...')

    # Get dimensions & calculate region of interest
    rg_span = surface.Lx
    az_span = surface.Ly

    # First dimension is number of channels, second is number of pols
    ch_dim = i_all.shape[0:2]
    npol = ch_dim[1]

    print('Generating plots and estimating values...')

    # SURFACE HEIGHT
    if plot_surface:
        plt.figure()
        plt.imshow(surface.Dz,
                   cmap="ocean",
                   extent=[0, surface.Lx, 0, surface.Ly],
                   origin='lower')
        plt.title('Surface Height')
        plt.xlabel('Ground range [m]')
        plt.ylabel('Azimuth [m]')
        cbar = plt.colorbar()
        cbar.ax.set_xlabel('[m]')

        if plot_save:
            plt.savefig(plot_path + os.sep + 'plot_surface.' + plot_format,
                        bbox_inches='tight')
            plt.close()
        else:
            plt.show()

    # PROCESSED AMPLITUDE
    if plot_proc_ampl:
        for pind in range(npol):
            save_path = (plot_path + os.sep + 'amp_dB_' + polt[pind] + '.' +
                         plot_format)
            plt.figure()
            plt.imshow(utils.db(i_all[0, pind]),
                       aspect='equal',
                       origin='lower',
                       vmin=utils.db(np.max(i_all[pind])) - 20,
                       extent=[0., rg_span, 0., az_span],
                       interpolation='nearest',
                       cmap='viridis')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("Amplitude")
            plt.colorbar()
            plt.savefig(save_path)
            plt.close()
            save_path = (plot_path + os.sep + 'amp_' + polt[pind] + '.' +
                         plot_format)
            int_img = (i_all[0, pind])**0.5
            vmin = np.mean(int_img) - 3 * np.std(int_img)
            vmax = np.mean(int_img) + 3 * np.std(int_img)
            plt.figure()
            plt.imshow(int_img,
                       aspect='equal',
                       origin='lower',
                       vmin=vmin,
                       vmax=vmax,
                       extent=[0., rg_span, 0., az_span],
                       interpolation='nearest',
                       cmap='viridis')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("Amplitude")
            plt.colorbar()
            plt.savefig(save_path)
            plt.close()

    if plot_coh and ch_dim[0] > 1:
        for pind in range(npol):
            save_path = (plot_path + os.sep + 'ATI_coh_' + polt[pind] +
                         polt[pind] + '.' + plot_format)
            coh_ind = coh_lut[0, pind, 1, pind]
            plt.figure()
            plt.imshow(np.abs(cohs[coh_ind]),
                       aspect='equal',
                       origin='lower',
                       vmin=0,
                       vmax=1,
                       extent=[0., rg_span, 0., az_span],
                       cmap='bone')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("ATI Coherence")
            # plt.colorbar()
            plt.savefig(save_path)

    # ATI PHASE

    tau_ati = b_ati / v_ground

    ati_phases = []
    # Hack to avoid interferogram computation if there are no interferometric channels
    if num_ch > 1:
        npol_ = npol
    else:
        npol_ = 0
    for pind in range(npol_):
        save_path = (plot_path + os.sep + 'ATI_pha_' + polt[pind] +
                     polt[pind] + '.' + plot_format)
        coh_ind = coh_lut[(0, pind, 1, pind)]
        ati_phase = uwphase(cohs[coh_ind])
        ati_phases.append(ati_phase)
        v_radial_est = -ati_phase / tau_ati[1] / (k0 * 2.)
        if plot_ati_phase:
            phase_mean = np.mean(ati_phase)
            phase_std = np.std(ati_phase)
            vmin = np.max([
                -np.abs(phase_mean) - 4 * phase_std, -np.abs(ati_phase).max()
            ])
            vmax = np.min(
                [np.abs(phase_mean) + 4 * phase_std,
                 np.abs(ati_phase).max()])
            plt.figure()
            plt.imshow(ati_phase,
                       aspect='equal',
                       origin='lower',
                       vmin=vmin,
                       vmax=vmax,
                       extent=[0., rg_span, 0., az_span],
                       cmap='hsv')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("ATI Phase")
            plt.colorbar()
            plt.savefig(save_path)

            save_path = (plot_path + os.sep + 'ATI_rvel_' + polt[pind] +
                         polt[pind] + '.' + plot_format)
            vmin = -np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std
            vmax = np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std
            plt.figure()
            plt.imshow(v_radial_est,
                       aspect='equal',
                       origin='lower',
                       vmin=vmin,
                       vmax=vmax,
                       extent=[0., rg_span, 0., az_span],
                       cmap='bwr')
            plt.xlabel('Ground range [m]')
            plt.ylabel('Azimuth [m]')
            plt.title("Estimated Radial Velocity " + polt[pind])
            plt.colorbar()
            plt.savefig(save_path)

    if npol_ == 4:  # Bypass this for now
        # Cross pol interferogram
        coh_ind = coh_lut[(0, 1)]
        save_path = (plot_path + os.sep + 'POL_coh_' + polt[0] + polt[1] +
                     '.' + plot_format)
        utils.image(np.abs(cohs[coh_ind]),
                    max=1,
                    min=0,
                    aspect='equal',
                    cmap='gray',
                    extent=[0., rg_span, 0., az_span],
                    xlabel='Ground range [m]',
                    ylabel='Azimuth [m]',
                    title='XPOL Coherence',
                    usetex=plot_tex,
                    save=plot_save,
                    save_path=save_path)
        save_path = (plot_path + os.sep + 'POL_pha_' + polt[0] + polt[1] +
                     '.' + plot_format)
        ati_phase = uwphase(cohs[coh_ind])
        phase_mean = np.mean(ati_phase)
        phase_std = np.std(ati_phase)
        vmin = np.max([-np.abs(phase_mean) - 4 * phase_std, -np.pi])
        vmax = np.min([np.abs(phase_mean) + 4 * phase_std, np.pi])
        utils.image(ati_phase,
                    aspect='equal',
                    min=vmin,
                    max=vmax,
                    cmap=utils.bwr_cmap,
                    extent=[0., rg_span, 0., az_span],
                    xlabel='Ground range [m]',
                    ylabel='Azimuth [m]',
                    title='XPOL Phase',
                    cbar_xlabel='[rad]',
                    usetex=plot_tex,
                    save=plot_save,
                    save_path=save_path)

    if num_ch > 1:
        ati_phases = np.array(ati_phases)

        output.write('--------------------------------------------\n')
        output.write('SURFACE RADIAL VELOCITY - NO SMOOTHING\n')
        output.write('MEAN(SURF. V) = %.4f\n' % v_radial_surf_mean)
        output.write('STD(SURF. V) = %.4f\n' % v_radial_surf_std)
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write(
            'SURFACE RADIAL VELOCITY - SMOOTHING (WIN. SIZE=%dx%d)\n' %
            (az_ml, rg_ml))
        output.write('MEAN(SURF. V) = %.4f\n' % v_radial_surf_mean)
        output.write('STD(SURF. V) = %.4f\n' % v_radial_surf_ml_std)
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write('SURFACE HORIZONTAL VELOCITY - NO SMOOTHING\n')
        output.write('MEAN(SURF. V) = %.4f\n' % v_horizo_surf_mean)
        output.write('STD(SURF. V) = %.4f\n' % v_horizo_surf_std)
        output.write('--------------------------------------------\n\n')

        if plot_vel_hist:
            # PLOT RADIAL VELOCITY
            plt.figure()

            plt.hist(v_radial_surf.flatten(),
                     200,
                     density=True,
                     histtype='step')
            #plt.hist(v_radial_surf_ml.flatten(), 500, density=True, histtype='step')
            plt.grid(True)
            plt.xlim([
                -np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std,
                np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std
            ])
            plt.xlabel('Radial velocity [m/s]')
            plt.ylabel('PDF')
            plt.title('Surface velocity')

            if plot_save:
                plt.savefig(plot_path + os.sep + 'TRUE_radial_vel_hist.' +
                            plot_format)
                plt.close()
            else:
                plt.show()

            plt.figure()
            plt.hist(v_radial_surf_ml.flatten(),
                     200,
                     density=True,
                     histtype='step')
            #plt.hist(v_radial_surf_ml.flatten(), 500, density=True, histtype='step')
            plt.grid(True)
            plt.xlim([
                -np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std,
                np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std
            ])
            plt.xlabel('Radial velocity [m/s]')
            plt.ylabel('PDF')
            plt.title('Surface velocity (low pass filtered)')

            if plot_save:
                plt.savefig(plot_path + os.sep + 'TRUE_radial_vel_ml_hist.' +
                            plot_format)
                plt.close()
            else:
                plt.show()

        if plot_vel:

            utils.image(
                v_radial_surf,
                aspect='equal',
                cmap=utils.bwr_cmap,
                extent=[0., rg_span, 0., az_span],
                xlabel='Ground range [m]',
                ylabel='Azimuth [m]',
                title='Surface Radial Velocity',
                cbar_xlabel='[m/s]',
                min=-np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std,
                max=np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std,
                usetex=plot_tex,
                save=plot_save,
                save_path=plot_path + os.sep + 'TRUE_radial_vel.' +
                plot_format)
            utils.image(
                v_radial_surf_ml,
                aspect='equal',
                cmap=utils.bwr_cmap,
                extent=[0., rg_span, 0., az_span],
                xlabel='Ground range [m]',
                ylabel='Azimuth [m]',
                title='Surface Radial Velocity',
                cbar_xlabel='[m/s]',
                min=-np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std,
                max=np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std,
                usetex=plot_tex,
                save=plot_save,
                save_path=plot_path + os.sep + 'TRUE_radial_vel_ml.' +
                plot_format)

        ##  ESTIMATED VELOCITIES

        # Note: plot limits are taken from surface calculations to keep the same ranges

        # ESTIMATE RADIAL VELOCITY
        v_radial_ests = -ati_phases / tau_ati[1] / (k0 * 2.)

        # ESTIMATE HORIZONTAL VELOCITY
        v_horizo_ests = -ati_phases / tau_ati[1] / (k0 *
                                                    2.) / np.sin(inc_angle)

        #Trim edges
        v_radial_ests = v_radial_ests[:, az_guard:-az_guard, 5:-5]
        v_horizo_ests = v_horizo_ests[:, az_guard:-az_guard, 5:-5]
        output.write('--------------------------------------------\n')
        output.write('ESTIMATED RADIAL VELOCITY - NO SMOOTHING\n')
        for pind in range(npol):
            output.write("%s Polarization\n" % polt[pind])
            output.write('MEAN(EST. V) = %.4f\n' %
                         np.mean(v_radial_ests[pind]))
            output.write('STD(EST. V) = %.4f\n' % np.std(v_radial_ests[pind]))
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write(
            'ESTIMATED RADIAL VELOCITY - SMOOTHING (WIN. SIZE=%dx%d)\n' %
            (az_ml, rg_ml))
        for pind in range(npol):
            output.write("%s Polarization\n" % polt[pind])
            output.write('MEAN(EST. V) = %.4f\n' % np.mean(
                utils.smooth(utils.smooth(v_radial_ests[pind], rg_ml, axis=1),
                             az_ml,
                             axis=0)))
            output.write('STD(EST. V) = %.4f\n' % np.std(
                utils.smooth(utils.smooth(v_radial_ests[pind], rg_ml, axis=1),
                             az_ml,
                             axis=0)))
        output.write('--------------------------------------------\n\n')

        output.write('--------------------------------------------\n')
        output.write('ESTIMATED HORIZONTAL VELOCITY - NO SMOOTHING\n')
        for pind in range(npol):
            output.write("%s Polarization\n" % polt[pind])
            output.write('MEAN(EST. V) = %.4f\n' %
                         np.mean(v_horizo_ests[pind]))
            output.write('STD(EST. V) = %.4f\n' % np.std(v_horizo_ests[pind]))
        output.write('--------------------------------------------\n\n')

    # Processed NRCS

    NRCS_est_avg = 10 * np.log10(
        np.mean(np.mean(i_all[:, :, az_guard:-az_guard, 5:-5], axis=-1),
                axis=-1))
    output.write('--------------------------------------------\n')
    for pind in range(npol):
        output.write("%s Polarization\n" % polt[pind])
        output.write('Estimated mean NRCS = %5.2f\n' % NRCS_est_avg[0, pind])
    output.write('--------------------------------------------\n\n')

    # Some bookkeeping information
    output.write('--------------------------------------------\n')
    output.write('GROUND RANGE GRID SPACING = %.4f\n' % grg_grid_spacing)
    output.write('AZIMUTH GRID SPACING = %.4f\n' % az_grid_spacing)
    output.write('--------------------------------------------\n\n')

    output.close()

    if plot_vel_hist and num_ch > 1:
        # PLOT RADIAL VELOCITY
        plt.figure()
        plt.hist(v_radial_surf.flatten(),
                 200,
                 density=True,
                 histtype='step',
                 label='True')
        for pind in range(npol):
            plt.hist(v_radial_ests[pind].flatten(),
                     200,
                     density=True,
                     histtype='step',
                     label=polt[pind])
        plt.grid(True)
        plt.xlim([
            -np.abs(v_radial_surf_mean) - 4. * v_radial_surf_std,
            np.abs(v_radial_surf_mean) + 4. * v_radial_surf_std
        ])
        plt.xlabel('Radial velocity [m/s]')
        plt.ylabel('PDF')
        plt.title('Estimated velocity')
        plt.legend()

        if plot_save:
            plt.savefig(plot_path + os.sep + 'ATI_radial_vel_hist.' +
                        plot_format)
            plt.close()
        else:
            plt.show()

    # Save some statistics to npz file
    #
    if num_ch > 1:
        filenpz = os.path.join(os.path.dirname(output_file), 'ati_stats.npz')
        # Mean coh
        cohs = np.array(cohs)[:, az_guard:-az_guard, 5:-5]

        np.savez(filenpz,
                 nrcs=NRCS_est_avg,
                 v_r_dop=np.mean(np.mean(v_radial_ests, axis=-1), axis=-1),
                 v_r_surf=v_radial_surf_mean,
                 v_r_surf_std=v_radial_surf_std,
                 coh_mean=np.mean(np.mean(cohs, axis=-1), axis=-1),
                 abscoh_mean=np.mean(np.mean(np.abs(cohs), axis=-1), axis=-1),
                 coh_lut=coh_lut,
                 pols=polt)
    print('----------------------------------------')
    print(
        time.strftime("ATI Processing finished [%Y-%m-%d %H:%M:%S]",
                      time.localtime()))
    print('----------------------------------------')