• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Синхронизация часов.

nikolz

Well-known member
А это и требовалось получить в задаче. Сколько страниц и исписанного текста, как вы это осознали.
Ваше то решение дало +-0.5 сек :) и даже применение Фильтр Калмана не помогает.
И не понятно, чем вас не устраивает синхронизация с точностью сравнимой с расхождением "кварцев" установленных на модулях?
Надо больше? Тогда дуплекс и Фильтры Калмана + эмуляция ФАПЧ.
Но тогда придется покопаться в приоритетах прерываний. Для этого вам надо изучить это:
Увы, Вы зря обрадовались.
Я ошибся в предыдущем посте.
У вас не получилось решить задачу с ошибкой в 5 мкс.
по моим расчетам, ошибка при проведении автором топика экспериметов будет составлять до 150 мкс.
Чуть позже я расскажу ему, свой оригинальный алгоритм устранение этой ошибки, без калмановской фильтрации и фапч.
Продолжение следует..
 

nikolz

Well-known member
@niкolz, вы можете дать пример кодa, чтобы сделать тест на ЕСПках? Пока мне рубеж 50мкс не удаётся преодалеть.
Про систематические ошибки не совсем полял. Что и как вычислять?
Начинаю рассказ, почему в алгоритме синхронизации по базе (часам роутера) у pvvx получается в экспериментах ошибка в 5 мкс на интервале 0.1 сек, а при измерении временного интервала между двумя сенсорами ошибка может составить до 150 мкс.
------------------
После объяснения приведу свой оригинальный алгоритм, который действительно обеспечивает устранение указанной ошибки.
--------------------
Теория:
В методе синхронизации по базе, мы подменяем значения собственных частов модулей, некоторой оценкой значений часов базы.
В WIFI базой является роутер (AP), часы которого значения TT0 с минимальным тактом T0.
По условию задачи, есть два сенсора E1 и E2 , часы которых генерируют значения TT1 и TT2 c минимальными тактами T1 и T2 соответственно.
В общем случае, часы E1 имеют погрешность хода D1=T1-T0, часы E2 D2=T2-T0.
-------------------------------
AP периодически посылает на E1 и E2 дискретные значения TSF текущего значения TT0 .
Период дискретизации выбирается пользователем произвольно, но рекомендован TD=( 2^10)*100 мкс = 102400 мкс. Так как T0=1 мкс, то TSF увеличивается с шагом 102400.
----------------------------------------------
В результате на E1 и E2 используем в качестве показаний часов значения TSF, которые точно равны текущему значению часов APс интервалом TD.
Т е шаг изменения таких часов будет составлять 102.4 мс.
внутри этого интервала реализуется приблизительное вычисление текущего времени с дискретностью T1 и T2.
---------------------------
Для этого, запоминается значение внутренних часов модуля TD1 и TD2 при получении значения TSF и от этого момента к значению TSF прибавляется разность текущего значения и время приема TSF.
Таким образом, в каждом модуле, на интервале TD рассчитывается примерное значение текущего времени AP по формуле
сенсор E1: TT1n=TSF+TT1-TD1
сенсор E2: TT2n=TSF+TT2-TD2
--------------------
Далее рассмотрим причины ошибок и их величину на примере модулей, которые я исследовал.
---------------------
Исследование относительного ухода времени частов TT1 и TT2 показали, что величина систематической погрешности значения DTT=TT1-TT2 =(T1-T2)*102400 и составляет 55 мкс за секунду.
Это означает, что при измерении относительной рассинхронизации часов сенсоров E1 и E2, т е значения DTTn=TT1n-TT2n, мы получим на интервале 102.4 мкс в идеальном случае систематическую ошибку 5.5 мкс.
Что и наблюдается и ошибочно принимается некоторыми товарищами за максимальную ошибку измерения.
Однако, полученная величина - это минимальное значение ошибки.
Максимальная величина этой ошибки может быть в десятки раз больше.
По моим экспериментальным данным ее значение в лучшем случае лежит в диапазоне до 150 мкс.
--------------------------
Такая ошибка возникает по следующей причине.
В задаче эксперимента необходимо измерить разность времени срабатывания сенсоров.
Т е моменты времени TT1 и TT2, в которые произойдут события не синхронизированы, а следовательно могут происходит на любом временном расстоянии от момента прихода значения TSFв сенсоры.
В результате ошибка рассинхронизации будет равна
DDTnk=(T1-T0)*N1-(T2-T0)*N2,
где N1 и N2 - произвольные целые числа в диапазоне от 0 до 102400.
Например, для N1=0 и N2=102400, получаем DDTnk=(T2-T0)*102400.
если будет пропущен прием очередного TSF, что иногда происходит, то ошибка кратно возрастает .В моем эксперименте эта величина получилпсь в диапазоне до 150 мкс.
========================
Алгоритм.
Теперь полагаю понятна причина маленькой ошибки при синхронном чтении часов E1 и E2 и причина большой ошибки в замере разности времени событий.
Перехожу к моему оригинальному алгоритму, который устарняет большие ошибки и реально позволяет достичь приемлемой точности.
Чтобы устранить указанную ошибку необходимо формулу вычисления оценки текущего времени APв модуле Eизменить следующим образом:
вместо
TTn=TSF+TT-TD
записать
TTn=TSF+A*(TT-TD),

