# A little question in the 'auto_count' of 'cca.hpp'

• ### Question

• Hello all,

I have been working on a school task that may well use the 'cca.hpp' to make sequence synchronized, but I got confused on the code given by Sora, mainly the value of 'auto_count'.

First it was set to zero:

```sync_state = no_energy;

auto_count = 0;```

After that,

```			if ( sync_state == no_energy )
{
// auto-correlation senssing
int iAutoCorr = GetAutoCorrelation ( pi>>2, corr_r, corr_i );
int iEnergy   = GetEnergy ( pi>>2 );

// save sample in the accumulator
sample_his << (pi>>2);

sense_count += 4;

if (
(iEnergy > (int)cca_pwr_threshold) &&
iAutoCorr >= (iEnergy - (iEnergy >> 3)))
{
auto_count++;

// any case we are sensing high, we reset the sense counter
sense_count = 0;

// if remaining in plateau for 4*4=16 samples
if (auto_count >= 4)
{
_dump_text ( "power detected!\n" );```

I thought that there would be no way that 'auto_count>=4' can be true, because after the determination the ‘auto_count’ will be set to zero again:

```                else
{
auto_count = 0;
}```

the whole 'cca.hpp' shows below：

```#pragma once
#include <sora.h>
#include <soratime.h>
#include <dspcomm.h>

/***********************************************
TEnergyDetect
************************************************/
DEFINE_LOCAL_CONTEXT(TEnergyDetect, CF_11CCA, CF_Error);
template<TFILTER_ARGS>
class TEnergyDetect : public TFilter<TFILTER_PARAMS>
{
static const uint win_len = 8;	                // 8*4  samples, roughly 1us
static const uint min_sensing_samples = 32;     // 32*4 samples, 3 us
static const uint max_sensing_samples = 100;    // 100*4 samples, roughly 10us
CTX_VAR_RO (uint, 				cca_pwr_threshold );

CTX_VAR_RW (CF_11CCA::CCAState, cca_state );
CTX_VAR_RW (ulong, error_code );

uint average_energy_;
uint window_[win_len];
uint idx_;
uint count_;

public:
DEFINE_IPORT(COMPLEX16, 4);
DEFINE_OPORT(COMPLEX16, 4);

protected:
FINL void __init () {
average_energy_ = 0;
memset ( window_, 0, sizeof(window_));
idx_   = 0;
count_ = 0;
}

public:
REFERENCE_LOCAL_CONTEXT(TEnergyDetect );

STD_TFILTER_CONSTRUCTOR(TEnergyDetect )
BIND_CONTEXT(CF_11CCA::cca_pwr_threshold, cca_pwr_threshold)
BIND_CONTEXT(CF_11CCA::cca_state, 		  cca_state)
BIND_CONTEXT(CF_Error::error_code, 		  error_code)
{ __init (); }

STD_TFILTER_RESET() {
__init ();
}

STD_TFILTER_FLUSH() { }

BOOL_FUNC_PROCESS (ipin)
{
{
const vcs& pi = cast_ref<vcs>(ipin.peek ());

// Computer the power average
// Average over 32 samples
vi power = hadd (shift_right (SquaredNorm (pi), 5));
uint ave_power = (uint) power[0];
average_energy_ = average_energy_ - window_[idx_] + ave_power;
window_[idx_] = ave_power;
idx_ ++; if ( idx_ >= win_len ) idx_ = 0;

count_ ++;
if ( count_ >= min_sensing_samples ) {
if ( count_ >= max_sensing_samples ) {
error_code = E_ERROR_CS_TIMEOUT;
ipin.clear();
return 0;
}

if ( average_energy_ >= cca_pwr_threshold ) {
cca_state = CF_11CCA::power_detected;
RaiseEvent(OnPowerDetected)();
}
}

// Energy gating - only low power samples pass
if ( cca_state != CF_11CCA::power_detected ) {
vcs& po = cast_ref<vcs>(opin().append());
po = pi;
Next()->Process(opin());
}

ipin.pop();

}
return true;
}
};

/*****************************************************
TCCA11a - Carrier sensing using auto-correlation
******************************************************/
DEFINE_LOCAL_CONTEXT(TCCA11a, CF_11CCA, CF_CFOffset, CF_Error);
template<TFILTER_ARGS>
class TCCA11a : public TFilter<TFILTER_PARAMS>
{
private:
typedef enum { no_energy, high_energy} CCA_STATE;

static const uint ac_norm_shift = 5;
static const uint NORM_SHIFT = 4;

// carrier sensing slot timing
static const uint max_sense_count = 84; // 80/20 = 4us

private:
// Context variables
CTX_VAR_RO (uint, cca_pwr_threshold );
CTX_VAR_RW (CF_11CCA::CCAState, cca_state );
CTX_VAR_RW (ulong,  error_code );

protected:
// accumulators
CMovingWindow<vcs, 4> sample_his;
CAccumulator <int, 4> ac_re_his;
CAccumulator <int, 4> ac_im_his;

// norm0 of the auto correlation
CAccumulator <int, 4> ac_norm_his;
CAccumulator <int, 4> energy_his;
CAccumulator <int, 4> energy_sqr_his;

// counter for autocorrelation high energy samples
uint auto_count;

// counter for the number of samples sensed
uint sense_count;

// counter for the samples in high energy state
uint high_count;

// local sync state
CCA_STATE sync_state;

// variables for cross-correlation
static_wrapper<A16 COMPLEX16 [16][16]> sts_corr_pattern;

// the max value in cross-correlation
int peak_corr;

// the index in sample of the peak
int peak_index;

public:
DEFINE_IPORT(COMPLEX16, 4);
DEFINE_OPORT(COMPLEX16, 4);

protected:
FINL int GetAutoCorrelation ( vcs& input, int& corr_re, int& corr_im ) {
vi re, im;

// compute the auto correlation
conj_mul ( re, im, input, sample_his.First() );

vi sum_r = hadd (re >> NORM_SHIFT );
vi sum_i = hadd (im >> NORM_SHIFT );

ac_re_his << sum_r[0];
ac_im_his << sum_i[0];

corr_re = ac_re_his.Register();
corr_im	= ac_im_his.Register();

// NORM0
int sum = (abs(corr_re) + abs(corr_im));

ac_norm_his << sum;

return ac_norm_his.Register();
}

FINL int GetEnergy ( vcs& input ) {
vi e  = SquaredNorm (input);
vi sum  = hadd (e >> NORM_SHIFT );
energy_his << sum[0];
return energy_his.Register();
}

FINL
int GetCrossCorrelation ( vcs* sarray, int k, vcs* pattern )
{
vi re[4], im[4];
vi sum_re, sum_im;

conj_mul ( re[0], im[0], pattern[0], sarray[k] ); k = (k+1) & 0x3;
conj_mul ( re[1], im[1], pattern[1], sarray[k] ); k = (k+1) & 0x3;
conj_mul ( re[2], im[2], pattern[2], sarray[k] ); k = (k+1) & 0x3;
conj_mul ( re[3], im[3], pattern[3], sarray[k] );

sum_re = hadd (re[0] + re[1] + re[2] + re[3]);
sum_im = hadd (im[0] + im[1] + im[2] + im[3]);

int corr = abs(sum_re[0]) + abs(sum_im[0]);
return corr;
}

FINL bool establish_sync () {
int sindex = sample_his.GetIndex ();
vcs* sarray = (vcs*) sample_his;

// clear the peak record
peak_corr = 0;

int sum_corr = 0;
for (int i=0; i<16; i++) {
vcs* pattern = (vcs*)sts_corr_pattern[i];
int corr = GetCrossCorrelation ( sarray, sindex, pattern );
if ( corr > peak_corr ) {
peak_corr = corr;
peak_index = i;
}
sum_corr += corr;
}

_dump_text ("establish sync: %d %d - sum %d\n", peak_corr, peak_index, sum_corr );

// a peak should be at least twice higher than noise correlation
return ( peak_corr > (sum_corr >> 3));

}

FINL bool check_sync () {
int sindex = sample_his.GetIndex ();
vcs* sarray = (vcs*) sample_his;

vcs* pattern = (vcs*)sts_corr_pattern[peak_index];

int corr = GetCrossCorrelation ( sarray, sindex, pattern );

_dump_text ( "check peak -- %d\n", corr );

// check if it is a peak
// a later peak should not be lower than the first peak by half
if ( corr < (peak_corr >> 1)) {
return false;
} else {
if ( corr > peak_corr ) {
peak_corr = corr;
}
return true;
}
}

protected:
FINL void __init_corr_pattern () {
// build up cross-correlation pattern
A16 COMPLEX16 temp[64];
Generate80211aSTS<64> (temp);

// cyclic shift
for (int i=0; i<16; i++) {
memcpy (sts_corr_pattern[i], &temp[i], sizeof(COMPLEX16)*16);
}
}

FINL void __init () {
sync_state = no_energy;

auto_count = 0;
sense_count = 0;
high_count = 0;

sample_his.Clear();
ac_re_his.Clear();
ac_im_his.Clear();
ac_norm_his.Clear();
energy_his.Clear();
energy_sqr_his.Clear ();

peak_index = 0;
peak_corr  = 0;
}

public:
REFERENCE_LOCAL_CONTEXT(TCCA11a );

STD_TFILTER_CONSTRUCTOR(TCCA11a )
BIND_CONTEXT(CF_11CCA::cca_pwr_threshold, cca_pwr_threshold)
BIND_CONTEXT(CF_11CCA::cca_state,		  cca_state)
BIND_CONTEXT(CF_CFOffset::CFO_est,		  CFO_est)
BIND_CONTEXT(CF_Error::error_code,		  error_code)
{
__init_corr_pattern();
__init ();
}

STD_TFILTER_RESET() {
__init ();
}

STD_TFILTER_FLUSH() { }

BOOL_FUNC_PROCESS (ipin)
{

{
const vcs& pi = cast_ref<const vcs>(ipin.peek ());
int corr_r, corr_i;

if ( sync_state == no_energy )
{
// auto-correlation senssing
int iAutoCorr = GetAutoCorrelation ( pi>>2, corr_r, corr_i );
int iEnergy   = GetEnergy ( pi>>2 );

// save sample in the accumulator
sample_his << (pi>>2);

sense_count += 4;

if (
(iEnergy > (int)cca_pwr_threshold) &&
iAutoCorr >= (iEnergy - (iEnergy >> 3)))
{
auto_count++;

// any case we are sensing high, we reset the sense counter
sense_count = 0;

// if remaining in plateau for 4*4=16 samples
if (auto_count >= 4)
{
_dump_text ( "power detected!\n" );

// use cross-correlation to establish sync
if ( establish_sync () ) {
sync_state = high_energy;

high_count = 0;

if ( peak_index > 3 ) {
high_count = peak_index / 4;
peak_index = peak_index & 0x03;
}

// coarse CFO estimation
// Kun: disabled
/*
FP_RAD theta = uatan2 ( corr_i, corr_r );
CFO_est = (theta >> 4);
printf ( "coarse freq offset (%lf) %lfKHz\n",
*/
}
}
}
/*
else if ( sense_count >= max_sense_count && auto_count == 0)
{
// CS timeout
error_code = E_ERROR_CS_TIMEOUT;
ipin.clear();
return true;
}
*/
else
{
auto_count = 0;
}
} else if ( sync_state == high_energy ) {
sample_his << (pi>>2);

high_count ++;

if ( high_count % 4 == 0 ) {
if ( !check_sync ()) {
// cross-correlation peak lost
// if we already have enough peaks found, we mark
// it as the end of STS
if ( high_count > 8 ) {
cca_state = CF_11CCA::power_detected;
RaiseEvent(OnPowerDetected)();

_dump_text ( "CCA done!\n" );
} else {
sync_state = no_energy;
sense_count = 0;
}
}
}
}

// Energy gating - only low power samples pass
if ( sync_state == no_energy ) {
vcs& po = cast_ref<vcs>(opin().append());
po = pi;
Next()->Process(opin());
}

ipin.pop();
}

// now we have processed all data inqueue
if ( sense_count >= max_sense_count && sync_state == no_energy ) {
// CS time out
error_code = E_ERROR_CS_TIMEOUT;
}

return true;
}
};
```

Thank you a lot for your time !

Tuesday, May 26, 2015 2:03 AM