summaryrefslogtreecommitdiff
path: root/cesar/bsu/aclf
diff options
context:
space:
mode:
authorNélio Laranjeiro2011-04-05 10:05:53 +0200
committerNélio Laranjeiro2011-04-14 14:35:15 +0200
commit37dc8a0b61604e61a58f93324536cb895290a910 (patch)
tree4140176d7a0bce55748551b7e5b2c8303100344d /cesar/bsu/aclf
parent8ab970b3c683a24621cab9f81dba46d61e962df1 (diff)
cesar/bsu/aclf: track crossing edge of the power line, refs #2341
This replaces the beacon duration computation by tracking powerline cross
Diffstat (limited to 'cesar/bsu/aclf')
-rw-r--r--cesar/bsu/aclf/aclf.h31
-rw-r--r--cesar/bsu/aclf/doc/Makefile33
-rw-r--r--cesar/bsu/aclf/doc/schema.diabin0 -> 1565 bytes
-rw-r--r--cesar/bsu/aclf/doc/src/pwlsync.tex236
-rw-r--r--cesar/bsu/aclf/src/aclf.c90
-rw-r--r--cesar/bsu/aclf/test/utest/beacon_period.py255
-rw-r--r--cesar/bsu/aclf/test/utest/common.h5
-rw-r--r--cesar/bsu/aclf/test/utest/common.py12
-rw-r--r--cesar/bsu/aclf/test/utest/phy.py61
-rw-r--r--cesar/bsu/aclf/test/utest/src/aclf.c4
-rw-r--r--cesar/bsu/aclf/test/utest/src/bpsd.c197
-rw-r--r--cesar/bsu/aclf/test/utest/src/common.c16
12 files changed, 492 insertions, 448 deletions
diff --git a/cesar/bsu/aclf/aclf.h b/cesar/bsu/aclf/aclf.h
index f1e92315aa..92dc58095e 100644
--- a/cesar/bsu/aclf/aclf.h
+++ b/cesar/bsu/aclf/aclf.h
@@ -29,7 +29,8 @@
enum bsu_aclf_frequency_t
{
BSU_ACLF_FREQ_50HZ,
- BSU_ACLF_FREQ_60HZ
+ BSU_ACLF_FREQ_60HZ,
+ BSU_ACLF_FREQ_NB
};
typedef enum bsu_aclf_frequency_t bsu_aclf_frequency_t;
@@ -55,6 +56,23 @@ typedef enum bsu_aclf_bp_t bsu_aclf_bp_t;
#define BSU_ACLF_60HZ_CLK_MAX_TCK \
BSU_ACLF_BP_60HZ_TCK + BITS_ONES (HPAV_BEACON_BTO_VALID_BITS)
+/** ACLF PowerLine synchronisation information. */
+struct bsu_aclf_pwl_sync_t
+{
+ /** Last power line cross date. */
+ u32 cross_date;
+ /** Last power line cross date estimated. */
+ u32 cross_est_date;
+ /** Filtered Error in ticks. */
+ int w_err_tck;
+ /** Cross interval between two wake ups in ticks. */
+ uint cross_interval_tck;
+ /** Trig PWL crossing present. */
+ bool trig_present;
+ /** Inform the BSU the PLL is initialised. */
+ bool init;
+};
+
/** ACLF context structure. */
struct bsu_aclf_t
{
@@ -90,9 +108,9 @@ struct bsu_aclf_t
*/
s16 bto[HPAV_BEACON_BTO_NB];
/**
- * Last zero_cross read in PRATIC register.
+ * Power Line information synchronisation.
*/
- u32 zero_cross_last_date;
+ struct bsu_aclf_pwl_sync_t pwl_sync;
};
typedef struct bsu_aclf_t bsu_aclf_t;
@@ -217,6 +235,13 @@ bsu_aclf_bpsd_avoid_overlap (bsu_aclf_t *ctx);
void
bsu_aclf_clear (bsu_aclf_t *ctx);
+/**
+ * Track the PowerLine cross date.
+ * \param ctx the module context.
+ */
+void
+bsu_aclf_track_powerline (bsu_aclf_t *ctx);
+
END_DECLS
#endif /* bsu_aclf_aclf_h */
diff --git a/cesar/bsu/aclf/doc/Makefile b/cesar/bsu/aclf/doc/Makefile
new file mode 100644
index 0000000000..2dd565b41e
--- /dev/null
+++ b/cesar/bsu/aclf/doc/Makefile
@@ -0,0 +1,33 @@
+DIA=schema
+DOC=pwlsync
+DIRECTORY=src
+DOCDEPS=src/pwlsync.tex $(DIA:%=%.png)
+TMPDIR=/tmp
+TOC=$(TMPDIR)/$(DOC).toc
+TOCTMP=$(TOC)tmp
+
+OUTPUT=$(DOC:%=%.pdf)
+
+$(OUTPUT): $(DOCDEPS)
+ touch $(TOCTMP)
+ pdflatex -output-directory $(TMPDIR) $<
+ pdflatex -output-directory $(TMPDIR) $< > /dev/null 2>&1
+ while true; \
+ do \
+ if [ `diff -q $(TOCTMP) $(TOC) > /dev/null 2>&1` ]; then \
+ cp $(TOC) $(TOCTMP); \
+ pdflatex -output-directory $(TMPDIR) $<; \
+ else break; \
+ fi; \
+ done;
+ mv $(TMPDIR)/$(OUTPUT) ./
+ rm $(TOCTMP)
+
+clean:
+ rm -rf $(OUTPUT)
+ rm -rf $(DIA:%=%.png)
+
+png: $(DIA:%=%.png)
+
+%.png: %.dia
+ dia -e $@ $<
diff --git a/cesar/bsu/aclf/doc/schema.dia b/cesar/bsu/aclf/doc/schema.dia
new file mode 100644
index 0000000000..6e555e5bba
--- /dev/null
+++ b/cesar/bsu/aclf/doc/schema.dia
Binary files differ
diff --git a/cesar/bsu/aclf/doc/src/pwlsync.tex b/cesar/bsu/aclf/doc/src/pwlsync.tex
new file mode 100644
index 0000000000..e886fc721c
--- /dev/null
+++ b/cesar/bsu/aclf/doc/src/pwlsync.tex
@@ -0,0 +1,236 @@
+\documentclass[a4paper,10pt]{article}
+\usepackage{a4}
+\usepackage[T1]{fontenc}
+\usepackage{amsmath, amsthm}
+\usepackage{amsfonts,amssymb}
+\usepackage{float}
+\usepackage{geometry}
+\usepackage{graphicx}
+\usepackage{graphics}
+\usepackage{fancyhdr}
+\usepackage{fancybox}
+\usepackage{color}
+\usepackage{amsmath}
+\usepackage{amsfonts}
+\usepackage{amssymb}
+\usepackage{amsthm}
+\usepackage{hyperref}
+\usepackage{lscape}
+\usepackage{eurosym}
+\usepackage{endnotes}
+\usepackage{layout}
+\usepackage[utf8]{inputenc}
+
+%==========================MACRO====================================
+
+\def\project{Cesar}
+\def\title{PowerLine synchronisation}
+\def\author{Nélio Laranjeiro}
+\def\keywords{Powerline, SPLL}
+\def\rev{1}
+
+%==========================CONF PDF====================================
+
+\hypersetup{
+backref=true,
+colorlinks=true,
+urlcolor= blue,
+bookmarksopen=true,
+linkcolor= black,
+pdfstartview=FitW,
+pdfkeywords={\keywords},
+pdfsubject={\title},
+pdfauthor={\author},
+pdftitle={\project}, }
+
+%============================script==================================
+
+\floatstyle{ruled}
+\newfloat{Script}{H}{Script_}[subsection]
+
+ \newsavebox{\fmbox}
+ \newenvironment{fmpage}[1]
+{\begin{lrbox}{\fmbox}\begin{minipage}{#1}}
+{\end{minipage}\end{lrbox}\fbox{\usebox{\fmbox}}}
+
+% vertical centering
+\newenvironment{vcenterpage}
+{\newpage\vspace*{\fill}} {\vspace*{\fill}\par\pagebreak}
+
+%==========================Code====================================
+
+\begin{document}
+\parindent 0pt
+
+%==========Page de garde===============
+
+\pagestyle{fancy}
+
+\lhead{\project}
+\chead{\hrule}
+\rhead{\title}
+
+\rfoot{\thepage}
+\cfoot{}
+\lfoot{Revision - \rev \vskip 2pt \hrule}
+
+\renewcommand{\footrulewidth}{0,4pt}
+
+%=============== Guard page =====================
+
+\voffset 1cm
+
+\noindent
+\begin{vcenterpage}
+\begin{minipage}{\textwidth}
+ \flushright
+ \Large
+ \textbf
+ {
+ \project\\
+ \title\\
+ }
+\end{minipage}
+\end{vcenterpage}
+
+\newpage
+
+\newpage
+\tableofcontents
+
+\newpage
+\section{Objective}
+
+\paragraph{PowerLine} synchronisation is a mandatory point in AV
+specification. For that the board received a cross information of a point of
+the PowerLine and set the corresponding date into a register. Software is
+responsible to get this date and compute the beacon period.\\
+
+The main problem is, the date registered by hardware have some jitter, to
+avoid this, a SPLL can be use to track the PowerLine crossing and reduce the
+jitter.
+
+\section {Schematic}
+
+\paragraph {The inputs of the SPLL} are the cross date information of the
+PowerLine set by the register and the cross date estimated by software.\\
+
+\begin{figure}[H]
+ \centering
+ \includegraphics[width=250pt]{schema.png}
+ \caption{Schema of the SPLL implementation.\label{fig1}}
+\end{figure}
+
+\paragraph{Figure 1 \ref{fig1}} represent the schema of the implementation. It
+is based on a SPLL with some blocks.
+
+\paragraph{Input} is the difference between the PowerLine cross date and the
+one simulated by software. See formula \ref{f1}.
+
+\begin{equation}
+ e = pwlcross\_date - pwlcross\_est\_date
+ \label{f1}
+\end{equation}
+
+\paragraph{W} is responsible to filter the error between the PowerLine cross
+measure and the one computed by software.
+
+\begin{equation}
+ w_{n} = \frac{1}{2^{E0}} * e_n + \frac{1}{2^{W0}} * w_{n-1}
+ \label{f2}
+\end{equation}
+
+E0: is a coefficient to keep only a part of the error.\\
+W0: is a coefficient to keep only a part of the history.
+
+\paragraph{NCO} is an adaptation of the estimated cross date to compare the
+same interval of time. For example, if the interval between the cross
+estimated date is twice the interval of the cross date, the NCO will compute
+an estimated cross date on 1 interval of cross i.e.\\
+$\mathrm{cross\ estimated\ date\ nco} = \mathrm{cross\ estimated\ date}_{n-1}
+ + \frac{\mathrm{interval\ cross\ estimated\ date}}{2}$.
+If the interval cross date is equal to estimated one, no adaptation is done.
+
+\newpage
+\section {Algorithm}
+
+\begin{verbatim}
+Constant:
+ // Smooth coefficient for error computation.
+ e0 = 1/2^E0
+ // Smooth coefficient for filtered error.
+ w0 = 1/2^W0
+
+Inputs:
+ // Cross date computed to follow the real cross date.
+ cross_est_date_n1 = cross_est_date
+ // The real cross date.
+ cross_date_n1 = cross_date
+ // The filtered error computed last loop.
+ w_err_tck
+ // Interval between two cross computation, corresponds to a beacon period
+ // when the PLL is stable.
+ interval_tck
+
+Algo:
+ hinterval_tck = interval_tck / 2
+ diff_tck = cross_date - cross_date_n1
+ nb_cross = (diff_tck + hinterval_tck / 2) / hinterval_tck
+ cross_est_date = cross_est_date_n1 + w_err_tck + nb_cross * hinterval_tck
+ error_tck = cross_date - cross_est_date
+ w_err_tck = e0 * error_tck + w0 * w_err_tck
+ cross_interval_tck = cross_interval_tck + w_err_tck
+\end{verbatim}
+
+\newpage
+\section*{References}
+\addcontentsline{toc}{section}{References}
+
+\paragraph {A Software Phase-Locked Loop from Theory to Practice} by\\
+Sithamparanathan Kandeepan.\\
+\url{http://epress.lib.uts.edu.au/dspace/bitstream/handle/2100/100/9_sithamparanathan.pdf?sequence=1}
+
+\newpage
+\listoffigures
+
+%========== Ending page ==============
+
+\newpage
+\thispagestyle{empty} \noindent
+\begin{minipage}{\textwidth}
+ \vskip 2cm
+ \begin{center}
+ \author\\
+
+ \vskip 12pt
+ \textbf{\title}\\
+ \textbf{\project}\\
+
+ \vskip 12pt
+ \textit{Revision - \rev}\\
+ \end{center}
+ \vskip 2cm
+ \underline{Keywords}\\
+ \hrule
+ \vskip 1pt
+ \hrule
+ \vskip 0.2cm
+ \begin{center}
+ \keywords\\
+ \end{center}
+ \vskip 0.2cm
+ \hrule
+ \vskip 1pt
+ \hrule
+ \vskip 3cm
+ \underline{Abstract}\\
+ \vskip 5pt
+ \hrule
+ \vskip 5pt
+ Computation of the beacon period date based on a PLL of the PowerLine
+ crossing.
+ \vskip 5pt
+ \hrule
+\end{minipage}
+
+\end{document}
diff --git a/cesar/bsu/aclf/src/aclf.c b/cesar/bsu/aclf/src/aclf.c
index a5d2b7bb0a..87fa753ab7 100644
--- a/cesar/bsu/aclf/src/aclf.c
+++ b/cesar/bsu/aclf/src/aclf.c
@@ -18,6 +18,11 @@
#include <string.h>
#include "config/aclf.h"
+/** Coefficient to smooth the PowerLine tracking .*/
+#define BSU_ACLF_PWL_E0 6
+/** Coefficient to smooth the PowerLine smoothed error. */
+#define BSU_ACLF_PWL_W0 3
+
/** Store constant values with the frequency detection found. */
#define BSU_ACLF_SET_FREQUENCY(freq) \
do { \
@@ -60,27 +65,32 @@ bsu_aclf_truncate_beacon_period (bsu_aclf_t *ctx)
ctx->beacon_period_tck = clk_min_tck;
}
-/**
- * Compute the beacon period duration from the AC Line frequency variation.
- * \param ctx the module context.
- */
-static void
-bsu_aclf_compute_beacon_period_from_acl (bsu_aclf_t *ctx)
+void
+bsu_aclf_track_powerline (bsu_aclf_t *ctx)
{
- uint zc_interval_tck = ctx->beacon_period_tck / 2;
- u32 zero_cross_date = phy_clock_get_zero_cross_captured_date (ctx->phy);
- u32 zc_diff_tck = zero_cross_date - ctx->zero_cross_last_date;
- if (zc_diff_tck)
+ u32 cross_date = phy_clock_get_zero_cross_captured_date (ctx->phy);
+ if (ctx->pwl_sync.trig_present && ctx->pwl_sync.init)
{
- /* Compute the number of zero cross since the last read value. */
- uint zc_nb =
- (zc_diff_tck + zc_interval_tck / 2) / zc_interval_tck;
- uint bp_tck = 2 * zc_diff_tck / zc_nb;
- ctx->beacon_period_tck +=
- ((int)bp_tck - (int)ctx->beacon_period_tck) >> 4;
- bsu_aclf_truncate_beacon_period (ctx);
- /* Store the last zero crossing date. */
- ctx->zero_cross_last_date = zero_cross_date;
+ uint hinterval_tck = ctx->pwl_sync.cross_interval_tck / 2;
+ uint diff_tck = cross_date - ctx->pwl_sync.cross_date;
+ uint nb_cross = (diff_tck + hinterval_tck / 2) / hinterval_tck;
+ /* Compute the estimated cross. */
+ ctx->pwl_sync.cross_est_date +=
+ ctx->pwl_sync.w_err_tck + nb_cross * hinterval_tck;
+ int err_tck = cross_date - ctx->pwl_sync.cross_est_date;
+ ctx->pwl_sync.w_err_tck =
+ (err_tck >> BSU_ACLF_PWL_E0)
+ + (ctx->pwl_sync.w_err_tck >> BSU_ACLF_PWL_W0);
+ ctx->pwl_sync.cross_date = cross_date;
+ ctx->pwl_sync.cross_interval_tck += ctx->pwl_sync.w_err_tck;
+ }
+ else
+ {
+ /* Simply initialise the PLL for the next step. */
+ ctx->pwl_sync.cross_date = cross_date;
+ ctx->pwl_sync.cross_est_date = cross_date;
+ ctx->pwl_sync.w_err_tck = 0;
+ ctx->pwl_sync.init = true;
}
}
@@ -104,15 +114,19 @@ bsu_aclf_ac_compute_beacon_period_start_date (bsu_aclf_t *ctx)
{
dbg_assert (ctx);
uint i;
- u32 now = phy_date ();
u32 bts;
int bto;
- bsu_aclf_compute_beacon_period_from_acl (ctx);
+ if (ctx->pwl_sync.trig_present)
+ ctx->beacon_period_tck = ctx->pwl_sync.cross_interval_tck;
+ bsu_aclf_truncate_beacon_period (ctx);
/* First time the function is called. */
if (ctx->bpsd[0] == ctx->bpsd[1])
{
- ctx->bpsd[0] = now;
+ if (ctx->pwl_sync.trig_present)
+ ctx->bpsd[0] = ctx->pwl_sync.cross_est_date;
+ else
+ ctx->bpsd[0] = phy_date ();
for (i = 1; i < BSU_ACLF_BPSD_NB; i++)
ctx->bpsd[i] = ctx->bpsd[i-1] + ctx->beacon_period_tck;
}
@@ -123,7 +137,24 @@ bsu_aclf_ac_compute_beacon_period_start_date (bsu_aclf_t *ctx)
ctx->bpsd[i] = ctx->bpsd[i+1];
/* Add on the last beacon period start date the beacon period
* estimated. */
- ctx->bpsd[BSU_ACLF_BPSD_NB - 1] += ctx->beacon_period_tck;
+ if (ctx->beacon_period_tck == ctx->pwl_sync.cross_interval_tck)
+ {
+ uint pwl_cross_tck = ctx->beacon_period_tck / 2;
+ u32 bpsd_last = ctx->pwl_sync.cross_est_date
+ + (BSU_ACLF_BPSD_NB - 1) * ctx->beacon_period_tck;
+ /* BPSD last must be at least a beacon period after the previous
+ * computed beacon period start date. */
+ u32 bpsd_cmp = ctx->bpsd[BSU_ACLF_BPSD_NB - 2]
+ + ctx->beacon_period_theo_tck
+ - BITS_ONES (HPAV_BEACON_BTO_VALID_BITS);
+ /* Confirm than bpsd_last is after the previous beacon period
+ * start date. */
+ while (lesseq_mod2p32 (bpsd_last, bpsd_cmp))
+ bpsd_last += pwl_cross_tck;
+ ctx->bpsd[BSU_ACLF_BPSD_NB - 1] = bpsd_last;
+ }
+ else
+ ctx->bpsd[BSU_ACLF_BPSD_NB - 1] += ctx->beacon_period_tck;
}
/* Compute the BTO using the theoretical beacon period value.
* BTO is computed from bpsd[1]. */
@@ -168,10 +199,19 @@ bsu_aclf_acl_frequency_detection (bsu_aclf_t *ctx)
}
/* Protection for Malika DK without trig 50Hz. */
if (!sum)
+ {
+ ctx->pwl_sync.trig_present = false;
ctx->beacon_period_tck = BSU_ACLF_BP_50HZ_TCK;
+ }
else
+ {
ctx->beacon_period_tck = 2 * (sum / nb);
- ctx->zero_cross_last_date = cross_new_date;
+ ctx->pwl_sync.trig_present = true;
+ ctx->pwl_sync.init = false;
+ ctx->pwl_sync.cross_interval_tck =
+ ctx->beacon_period_tck = 2 * (sum / nb);
+ ctx->pwl_sync.cross_est_date = cross_new_date;
+ }
}
if (ctx->beacon_period_tck == 0
|| ctx->beacon_period_tck >= BSU_ACLF_BP_55HZ_TCK)
@@ -190,7 +230,7 @@ bsu_aclf_clear (bsu_aclf_t *ctx)
ctx->beacon_period_tck = ctx->beacon_period_theo_tck;
for (i = 0; i < COUNT (ctx->bto); i++)
ctx->bto[i] = 0;
- ctx->zero_cross_last_date = 0;
+ ctx->pwl_sync.init = false;
}
/**
diff --git a/cesar/bsu/aclf/test/utest/beacon_period.py b/cesar/bsu/aclf/test/utest/beacon_period.py
deleted file mode 100644
index 238072439c..0000000000
--- a/cesar/bsu/aclf/test/utest/beacon_period.py
+++ /dev/null
@@ -1,255 +0,0 @@
-#!/usr/bin/python
-
-#############################################################################
-# Copyright (C) 2011 Spidcom
-#
-# This script simulates a PowerLine frequency change.
-#
-# Frequency in Europe can go from 42.5Hz to 57.5Hz.
-# In US it can go from 51 to 69Hz.
-# To keep a good synchronisation and BTO computation value,
-# under 55Hz, 50Hz should be chose, 60Hz when frequency is greater.
-#
-# HomePlug AV only supports a small range of variation on the PowerLine which
-# is provided by the BTOs with the central beacon. Those BTOs are a signed
-# 16bits values with 0x8000 reserved for invalid value.
-# The station computes the next beacon periods from the BTS and the BTOs with
-# the following formulae.
-# bpsd_n = bpsd_{n-1} + beacon_period_theoretical_tck + bto_n
-# bpsd_n is the next beacon period start date.
-# beacon_period_theoretical is the beacon period in ticks corresponding to 50
-# or 60Hz.
-# Knowing this the station is only able to synchronise if the variation is in
-# a small range i.e beacon_period_theoretical_tck +/- 0x7fff.
-#
-# For 50Hz the maximum delta 1.0e6 +/- 32567, so 48.42Hz to 51.68Hz.
-# For 60Hz the maximum delta 833333 +/- 32567, so 57.74Hz to 62.44Hz.
-#
-#############################################################################
-
-import sys
-from phy import Phy
-from common import MAC_MS_TO_TCK
-
-CLOCK_50HZ_TCK = 1000000
-CLOCK_55HZ_TCK = 909090
-CLOCK_60HZ_TCK = 833333
-
-CLOCK_50HZ_MIN_TCK = CLOCK_50HZ_TCK - 0x7fff
-CLOCK_50HZ_MAX_TCK = CLOCK_50HZ_TCK + 0x7fff
-
-CLOCK_60HZ_MIN_TCK = CLOCK_60HZ_TCK - 0x7fff
-CLOCK_60HZ_MAX_TCK = CLOCK_60HZ_TCK + 0x7fff
-
-class BsuAclf:
- """Python BSU ACLF class."""
-
- def __init__ (self, phy):
- """Initialise the class."""
- self.phy = phy
- self.frequency_theo_hz = 0
- self.beacon_period_theo_tck = 0
- self.beacon_period_tck = 0
- self.zero_cross_last_read_date = 0
-
- def __beacon_period_fit_bto_range (self):
- """Truncate value to have a beacon period which can fit in the BTO
- range value."""
- if self.beacon_period_tck > self.beacon_period_theo_tck + 0x7fff:
- self.beacon_period_tck = self.beacon_period_theo_tck + 0x7fff
- elif self.beacon_period_tck < self.beacon_period_theo_tck - 0x7fff:
- self.beacon_period_tck = self.beacon_period_theo_tck - 0x7fff
-
- def frequency_detection (self):
- """Try to find at what frequency the medium is at.
- phy: phy class initialised.
- """
- zero_cross_tck = self.phy.zero_crossing ()
- zero_cross_new_tck = zero_cross_tck
- now = self.phy.date ()
- wait_until = now + MAC_MS_TO_TCK (50)
- while self.phy.date () < wait_until \
- and zero_cross_new_tck == zero_cross_tck:
- zero_cross_new_tck = self.phy.zero_crossing ()
- # this line should not be implemented in C.
- self.phy.clock (1000)
- diff_zc_tck = zero_cross_new_tck - zero_cross_tck
- self.beacon_period_tck = 2 * diff_zc_tck
- if self.beacon_period_tck >= CLOCK_55HZ_TCK \
- or diff_zc_tck == 0:
- self.frequency_theo_hz = 50
- self.beacon_period_theo_tck = CLOCK_50HZ_TCK
- self.zero_cross_last_read_date = zero_cross_new_tck
- self.__beacon_period_fit_bto_range ()
- return self.frequency_theo_hz
- else:
- self.frequency_theo_hz = 60
- self.beacon_period_theo_tck = CLOCK_60HZ_TCK
- self.zero_cross_last_read_date = zero_cross_new_tck
- self.__beacon_period_fit_bto_range ()
- return self.frequency_theo_hz
-
- def compute_beacon_period (self):
- """Compute the beacon period using the phy class."""
- zc_interval_tck = self.beacon_period_tck / 2
- zero_cross_date = self.phy.zero_crossing ()
- zc_diff_tck = zero_cross_date - self.zero_cross_last_read_date
- if zc_diff_tck:
- zc_nb = (zc_diff_tck + zc_interval_tck / 2) \
- / zc_interval_tck
- bp_tck = 2 * zc_diff_tck / zc_nb
- self.zero_cross_last_read_date = zero_cross_date
- self.beacon_period_tck += \
- int (0.0625 * (bp_tck - self.beacon_period_tck))
- self.__beacon_period_fit_bto_range ()
- return self.beacon_period_tck
-
-if __name__ == '__main__':
- import unittest
-
- class TestBeaconPeriod(unittest.TestCase):
- def setUp (self):
- pass
- def tearDown (self):
- pass
-
- def verify_beacon_period (self, bsuaclf, frequency):
- """Verify the beacon period estimated is correct.
- """
- # powerline_cycle_tck = 25.0e6 * 1/F = 25.0e6 / F
- # beacon_period_tck = 2 * powerline_cycle_tck
- diff = int (50.0e6 / frequency) - bsuaclf.beacon_period_tck
- if bsuaclf.frequency_theo_hz == 50:
- self.failUnless (\
- bsuaclf.beacon_period_tck == CLOCK_50HZ_MIN_TCK \
- or bsuaclf.beacon_period_tck == CLOCK_50HZ_MAX_TCK \
- or (diff >= -25 and diff <= 25) \
- )
- else:
- self.failUnless (\
- bsuaclf.beacon_period_tck == CLOCK_60HZ_MIN_TCK \
- or bsuaclf.beacon_period_tck == CLOCK_60HZ_MAX_TCK \
- or (diff >= -25 and diff <= 25) \
- )
-
- def test_frequency_detection (self):
- """test the frequency detection for from 42.5 to 69Hz.
- Result expected is a detected medium frequency at:
- - 50Hz for frequency from 42.5 to 54.2Hz.
- - 60Hz for frequency from 54.3 to 69Hz.
- """
- # Xrange does not support floating points, so frequencies to tests
- # are multiplied by 10.
- for f in xrange (425, 690):
- frequency = (f + 0.0) / 10
- p = Phy (frequency)
- ba = BsuAclf (p)
- res = ba.frequency_detection ()
- self.failUnless ((frequency <= 55.0 and res == 50)
- or (frequency > 55 and res == 60))
- self.verify_beacon_period (ba, frequency)
-
- def test_estimate_beacon_period (self):
- """Test the algorithm for beacon period estimation.
- Should test the beacon period computation for each possible
- frequency. The beacon period is not just twice the period of the
- powerline, it is smoothed with the previous beacon period and the
- one computed using two powerline zero cross.
- """
- for f in xrange (425, 690):
- frequency = (f + 0.0) / 10
- p = Phy (frequency)
- ba = BsuAclf (p)
- ba.frequency_detection ()
- # current beacon period.
- for i in xrange (0, 10):
- # Give some clocks ticks.
- p.clock (ba.beacon_period_tck)
- ba.compute_beacon_period ()
- self.verify_beacon_period (ba, frequency)
-
- def frequency_variation (self, freq, step = 0.1, inc = True):
- """Make the frequency increase or decrease during the test.
- freq: Initial frequency (float value) [42.5, 69].
- step: Increase or decrease step (float value).
- inc: True to increase frequency, false otherwise.
- """
- p = Phy (freq)
- ba = BsuAclf (p)
- ba.frequency_detection ()
- if inc:
- while ((p.frequency () <= 69.0
- and ba.frequency_theo_hz == 60)
- or (p.frequency () <= 57.5
- and ba.frequency_theo_hz == 50)):
- for i in xrange (0, 100):
- # give some clocks ticks.
- p.clock (ba.beacon_period_tck)
- ba.compute_beacon_period ()
- self.verify_beacon_period (ba, p.frequency ())
- p.frequency_inc (step)
- else:
- while ((p.frequency () >= 42.5
- and ba.frequency_theo_hz == 50)
- or (p.frequency () >= 51.0
- and ba.frequency_theo_hz == 60)):
- for i in xrange (0, 100):
- # give some clocks ticks.
- p.clock (ba.beacon_period_tck)
- ba.compute_beacon_period ()
- self.verify_beacon_period (ba, p.frequency ())
- p.frequency_dec (step)
-
- def test_estimate_beacon_period_frequency_increase (self):
- """Test the beacon period computation with a frequency which
- increase by 0.1 Hz each 100 beacon periods.
- """
- self.frequency_variation (42.5)
- self.frequency_variation (57.0)
-
- def test_estimate_beacon_period_frequency_deacrease (self):
- """Test the beacon period computation with a frequency which
- decrease by 0.1 Hz each 100 beacon periods.
- """
- self.frequency_variation (69, inc = False)
- self.frequency_variation (55.0, inc = False)
-
- def estimate_beacon_period_frequency_inc_and_dec (self, freq,
- step = 0.1):
- p = Phy (freq)
- ba = BsuAclf (p)
- ba.frequency_detection ()
- while ((p.frequency () <= 69.0
- and ba.frequency_theo_hz == 60)
- or (p.frequency () <= 57.5
- and ba.frequency_theo_hz == 50)):
- for i in xrange (0, 100):
- # give some clocks ticks.
- p.clock (ba.beacon_period_tck)
- beacon_period_tck = ba.compute_beacon_period ()
- self.verify_beacon_period (ba, p.frequency ())
- p.frequency_inc (0.1)
- while ((p.frequency () >= 42.5
- and ba.frequency_theo_hz == 50)
- or (p.frequency () >= 51.0
- and ba.frequency_theo_hz == 60)):
- for i in xrange (0, 100):
- # give some clocks ticks.
- p.clock (ba.beacon_period_tck)
- beacon_period_tck = ba.compute_beacon_period ()
- self.verify_beacon_period (ba, p.frequency ())
- p.frequency_dec (0.1)
-
- def test_estimate_beacon_period_frequency_inc_and_dec (self):
- """Test the beacon period computation with a frequency which
- increase by 0.1 Hz each 100 beacon periods. It will restart just
- after with a decrease of 0.1 Hz each 100 beacons.
- """
- self.estimate_beacon_period_frequency_inc_and_dec (42.5)
- self.estimate_beacon_period_frequency_inc_and_dec (55.1)
-
- # Start the unit test.
- suite = unittest.TestLoader().loadTestsFromTestCase(TestBeaconPeriod)
- testResult = unittest.TextTestRunner(verbosity=2).run(suite)
-# For nightly build errors
-sys.exit ((1, 0)[testResult.wasSuccessful ()])
diff --git a/cesar/bsu/aclf/test/utest/common.h b/cesar/bsu/aclf/test/utest/common.h
index 10e360fe61..f8cad070e7 100644
--- a/cesar/bsu/aclf/test/utest/common.h
+++ b/cesar/bsu/aclf/test/utest/common.h
@@ -13,6 +13,7 @@
* \ingroup bsu_aclf
*/
#include "bsu/aclf/aclf.h"
+#include "lib/rnd.h"
struct bsu_aclf_test_phy_t
{
@@ -25,6 +26,10 @@ struct bsu_aclf_test_phy_t
/** False to use phy clock function to make time goes on,
* or false to increase time by 1000 ticks on phy_date function call. */
bool use_phy_clock;
+ /** True to use a random jitter, false otherwise. */
+ bool use_jitter;
+ /** Add random. */
+ lib_rnd_t rnd;
};
typedef struct bsu_aclf_test_phy_t bsu_aclf_test_phy_t;
diff --git a/cesar/bsu/aclf/test/utest/common.py b/cesar/bsu/aclf/test/utest/common.py
deleted file mode 100644
index 0cb0c607cb..0000000000
--- a/cesar/bsu/aclf/test/utest/common.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/python
-
-#############################################################################
-# Copyright (C) 2011 Spidcom
-#
-# Common function to unit tests.
-#############################################################################
-
-def MAC_MS_TO_TCK(ms):
- """Convert a ms time into tcks."""
- MAC_TCK_PER_US = 25
- return int ((ms) * MAC_TCK_PER_US * 1000)
diff --git a/cesar/bsu/aclf/test/utest/phy.py b/cesar/bsu/aclf/test/utest/phy.py
deleted file mode 100644
index 353f909bd5..0000000000
--- a/cesar/bsu/aclf/test/utest/phy.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/python
-
-#############################################################################
-# Copyright (C) 2011 Spidcom
-#
-# Phy class with necessary function to simulate the phy for ACLF.
-#############################################################################
-
-class Phy:
- """Class phy containing some functions to simulate the Phy on Cesar."""
-
- def __init__ (self, frequency):
- """Initialise the phy class.
- - frequency: the frequency to use with the test.
- """
- self.__frequency = frequency
- self.__date_tck = 0
- self.__zero_crossing_tck = 0
-
- def zero_cross_interval (self):
- """Compute the zero cross interval corresponding to the current
- frequency."""
- return int (25.0e6 / self.__frequency)
-
- def zero_crossing (self):
- """Get the phy last crossing date.
- This function should return a phy crossing date in ticks.
- """
- return self.__zero_crossing_tck
-
- def frequency_inc (self, val_hz):
- """Increase frequency.
- val: the value to increase in hertz."""
- self.__frequency += val_hz
-
- def frequency_dec (self, val_hz):
- """Decrease frequency.
- val: the value to decrease in hertz."""
- self.__frequency -= val_hz
- if self.__frequency < 0:
- self.__frequency = 0
-
- def frequency (self):
- """Return the current frequency of the medium."""
- return self.__frequency
-
- def date (self):
- """Get the current phy date."""
- return self.__date_tck
-
- def clock (self, tck):
- """Make time goes on.
- - tck: increase time of tck ticks."""
- self.__date_tck += tck
- zc_interval_tck = self.zero_cross_interval ()
- zc_nb_interval_since_last_tck = \
- (self.__date_tck - self.__zero_crossing_tck) \
- / zc_interval_tck
- zc_next_tck = self.__zero_crossing_tck \
- + zc_nb_interval_since_last_tck * zc_interval_tck
- self.__zero_crossing_tck = zc_next_tck
diff --git a/cesar/bsu/aclf/test/utest/src/aclf.c b/cesar/bsu/aclf/test/utest/src/aclf.c
index 3250444d66..763a0886df 100644
--- a/cesar/bsu/aclf/test/utest/src/aclf.c
+++ b/cesar/bsu/aclf/test/utest/src/aclf.c
@@ -18,7 +18,7 @@ void
test_suite_aclf__frequency (test_t t);
void
-test_suite_aclf__bpsd_accurate (test_t t);
+test_suite_aclf__track_powerline (test_t t);
int
main (int argc, char **argv)
@@ -27,7 +27,7 @@ main (int argc, char **argv)
test_init (test, argc, argv);
lib_stats_init ();
test_suite_aclf__frequency (test);
- test_suite_aclf__bpsd_accurate (test);
+ test_suite_aclf__track_powerline (test);
lib_stats_uninit ();
test_result (test);
return test_nb_failed (test) == 0 ? 0 : 1;
diff --git a/cesar/bsu/aclf/test/utest/src/bpsd.c b/cesar/bsu/aclf/test/utest/src/bpsd.c
index b524ddfe9e..491c3c9d56 100644
--- a/cesar/bsu/aclf/test/utest/src/bpsd.c
+++ b/cesar/bsu/aclf/test/utest/src/bpsd.c
@@ -13,126 +13,149 @@
#include "common/std.h"
#include "lib/test.h"
#include "common.h"
+#include <string.h>
void
-bsu_aclf_acl_frequency_detection (bsu_aclf_t *ctx);
-
-void
-bsu_aclf_ac_compute_beacon_period_start_date (bsu_aclf_t *ctx);
-
-void
-bsu_aclf_shift_beacon_period_start_date (bsu_aclf_t *ctx);
-
-void
-test_case_aclf_compute_bto (test_t t)
+test_case_powerline_stable_common (test_t t, bsu_aclf_frequency_t freq)
{
- test_case_begin (t, "BTO computation");
- uint f, i;
- float frequency;
+ uint i, interval_tck = 0;
+ char text[30];
bsu_aclf_test_t ctx;
- test_begin (t, "Test beacon period date and BTO")
+ bsu_aclf_test_init (&ctx);
+ ctx.aclf->pwl_sync.trig_present = true;
+ if (freq == BSU_ACLF_FREQ_50HZ)
+ {
+ ctx.phy->frequency_hz = 50.0;
+ interval_tck = BSU_ACLF_BP_50HZ_TCK;
+ ctx.aclf->pwl_sync.cross_interval_tck = BSU_ACLF_BP_50HZ_TCK;
+ strcpy (text, "50 Hz PowerLine crossing\0");
+ }
+ else
+ {
+ ctx.phy->frequency_hz = 60.0;
+ interval_tck = BSU_ACLF_BP_60HZ_TCK;
+ ctx.aclf->pwl_sync.cross_interval_tck = BSU_ACLF_BP_60HZ_TCK;
+ strcpy (text, "60 Hz PowerLine crossing\0");
+ }
+ test_begin (t , text)
{
- for (f = 425; f < 691; f++)
+ for (i = 0; i < 30000; i++)
{
- bsu_aclf_test_init (&ctx);
- frequency = (float) f / 10;
- ctx.phy->frequency_hz = frequency;
- bsu_aclf_acl_frequency_detection (ctx.aclf);
- bsu_aclf_ac_compute_beacon_period_start_date (ctx.aclf);
- for (i = 1; i < BSU_ACLF_BPSD_NB; i++)
- test_fail_unless (ctx.aclf->bpsd[i] != ctx.aclf->bpsd[i-1]);
- for (i = 0; i < HPAV_BEACON_BTO_NB; i++)
- test_fail_unless (
- ctx.aclf->bto[i] != HPAV_BEACON_BTO_INVALID);
- bsu_aclf_test_uninit (&ctx);
+ phy_clock (ctx.phy, interval_tck);
+ bsu_aclf_track_powerline (ctx.aclf);
+ /* With a stable PowerLine the error must be 0. */
+ test_fail_unless (ctx.aclf->pwl_sync.init);
+ test_fail_unless (ctx.aclf->pwl_sync.cross_date
+ == ctx.aclf->pwl_sync.cross_est_date);
+ test_fail_unless (ctx.aclf->pwl_sync.w_err_tck == 0);
}
}
test_end;
+ bsu_aclf_test_uninit (&ctx);
}
-/**
- * Test BPSD computation from PowerLine and beacon reception.
- * \param t the test context.
- * \param frequency multiplied by 10 to avoid rounded values.
- */
void
-test_case_aclf_shift_bpsd_freq (test_t t, uint frequency)
+test_case_powerline_stable (test_t t)
{
- test_within (t);
+ test_case_begin (t, "PowerLine stable no jitter");
uint i;
- u32 ntb_offset_tck = 1000;
+ for (i = 0; i < BSU_ACLF_FREQ_NB; i++)
+ test_case_powerline_stable_common (t, i);
+}
+
+void
+test_case_powerline_unstable_common (test_t t, bsu_aclf_frequency_t freq)
+{
+ uint i, interval_tck = 0;
+ char text[30];
bsu_aclf_test_t ctx;
bsu_aclf_test_init (&ctx);
- ctx.phy->frequency_hz = (float) frequency / 10;
- bsu_aclf_acl_frequency_detection (ctx.aclf);
- uint beacon_period_cmp_tck = 50.0e6 / ((float) frequency / 10);
- s16 bto[] = {0, 0, 0, 0};
- /* Truncate the beacon period comparison. */
- if (ctx.aclf->frequency == BSU_ACLF_FREQ_50HZ)
+ ctx.aclf->pwl_sync.trig_present = true;
+ if (freq == BSU_ACLF_FREQ_50HZ)
{
- if (beacon_period_cmp_tck < BSU_ACLF_50HZ_CLK_MIN_TCK)
- beacon_period_cmp_tck = BSU_ACLF_50HZ_CLK_MIN_TCK;
- else if (beacon_period_cmp_tck > BSU_ACLF_50HZ_CLK_MAX_TCK)
- beacon_period_cmp_tck = BSU_ACLF_50HZ_CLK_MAX_TCK;
+ ctx.phy->frequency_hz = 50.0;
+ ctx.aclf->pwl_sync.cross_interval_tck = BSU_ACLF_BP_50HZ_TCK;
+ interval_tck = BSU_ACLF_BP_50HZ_TCK;
+ strcpy (text, "50 Hz PowerLine crossing\0");
}
else
{
- if (beacon_period_cmp_tck < BSU_ACLF_60HZ_CLK_MIN_TCK)
- beacon_period_cmp_tck = BSU_ACLF_60HZ_CLK_MIN_TCK;
- else if (beacon_period_cmp_tck > BSU_ACLF_60HZ_CLK_MAX_TCK)
- beacon_period_cmp_tck = BSU_ACLF_60HZ_CLK_MAX_TCK;
- }
- bsu_aclf_ac_compute_beacon_period_start_date (ctx.aclf);
- bsu_aclf_shift_beacon_period_start_date (ctx.aclf);
- for (i = 1; i < BSU_ACLF_BPSD_NB; i++)
- {
- test_fail_unless (
- less_mod2p32 (ctx.aclf->bpsd[i-1], ctx.aclf->bpsd[i]));
- int diff_tck =
- beacon_period_cmp_tck - (ctx.aclf->bpsd[i] - ctx.aclf->bpsd[i-1]);
- test_fail_unless (diff_tck <= 1 && diff_tck >= -1);
- }
- /* Compare BTOs. */
- for (i = 0; i < HPAV_BEACON_BTO_NB; i++)
- {
- bto[i] = beacon_period_cmp_tck -
- ctx.aclf->beacon_period_theo_tck;
- int bto_diff = ctx.aclf->bto[i] - bto[i];
- test_fail_unless (bto_diff >= -1 && bto_diff <= 1);
+ ctx.phy->frequency_hz = 60.0;
+ ctx.aclf->pwl_sync.cross_interval_tck = BSU_ACLF_BP_60HZ_TCK;
+ interval_tck = BSU_ACLF_BP_60HZ_TCK;
+ strcpy (text, "60 Hz PowerLine crossing\0");
}
- /* Compute the next beacon period using a received information
- * from the beacon. */
- u32 bts = ctx.aclf->bpsd[1] + ntb_offset_tck;
- bsu_aclf_compute_beacon_period_start_date (
- ctx.aclf, bts, bto, 0, ntb_offset_tck);
- ctx.aclf->bpsd[0] = bts - ntb_offset_tck;
- for (i = 1; i < BSU_ACLF_BPSD_NB - 1; i++)
+ ctx.phy->use_jitter = true;
+ test_begin (t , text)
{
- u32 diff_tck = ctx.aclf->bpsd[i] - ctx.aclf->bpsd[i-1];
- test_fail_unless (diff_tck == beacon_period_cmp_tck,
- "Frequency %d diff_tck %d",
- frequency, diff_tck);
+ for (i = 0; i < BITS_ONES (16); i++)
+ {
+ phy_clock (ctx.phy, interval_tck);
+ bsu_aclf_track_powerline (ctx.aclf);
+ test_fail_unless (ctx.aclf->pwl_sync.init);
+ if (i == 0)
+ {
+ test_fail_unless (ctx.aclf->pwl_sync.cross_date
+ == ctx.aclf->pwl_sync.cross_est_date);
+ test_fail_unless (ctx.aclf->pwl_sync.w_err_tck == 0);
+ }
+ else
+ {
+ test_fail_unless ((uint) ABS (ctx.aclf->pwl_sync.w_err_tck)
+ < (interval_tck >> 8));
+ }
+ }
+ test_fail_unless ((uint) ABS (ctx.aclf->pwl_sync.w_err_tck)
+ < (interval_tck >> 8));
}
+ test_end;
bsu_aclf_test_uninit (&ctx);
}
void
-test_case_aclf_shift_bpsd (test_t t)
+test_case_powerline_unstable (test_t t)
+{
+ test_case_begin (t, "PowerLine with jitter");
+ uint i;
+ for (i = 0; i < BSU_ACLF_FREQ_NB; i++)
+ test_case_powerline_unstable_common (t, i);
+}
+
+
+void
+test_case_bpsd_ac_compute (test_t t)
{
- uint f;
- test_case_begin (t, "Shift bpsd");
- test_begin (t, "shift")
+ test_case_begin (t, "Compute BPSD when tracking is before the last BPSD");
+ test_begin (t, "Trigger")
{
- for (f = 425; f < 691; f++)
- test_case_aclf_shift_bpsd_freq (t, f);
+ bsu_aclf_test_t ctx;
+ bsu_aclf_test_init (&ctx);
+ /* Trigger is not present to allow a simple zero cross date diving. */
+ ctx.aclf->pwl_sync.trig_present = false;
+ ctx.phy->frequency_hz = 50.0;
+ *((u32*)&ctx.aclf->beacon_period_theo_tck) = BSU_ACLF_BP_50HZ_TCK;
+ ctx.aclf->pwl_sync.cross_interval_tck = BSU_ACLF_BP_50HZ_TCK;
+ uint i;
+ for (i = 0; i < BSU_ACLF_BPSD_NB; i++)
+ ctx.aclf->bpsd[i] = i * BSU_ACLF_BP_50HZ_TCK;
+ /* This will cause the ACLF to delay the last bpsd. */
+ ctx.aclf->pwl_sync.cross_est_date = ctx.aclf->bpsd[0] - 500000;
+ ctx.aclf->pwl_sync.cross_interval_tck = BSU_ACLF_BP_50HZ_TCK;
+ /* Request a computation. */
+ bsu_aclf_ac_compute_beacon_period_start_date (ctx.aclf);
+ for (i = 0; i < BSU_ACLF_BPSD_NB - 1; i++)
+ test_fail_unless (less_mod2p32 (ctx.aclf->bpsd[i],
+ ctx.aclf->bpsd[i+1]));
+ bsu_aclf_test_uninit (&ctx);
}
test_end;
}
void
-test_suite_aclf__bpsd_accurate (test_t t)
+test_suite_aclf__track_powerline (test_t t)
{
- test_suite_begin (t, "Beacon Period Start Date accurate");
- test_case_aclf_compute_bto (t);
- test_case_aclf_shift_bpsd (t);
+ test_suite_begin (t, "Track PowerLine");
+ test_case_powerline_stable (t);
+ test_case_powerline_unstable (t);
+ test_case_bpsd_ac_compute (t);
}
diff --git a/cesar/bsu/aclf/test/utest/src/common.c b/cesar/bsu/aclf/test/utest/src/common.c
index 9792faf9a6..8c42b4fce7 100644
--- a/cesar/bsu/aclf/test/utest/src/common.c
+++ b/cesar/bsu/aclf/test/utest/src/common.c
@@ -25,7 +25,9 @@ bsu_aclf_test_init (bsu_aclf_test_t *t)
memset (&phy_test_global, 0, sizeof (bsu_aclf_test_phy_t));
t->aclf = bsu_aclf_init ((phy_t *) &phy_test_global, &t->mac_config);
phy_test_global.use_phy_clock = true;
+ phy_test_global.use_jitter = false;
t->phy = &phy_test_global;
+ lib_rnd_init (&t->phy->rnd, 0x234457);
}
void
@@ -49,9 +51,17 @@ phy_clock (bsu_aclf_test_phy_t *ctx, u32 ticks)
uint zc_nb_interval_since_last_date =
(ctx->phy_date - ctx->zero_crossing_date)
/ zc_interval_tck;
- u32 zc_next_date = ctx->zero_crossing_date
- + zc_nb_interval_since_last_date * zc_interval_tck;
- ctx->zero_crossing_date = zc_next_date;
+ if (ctx->use_jitter)
+ {
+ int jitter =
+ lib_rnd_uniform (&ctx->rnd, zc_interval_tck / 3);
+ ctx->zero_crossing_date = ctx->phy_date - jitter;
+ }
+ else
+ {
+ ctx->zero_crossing_date = ctx->zero_crossing_date
+ + zc_nb_interval_since_last_date * zc_interval_tck;
+ }
}
u32