где A=(TSF-TSF0)/(TD-TD0);
TSF0 - предыдущее значение TSF0;
TD0 - значение момента приема TSF0

--------------------------------
PS: если хотите, чтобы синхронизация была действительно с малой ошибкой, то просите pvvx, чтобы он в свою примитивную программу добавил мой оригинальный алгоритм.
 

pvvx

Активный участник сообщества
Начинаю рассказ, почему в алгоритме синхронизации по базе (часам роутера) у pvvx получается в экспериментах ошибка в 5 мкс на интервале 0.1 сек, а при измерении временного интервала между двумя сенсорами ошибка может составить до 150 мкс.
В том примере не может быть ошибки более 6-ти us. Каждые 0.1024 секунды значение счетчика TSF корректируется на число не более 6. А счет у него в us. И указано - примитивный алгоритм. :p
2) Пропусков beacon быть не должно. Если они есть, то ваш модуль спит и ему не до синхронизации вообще - любой счетчик может быть отключен для понижения потребления.
3) Ошибка у гуру Nicolz возникает из-за неверного написания программы. У него нет атомарной связи с чтением TSF счетчика и внешнего события. Между ними происходят системные прерывания обслуживания WiFi и т.д. до десятков ms. Какая при этом привязка к времени внешнего события?
4) Если часы модуля расходятся на более 5 us за 0.1 сек - это значит, что надо корректировать PLL или выкинуть модуль на помойку - в нем установлены некачественные комплектующие и он не может равботь в WiFi по стандарту (будет пищать не на тех частотах). Типичные отклонения дешевых кварцев = 6 десятичный знак с учетом температуры.
5) Меня не надо просить вставлять код - исходники выложены и каждый сам может вставить в процедуры работы с TSF что хочет. Лицензия на то, что есть, учитывает, что вы сами вставите свой (c), а упоминания от куда взяли - сотрете. Это лучший вариант.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Померил через какие интервалы времени ESP_AP посылает tsf. В графике время между текущим и предыдущим сигналом recv_tsf. Результат удивил меня. Никакая там не 0.1сек.
От 312мкс до 3401(!)мкс.
Что то там не хорошо :(
Посмотреть вложение 2996
Спит он у вас наверно. Режим MODEM или ...
Снимок1129.gif
 

sasasa

Member
У меня там такая строчка в Setup()
wifi_set_sleep_type(NONE_SLEEP_T);
А как проверить какой там режим реально? Есть какая то функция запроса состояния?
 

pvvx

Активный участник сообщества
В то же время от рутера без единой ошибки всё одинаково 1735мкс
Что то там не хорошо :( Как заставить ЕСПку передавать нормально тсф?
Наверно никак - такая SoftAP на ней кривая или что-то в Arduino мешает ей.
У меня там такая строчка в Setup()
wifi_set_sleep_type(NONE_SLEEP_T);
А как проверить какой там режим реально? Есть какая то функция запроса состояния?
struct softap_config -> uint16 beacon_interval; // Note: support 100 ~ 60000 ms, default 100 (wifi_softap_get_config()).
bool wifi_set_sleep_type(enum sleep_type type);
enum sleep_type wifi_get_sleep_type(void);
 

pvvx

Активный участник сообщества
Поспешил я сказав что с рутера всё одинаково. Там тоже плывёт частота, но на много меньше. Интересно что большой сдвиг у рутера происходит через каждый 59-ый сигнал
Посмотреть вложение 3000
Ставлю синхро ослу на внешний ген 102.400000 ms - даже не дрожит.
В куче сигнал передачи на щуп с детекторным СВЧ диодом:
beacon.gif
Беакон самый "толстый" - передается на низкой модуляции...
Это был роутер.
Теперь ESP c web-свалкой в режиме AP+ST:
Esp_beacon.gif
Прыжки на 2 ms
 
Последнее редактирование:

sasasa

Member
Теперь ESP c web-свалкой в режиме AP+ST:
Я не по осцилографу то что AP посылает, а по принятому на ESP_STA recv_tsf значению смотрю. График по их разнице между собой

почти то же самое что у меня на рутере 2100+мкс.
Но ЕСПка почему то до 3400мкс тормозит в SoftAP
 
Последнее редактирование:

pvvx

Активный участник сообщества
Я не по осцилографу то что AP посылает, а по принятому на ESP_STA recv_tsf значению смотрю. График по их разнице между собой


почти то же самое что у меня на рутере 2100+мкс
Для наглядности
(тут 2 ms клетка)
видим оба beacona от роутера и ESP и узреваем, что SoftAP ESP синхронизируется по внешнему сигналу от соединения её station c AP роутера.
Через время ESP уплывет... Сигнал с роутера останется прыгать там-же, относительно внешнего генератора синхронизации 102.4 ms...
 
Последнее редактирование:

pvvx

Активный участник сообщества
А то, что у вас ещё прерывается всяким софтом - вы это ещё не устранили.
Роутер исправно вставляет правленный на прыжки его беакона TSF, а вот с ESP ещё не проверял.
Прошивка на роутере Padavan-ская...
по принятому на ESP_STA recv_tsf значению смотрю. График по их разнице между собой
А почему цикл не 102.4 ms? Накручено что-то в роутере?

Примерно измерил расхождение аппаратного счетчика у ESP (по передаче beacon с отключенными роутерами). Итог 1 ms на 200 секунд (усредненное значение в текущей температуре). Это 0.001/200 = 0.000005, т.е. 5 us в секунду (относительно генератора с джиттером 20 ns GPS :)). Nikolz опять в пролете :p
 
Последнее редактирование:

sasasa

Member
А почему цикл не 102.4 ms? Накручено что-то в роутере?
Ничего не накручено, и рутер, и ЕСПка с default установками.
Среднее значение если взять ~5000+ сигналов 1561мкс. Про чём это абсолютно одинакого как для рутера, так и для ЕСПки. С той разницей, что у ЕСПки на много больше разброс. Это при условии что принятое значение показывает микросекунды. Одно из двух - то ли интервал 1.56мс, то ли отсчёт не в микросекундах а "попугаях".
По большому счёту это ничего не меняет, если бы на расброс.
Первый столбик recv_tsf (каждое новое значение), второй разница между предыдущим
Код:
2172395751        1562
2172397312        1562
2172398873        1561
2172400434        1561
2172401995        1562
2172403556        1562
2172405117        1561
2172406678        1562
2172408239        1561
2172409800        1590
2172411361        1533
2172412922        1562
2172414483        1561
2172416044        2480
2172417605        1317
2172419166        1544
2172420727        1561
2172422288        1561
2172423849        1562
2172425410        1562
2172426971        1561
2172428532        1562
2172430093        1561
2172431654        1562
2172433215        1561
Код:
xx = get_tsf_station();
if(xx > prev_xx) {
  val[i] = xx;
  i++;
  prev_xx = xx;
}
 
Последнее редактирование:

pvvx

Активный участник сообщества
Ничего не накручено, и рутер, и ЕСПка с default установками.
Среднее значение если взять ~5000+ сигналов 1561мкс. Про чём это абсолютно одинакого как для рутера, так и для ЕСПки. С той разницей, что у ЕСПки на много больше разброс. Это при условии что принятое значение показывает микросекунды. Одно из двух - то ли интервал 1.56мс, то ли отсчёт не в микросекундах а "попугаях".
По большому счёту это ничего не меняет, если бы на расброс.
У вас что, не стандартный ESP8266? У него данный счетчик строго в us.
 

pvvx

Активный участник сообщества
Код:
uint32 GPIO_INT_init_flg DATA_IRAM_ATTR;

#define GPIOs_intr_TASK_PRIO (USER_TASK_PRIO_1)
#define GPIOs_intr_TASK_QUEUE_LEN 2
#define GPIOs_intr_SIG_DELTA 7

volatile uint64 recv_tsf; // принятый TSF от внешней AP
volatile uint32 recv_tsf_time;    // время приема TSF (младшие 32 бита)
// процедура вывода в UART
void ICACHE_FLASH_ATTR task_GPIOs(os_event_t *e)
{
    if(e->sig == GPIOs_intr_SIG_DELTA) os_printf("%u,%u\n", e->par, (uint32)recv_tsf);
}
extern void cnx_update_bss_mor_(int a2,  struct ieee80211_scanparams *scnp, void *a4);
//===============================================================================
// save_tsf_station() процедура приема TSF от AP
//-------------------------------------------------------------------------------
#define GPIOs_intr_TASK_PRIO (USER_TASK_PRIO_1)
#define GPIOs_intr_SIG_DELTA 7
void ICACHE_FLASH_ATTR cnx_update_bss_more(int a2,  struct ieee80211_scanparams *scnp, void *a4)
{
    ets_intr_lock();
    MEMW();
    recv_tsf_time = *((volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR);
    os_memcpy((void *)&recv_tsf, (void *)scnp->tstamp, 8);
    ets_intr_unlock();
    cnx_update_bss_mor_(a2, scnp, a4);
    system_os_post(GPIOs_intr_TASK_PRIO, GPIOs_intr_SIG_DELTA, recv_tsf_time);
}
// кусок инициализации:
    system_os_task(task_GPIOs, GPIOs_intr_TASK_PRIO, GPIOs_intr_taskQueue, GPIOs_intr_TASK_QUEUE_LEN);
На GPIO - в названиях не смотреть - копипаст из другого примера :)
Вот лог приема пять с половиной тысяч TSF:
 

Вложения

  • 122.9 KB Просмотры: 6
Последнее редактирование:

pvvx

Активный участник сообщества
По приему TSF создается событие и передается запрос system_os_post(). После отработки приема, когда будет работать менеджер задач, он вызовет процедуру task_GPIOs(), которая распечатает переданное время приема и младшие 32 бита TSF в UART.
Могу скинуть прошивку web-свалки с данным тестом + оверлей который распечатывает данные в UART... Это если мало 5.5 тысяч замеров для вывода статистики :)
Берем различия хода, тупа - 2 замер и последний:
Получаем время хода между 5663 замерами счетчика таймера и принятой TFS:
580107040-580096030=11010
Т.е. за 580 секунд расхождение часов ESP от AP роутера на 11010 us.
11010/580=18.982759 us в секунду. При следовании beacon в 0.1 сек получим предел расхождения в 1.9 us, а не заоблачные данные от Гуру Nikolz. :) :p
При этом какое умножение даст коррекцию по его формуле? y+- единица * x = ? Т.е. смысл этого действа? - Перевести в наносекунды? :)
 
