Exemplo n.º 1
0
def proportion_35_to_40m(ds):
    """
    Proportion of the waveform energy from signal beginning to ground peak that is between 35
    and 40 meters in height. Ground peak defined as whichever of the two lowest peaks has greater amplitude.
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    ds = get_dist_metric_value(ds, metric='adj_ground_peak_dist')

    # the processed wf is from sig beg to sig end, select sig beg to ground peak
    sig_beg_to_ground = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.sig_begin_dist,
        signal_end_dist=ds.adj_ground_peak_dist,
    )

    # then select 35 to 40m
    ht_35_to_40m = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.adj_ground_peak_dist - 40.0,
        signal_end_dist=ds.adj_ground_peak_dist - 35.0,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    sig_beg_to_ground = sig_beg_to_ground.transpose(dims[0], dims[1])
    ht_35_to_40m = ht_35_to_40m.transpose(dims[0], dims[1])

    return ht_35_to_40m.sum(dim="rec_bin") / sig_beg_to_ground.sum(
        dim="rec_bin")
Exemplo n.º 2
0
def energy_adj_ground_to_sig_end(ds):
    """
    Waveform energy from the ground peak.  We calculated senergy_whrc as the energy of the waveform (in digital counts) from the ground peak
    to the signal end multiplied by two. Ground peak defined as whichever of the two lowest peaks has greater amplitude. We then applied the
    following linear transformation in order to calculate on the same scale as data published by Margolis et al. (2015)
    senergy = -4.397006 + 0.006208 * senergy_whrc
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    path = 'gs://carbonplan-climatetrace/inputs/volt_table.csv'
    volt_table = pd.read_csv(path)
    volt_to_digital_count = volt_table.set_index('volt_value')['ind'].to_dict()
    wf_in_digital_count = xr.apply_ufunc(
        volt_to_digital_count.__getitem__,
        ds.rec_wf.astype(float).round(6).fillna(-0.195279),
        vectorize=True,
        dask='parallelized',
    )

    ds = get_dist_metric_value(ds, metric='adj_ground_peak_dist')
    # the processed wf is from sig beg to sig end, select adj ground peak to sig end instead
    ground_energy = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=wf_in_digital_count,
        signal_begin_dist=ds.adj_ground_peak_dist,
        signal_end_dist=ds.sig_end_dist,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    ground_energy = ground_energy.transpose(dims[0], dims[1])

    senergy_whrc = ground_energy.sum(dim="rec_bin") * 2

    return -4.397006 + 0.006208 * senergy_whrc
Exemplo n.º 3
0
def proportion_sig_beg_to_start_of_ground(ds):
    """
    The total energy from signal beginning to the start of the ground peak,
    normalized by total energy of the waveform. Ground peak assumed to be the last peak.
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    ds = get_dist_metric_value(ds, metric='start_of_ground_peak_dist')

    # the processed wf is from sig beg to sig end, select sig beg to ground peak
    sig_beg_to_ground = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.sig_begin_dist,
        signal_end_dist=ds.start_of_ground_peak_dist,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    sig_beg_to_ground = sig_beg_to_ground.transpose(dims[0], dims[1])

    # total energy of the smoothed waveform
    total = ds.processed_wf.sum(dim="rec_bin")

    return sig_beg_to_ground.sum(dim="rec_bin") / total
Exemplo n.º 4
0
def get_quadratic_mean_dist(ds):
    """
    From Neigh et al 2013: quadratic mean height of the waveform, calculated as the
    square root [∑ (normalized amplitude in a given canopy height bin) × (height of bin)**2]
    Original citation from Lefsky et al 1999. From signal beginning to adj ground peak.
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    ds = get_dist_metric_value(ds, metric='adj_ground_peak_dist')

    # the processed wf is from sig beg to sig end, select sig beg to ground peak
    sig_beg_to_adj_ground = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.sig_begin_dist,
        signal_end_dist=ds.adj_ground_peak_dist,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    sig_beg_to_adj_ground = sig_beg_to_adj_ground.transpose(dims[0], dims[1])

    bins = ds.rec_wf_sample_dist

    # equivalent to
    # numerator = (np.square(bins) * sig_beg_to_adj_ground).sum(dim='rec_bin')
    # denom = sig_beg_to_adj_ground.sum(dim='rec_bin')
    # np.sqrt(numerator / denom)
    return np.sqrt(
        np.square(bins).weighted(sig_beg_to_adj_ground).mean("rec_bin"))
Exemplo n.º 5
0
def get_percentile_canopy_dist(ds, percentile):
    """
    the height at which 10% of the waveform energy from 0.5 m above the ground peak
    to signal beginning has been reached
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    ds = get_dist_metric_value(ds, metric='bottom_of_canopy_dist')

    # the processed wf is from sig beg to sig end, select sig beg to ground peak
    canopy = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.sig_begin_dist,
        signal_end_dist=ds.bottom_of_canopy_dist,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    canopy = canopy.transpose(dims[0], dims[1])

    total = canopy.sum(dim="rec_bin")
    cumsum = canopy.cumsum(dim="rec_bin")
    target = total * percentile / 100.0

    return ds.rec_wf_sample_dist.where(cumsum > target).max(dim="rec_bin")
Exemplo n.º 6
0
def get_percentile_of_sig_beg_and_adj_ground_dist(ds, percentile):
    """
    the distance, in meters, between the ground peak and the height at which 10% of the waveform energy
    from ground peak to signal beginning has been reached. Waveform energy accumulation relative to
    ground peak. Ground peak defined as whichever of the two lowest peaks has greater amplitude.
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    ds = get_dist_metric_value(ds, metric='adj_ground_peak_dist')

    # the processed wf is from sig beg to sig end, select sig beg to ground peak
    sig_beg_to_adj_ground = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.sig_begin_dist,
        signal_end_dist=ds.adj_ground_peak_dist,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    sig_beg_to_adj_ground = sig_beg_to_adj_ground.transpose(dims[0], dims[1])

    total = sig_beg_to_adj_ground.sum(dim="rec_bin")
    cumsum = sig_beg_to_adj_ground.cumsum(dim="rec_bin")
    target = total * percentile / 100.0

    return ds.rec_wf_sample_dist.where(cumsum > target).max(dim="rec_bin")
Exemplo n.º 7
0
def get_mean_dist(ds):
    """
    Mean height of the waveform from the signal beginning to adj ground peak
    """
    from carbonplan_trace.v1.glas_preprocess import select_valid_area  # avoid circular import

    ds = get_dist_metric_value(ds, metric='adj_ground_peak_dist')

    # the processed wf is from sig beg to sig end, select sig beg to ground peak
    sig_beg_to_adj_ground = select_valid_area(
        bins=ds.rec_wf_sample_dist,
        wf=ds.processed_wf,
        signal_begin_dist=ds.sig_begin_dist,
        signal_end_dist=ds.adj_ground_peak_dist,
    )

    # make sure dimensions matches up
    dims = ds.processed_wf.dims
    sig_beg_to_adj_ground = sig_beg_to_adj_ground.transpose(dims[0], dims[1])

    bins = ds.rec_wf_sample_dist

    return bins.weighted(sig_beg_to_adj_ground).mean("rec_bin")