mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-19 20:46:22 +00:00
ptp: Add median based pre-filtering of delays
If the delay measurement is too far away from the median of the window of last delay measurements, we discard it. This increases accuracy on wifi a lot. https://bugzilla.gnome.org/show_bug.cgi?id=749391
This commit is contained in:
parent
02ba5b20c7
commit
ac2eb6e23e
1 changed files with 63 additions and 0 deletions
|
@ -106,6 +106,13 @@ GST_DEBUG_CATEGORY_STATIC (ptp_debug);
|
||||||
*/
|
*/
|
||||||
#define USE_ONLY_SYNC_WITH_DELAY 1
|
#define USE_ONLY_SYNC_WITH_DELAY 1
|
||||||
|
|
||||||
|
/* Filter out delay measurements that are too far away from the median of the
|
||||||
|
* last delay measurements, currently those that are more than 2 times as big.
|
||||||
|
* This increases accuracy a lot on wifi.
|
||||||
|
*/
|
||||||
|
#define USE_MEDIAN_PRE_FILTERING 1
|
||||||
|
#define MEDIAN_PRE_FILTERING_WINDOW 9
|
||||||
|
|
||||||
/* How many updates should be skipped at maximum when using USE_MEASUREMENT_FILTERING */
|
/* How many updates should be skipped at maximum when using USE_MEASUREMENT_FILTERING */
|
||||||
#define MAX_SKIPPED_UPDATES 5
|
#define MAX_SKIPPED_UPDATES 5
|
||||||
|
|
||||||
|
@ -306,6 +313,9 @@ typedef struct
|
||||||
GstClockTime last_delay_req, min_delay_req_interval;
|
GstClockTime last_delay_req, min_delay_req_interval;
|
||||||
guint16 last_delay_req_seqnum;
|
guint16 last_delay_req_seqnum;
|
||||||
|
|
||||||
|
GstClockTime last_path_delays[MEDIAN_PRE_FILTERING_WINDOW];
|
||||||
|
gint last_path_delays_missing;
|
||||||
|
|
||||||
GQueue pending_syncs;
|
GQueue pending_syncs;
|
||||||
|
|
||||||
GstClock *domain_clock;
|
GstClock *domain_clock;
|
||||||
|
@ -770,6 +780,7 @@ select_best_master_clock (PtpDomainData * domain, GstClockTime now)
|
||||||
sizeof (PtpClockIdentity));
|
sizeof (PtpClockIdentity));
|
||||||
domain->mean_path_delay = 0;
|
domain->mean_path_delay = 0;
|
||||||
domain->last_delay_req = 0;
|
domain->last_delay_req = 0;
|
||||||
|
domain->last_path_delays_missing = 9;
|
||||||
domain->min_delay_req_interval = 0;
|
domain->min_delay_req_interval = 0;
|
||||||
domain->sync_interval = 0;
|
domain->sync_interval = 0;
|
||||||
domain->last_ptp_sync_time = 0;
|
domain->last_ptp_sync_time = 0;
|
||||||
|
@ -834,6 +845,7 @@ handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
|
||||||
g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
|
g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
|
||||||
g_free (clock_name);
|
g_free (clock_name);
|
||||||
g_queue_init (&domain->pending_syncs);
|
g_queue_init (&domain->pending_syncs);
|
||||||
|
domain->last_path_delays_missing = 9;
|
||||||
domain_data = g_list_prepend (domain_data, domain);
|
domain_data = g_list_prepend (domain_data, domain);
|
||||||
|
|
||||||
g_mutex_lock (&domain_clocks_lock);
|
g_mutex_lock (&domain_clocks_lock);
|
||||||
|
@ -1230,9 +1242,27 @@ out:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_MEDIAN_PRE_FILTERING
|
||||||
|
static gint
|
||||||
|
compare_clock_time (const GstClockTime * a, const GstClockTime * b)
|
||||||
|
{
|
||||||
|
if (*a < *b)
|
||||||
|
return -1;
|
||||||
|
else if (*a > *b)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
update_mean_path_delay (PtpDomainData * domain, PtpPendingSync * sync)
|
update_mean_path_delay (PtpDomainData * domain, PtpPendingSync * sync)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_MEDIAN_PRE_FILTERING
|
||||||
|
GstClockTime last_path_delays[G_N_ELEMENTS (domain->last_path_delays)];
|
||||||
|
GstClockTime median;
|
||||||
|
gint i;
|
||||||
|
#endif
|
||||||
|
|
||||||
GstClockTime mean_path_delay, delay_req_delay;
|
GstClockTime mean_path_delay, delay_req_delay;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
|
@ -1243,6 +1273,37 @@ update_mean_path_delay (PtpDomainData * domain, PtpPendingSync * sync)
|
||||||
(sync->correction_field_sync + sync->correction_field_delay +
|
(sync->correction_field_sync + sync->correction_field_delay +
|
||||||
32768) / 65536) / 2;
|
32768) / 65536) / 2;
|
||||||
|
|
||||||
|
#ifdef USE_MEDIAN_PRE_FILTERING
|
||||||
|
for (i = 1; i < G_N_ELEMENTS (domain->last_path_delays); i++)
|
||||||
|
domain->last_path_delays[i - 1] = domain->last_path_delays[i];
|
||||||
|
domain->last_path_delays[i - 1] = mean_path_delay;
|
||||||
|
|
||||||
|
if (domain->last_path_delays_missing) {
|
||||||
|
domain->last_path_delays_missing--;
|
||||||
|
} else {
|
||||||
|
memcpy (&last_path_delays, &domain->last_path_delays,
|
||||||
|
sizeof (last_path_delays));
|
||||||
|
g_qsort_with_data (&last_path_delays,
|
||||||
|
G_N_ELEMENTS (domain->last_path_delays), sizeof (GstClockTime),
|
||||||
|
(GCompareDataFunc) compare_clock_time, NULL);
|
||||||
|
|
||||||
|
median = last_path_delays[G_N_ELEMENTS (last_path_delays) / 2];
|
||||||
|
|
||||||
|
/* FIXME: We might want to use something else here, like only allowing
|
||||||
|
* things in the interquartile range, or also filtering away delays that
|
||||||
|
* are too small compared to the median. This here worked well enough
|
||||||
|
* in tests so far.
|
||||||
|
*/
|
||||||
|
if (mean_path_delay > 2 * median) {
|
||||||
|
GST_WARNING ("Path delay for domain %u too big compared to median: %"
|
||||||
|
GST_TIME_FORMAT " > 2 * %" GST_TIME_FORMAT, domain->domain,
|
||||||
|
GST_TIME_ARGS (mean_path_delay), GST_TIME_ARGS (median));
|
||||||
|
ret = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_RUNNING_AVERAGE_DELAY
|
#ifdef USE_RUNNING_AVERAGE_DELAY
|
||||||
/* Track an average round trip time, for a bit of smoothing */
|
/* Track an average round trip time, for a bit of smoothing */
|
||||||
/* Always update before discarding a sample, so genuine changes in
|
/* Always update before discarding a sample, so genuine changes in
|
||||||
|
@ -1344,6 +1405,7 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
|
||||||
|
|
||||||
if (!domain) {
|
if (!domain) {
|
||||||
gchar *clock_name;
|
gchar *clock_name;
|
||||||
|
|
||||||
domain = g_new0 (PtpDomainData, 1);
|
domain = g_new0 (PtpDomainData, 1);
|
||||||
domain->domain = msg->domain_number;
|
domain->domain = msg->domain_number;
|
||||||
clock_name = g_strdup_printf ("ptp-clock-%u", domain->domain);
|
clock_name = g_strdup_printf ("ptp-clock-%u", domain->domain);
|
||||||
|
@ -1351,6 +1413,7 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
|
||||||
g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
|
g_object_new (GST_TYPE_SYSTEM_CLOCK, "name", clock_name, NULL);
|
||||||
g_free (clock_name);
|
g_free (clock_name);
|
||||||
g_queue_init (&domain->pending_syncs);
|
g_queue_init (&domain->pending_syncs);
|
||||||
|
domain->last_path_delays_missing = 9;
|
||||||
domain_data = g_list_prepend (domain_data, domain);
|
domain_data = g_list_prepend (domain_data, domain);
|
||||||
|
|
||||||
g_mutex_lock (&domain_clocks_lock);
|
g_mutex_lock (&domain_clocks_lock);
|
||||||
|
|
Loading…
Reference in a new issue