Последнее редактирование:

sasasa

Member
Я вам верю, но никак не могу понять почему у меня recv_tsf обновляется черес 1.56мс а не 100мс как должно быть
 

Вложения

  • 78.5 KB Просмотры: 2

pvvx

Активный участник сообщества
Я вам верю, но никак не могу понять почему у меня recv_tsf обновляется черес 1.56мс а не 100мс как должно быть
Вера тут не при чем. Это наверно ваш цикл опроса, а не время приема и не следующее значение переданное TSF с AP.
Судя по передаче 10 символов в UART на точку, скорость вывода в UART стоит от (1/0.00156)*10=6410.25641 baud. Наверно 9600 и + задержка на исполнение вычислений и т.д. ? (это гадание :))
 
Последнее редактирование:

pvvx

Активный участник сообщества
Вот разброс хода таймера и хода beacon от туда:
Снимок1130.gif
В логе:
Первый столбец - время прихода beacon по часам ESP.
Второй столбец - TSF переданный AP.
Если взять разницу между приемами по часам ESP и вычесть разницу в переданном TSF, то получим указанный график.
Дисперсия возникает из-за прерываний в процессе получения TSF и фиксации времени.
Можно сделать простой фильтр:
При приеме делаем вычисление текущей TSF по прошлым данным с учетом таймера.
Если оно более +-6, то прибавляем не более +-6 к текущему смещению времени. Если менее - то это и прибавляем. Подряд идущих искажений не замечено.
Это уже дает уровень точности +-6 us. Но является ужасно примитивным и надо создать правильные стартовые значения...
Лучше всё таки какой фильтр. Тогда +-2 us гарантированно.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Ну конечно же - я не ту функцию записал! o_O:mad::confused:
Я тоже ошибся. При передаче символов есть ещё символ перевода строки и каретки. Т.е. 12 символов на строку, из них 10 цифр. При 9600 baud, берем на символ 11 бит - 1 старт, 8 данных, 2 стоп. Получаем 11*12/9600 = 0.01375 сек на вывод строки...
 
Сверху Снизу