Когда GPS не видит спутники, как я могу продолжать отмечать плавное время?
Я получаю 10 обновлений в секунду от моего устройства GPS (MTK3339, используемого в коммутационной плате Adafruit) и использую его для обновления дисплея часов. Это работает достаточно хорошо, хотя есть одна небольшая проблема, которую я хотел бы решить, и одна большая проблема, которую мне нужно решить.
Сначала небольшая проблема; Я не получаю обновления каждые 100 мс. Я получаю один примерно каждые 100 мс... плюс-минус около 20-30 мс. Если позднее и раннее обновление поступают одно за другим сразу после того, как дисплей переходит от n к n+1 секундам, заметно, что оно не тикает с обычной частотой. Это не смертельно, но смотреть на аритмическое заикание очень больно.
Основной вопрос: что делать, если GPS не может найти сигнал? Возможно, устройство в течение минуты едет по туннелю или есть какое-то другое препятствие в небе. Я по-прежнему хочу, чтобы часы обновлялись с наибольшей вероятностью.
Нельзя просто обновить отображение секунд, а затем, через 1000 (измеряется Arduino) миллисекунд, обновить часы, если новое сообщение не пришло. 1000 реальных миллисекунд могут составлять от 700 до 1400 мс, измеренных Arduino, в зависимости от платы и качества кристалла. Что еще хуже, это несоответствие далеко не постоянно в пределах одного кристалла. Наблюдать, как процессор ускоряется и замедляется на несколько процентов в течение нескольких минут, не редкость.
Итак, мне бы хотелось иметь механизм, который будет постоянно сглаживать полученное (GPS) время, чтобы давать наилучшую оценку текущего фактического времени. Я согласен с тем, что это секунда или две (максимум) отличается от реального времени, пока частота шагов ощущается как настоящие секунды, а потеря GPS на несколько минут может быть быстро исправлена, когда сигнал повторно получен. .
Я немного знаком с (перечеркнутыми) методами DIP(/перечеркнутыми) PID, но я не знаю, как их применить здесь. Кажется, кто-то решил проблему ради синхронизации времени в Интернете, поэтому мне не следует заново изобретать решение.
4 ответа
Лучший ответ:
То, что вы хотите, а именно что-то, чтобы «сгладить полученное (GPS) время», называется дисциплинированным генератором GPS. Очевидно, вы не после высокой точности коммерческих GPSDO, но принцип работы то, что вы описываете, по сути одно и то же.
Что делать, если GPS не может найти сигнал?
На жаргоне GPSDO это называется состоянием удержания. В этот момент вы
полагаться исключительно на ваш локальный осциллятор (здесь, millis()
или micros()
),
и направьте его, чтобы скорректировать естественный дрейф, как определено во время
Прием GPS был хорошим. Или вы можете пофантазировать, измерьте чип
температуру и примените температурную компенсацию.
Я немного знаком с методами DIP, но не знаю, как их применять. здесь
Полагаю, вы имеете в виду «PID".
Вы применяете это к фазе осциллятора. Если местный осциллятор
опережает GPS (положительная фазовая ошибка), вы снижаете его частоту. Для
например, вы можете увеличивать количество секунд каждые 1 000 100
микросекунд (измеряется с помощью micros()
), а не каждые 1 000 000.
Это немного замедлит ваши часы и повторно синхронизирует их с
GPS. И наоборот, если ваши часы отстают от GPS, вы немного
увеличьте его частоту, чтобы он работал быстрее.
Другими словами, значение ошибки вашего PID – это фазовая ошибка вашего часы, а управляющая переменная — настройка частоты. К применяя технику PID таким образом, вы строите то, что известно как петля фазовой автоподстройки частоты или PLL. Это стандартный способ внедрение GPSDO.
Кажется, кто-то решил проблему ради синхронизация интернет-времени
Конечно, но реализация NTP может быть довольно сложной, поскольку с несколькими серверами, имеющими разные задержки туда и обратно и разные уровни доверия. Я не знаю ни одной библиотеки Arduino, которая делает ничего похожего. Вы можете искать «синхронизация времени» или «PLL». Если вы их не найдете, вы можете выбрать библиотеку PID и применить ее к своему осциллятор.
Несколько заключительных замечаний:
Вы написали: "ускоряйтесь и замедляйтесь на несколько процентов по ходу движения. несколько минут — не редкость». Это показывает, что есть что-то ужасно неправильно либо с вашей Arduino, либо с вашим кодом. За несколько минут, вы ожидаете изменения частоты порядка одной части на миллион на Arduino с керамическим резонатором, и несколько частей на миллиард, если у вас нет кристалла. Видеть это экспериментальное исследование стабильности часов Arduino. Эта проблема со стабильностью — самое первое, что вы должны исследовать. и исправить.
Многие GPS-модули поддерживают скорость 1PPS (один импульс в секунду). второй) сигнал. Если вы можете использовать этот сигнал, вы можете получить довольно точное измерение фазовой ошибки. Опираясь на NMEA предложения вызовут у вас сильное волнение, которое затем придется компенсировать, установив постоянную времени PLL на очень большую значение.
Точность 700–1400 мс кажется вам большой проблемой. Обычно это +- 10-20 мс. Вы можете предоставить свой код? Или, по крайней мере, важные его части? Возможно ли, что вы использовали функцию задержки?
Если это так, вам обязательно следует прочитать о функции millis и о том, как использовать ее в качестве таймера. Это значительно повысит «точность». Потому что при вызове функции задержки чип не просто ждет заданное количество секунд. Чип также вызывает функцию yield. Это в основном используется, чтобы убедиться, что вся фоновая работа выполнена, прежде чем продолжить.
Что также может вызвать у меня проблему, так это любые модификации микросхемы часов. Я видел код, в котором люди изменяют частоту ШИМ-сигнала. Это также влияет на часы во всех остальных отношениях.
Керамический резонатор (например, на Uno) обычно имеет скидку около 0,1% (1 мс в секунду). В худшем случае скидка 0,5%. Кристалл намного лучше., @Edgar Bonet
Вы не можете просто обновить отображение секунд, а затем 1000 (измеряется Arduino) миллисекундами позже, обновите часы, если появились новые сообщение не пришло.
Почему бы и нет? Я бы так и сделал:
- Ведение часов в памяти
- Обновлять при получении сообщения GPS
- Каждые 1000 мс (в миллисекундах) отсчитывайте часы, если сообщение не пришло, и в любом случае обновляйте отображение.
Что-то вроде:
SimpleTimer Timers;
unsigned long MyClock_sec = 0;
bool clockIsTicked = false;
void setup()
{
Timers.setInterval(10L, GpsCallback); // если сообщение, обновить MyClock & установить флаг
Timers.setInterval(1000, DisplayCallback); // если нет флага, ++MyClock; обновить дисплей
}
void loop(){
Timers.run();
}
void GpsCallback(void){
// если сообщение GPS {
// Мои часы = <<GPS_TIME>>;
// ++часыотмечены;
// }
}
void DisplayCallback(void){
if( !clockIsTicked )
++MyClock;
// обновить дисплей
clockIsTicked = false;
}
(Не скомпилировано и не протестировано — считайте это наброском псевдокода).
Что, если бы вы начали с самых точных часов Arduino, какие только могли построить, а затем периодически обновляли время через GPS? Для этого вам понадобится Arduino с кристаллом хорошего качества и библиотека TimerOne.
Пример Pro Mini с кристаллом хорошего качества
Используя этот скетч с модулем часов I2C Pro Mini и TM1637, я смог построить часы, которые «отстают» на 45 секунд в год. GPS или NTP не требуются :)
// Начните с комментирования кода коррекции времени "Fine"
// и сначала определяем "грубую" временную коррекцию.
#include <TimerOne.h>
int8_t secondCounter = 0;
int8_t minuteCounter = 0;
int8_t hourCounter = 12;
volatile int8_t oneSecondElapsed = 0;
// "Грубая" временная коррекция.
// 1000000 ДОЛЖНО = 1 секунда. Отрегулируйте это значение, чтобы компенсировать «быстрое»
// или "медленный" осциллятор. На моем Pro Mini 1000032 медленнее на 0,5 секунды.
// 24 часа, 1000000 слишком быстро на 1,5 секунды за 24 часа. «Исправление» состоит в том, чтобы
// чередуем число между 1000032 и 1000000, затем перезапускаем таймер
// два раза каждую минуту.
// ПРИМЕЧАНИЕ. Использование числа от 1000000 до 1000031 не имеет значения, поскольку
// "зернистость" расчета, выполненного в TimerOne.cpp, setPeriod().
// Это каждые 32, когда изменение действительно будет иметь значение. Используйте кратные
// из 32, например, 999968, 1000000, 1000032, 1000064, 1000096, 1000128 и т. д.
unsigned long oneSecond = 1000032;
void setup(){
Timer1.initialize(oneSecond);
Timer1.attachInterrupt(oneSecondTimerISR);
Serial.begin(9600);
displayTime();
}
void loop(){
// Обновлять переменные времени каждую секунду.
if(oneSecondElapsed){
// счетчик от 0 до 60 секунд.
secondCounter++;
// "Точная" временная коррекция.
// Чередование между 16 секундами на 1000000 (быстрее, чем фактическое время),
// и 44 секунды на 1000032 (медленнее реального времени).
// 15 секунд и 45 секунд стали медленнее на 1/2 секунды через 2 дня.
// 16 секунд и 44 секунды стали медленнее на 1/2 секунды через 7 дней.
if(secondCounter == 14){
oneSecond = 1000000; // Быстрее, чем реальное время.
Timer1.initialize(oneSecond);
}
else if(secondCounter == 30){
oneSecond = 1000032; // Медленнее реального времени.
Timer1.initialize(oneSecond);
}
// Переменные хронометража.
if(secondCounter > 59){
secondCounter = 0;
minuteCounter++;
if(minuteCounter > 59){
minuteCounter = 0;
hourCounter++;
}
if(hourCounter > 23){
hourCounter = 0;
}
}
oneSecondElapsed = 0;
displayTime();
}
}
void oneSecondTimerISR(){
oneSecondElapsed = 1;
}
void displayTime(){
if(hourCounter < 10){
Serial.print("0");
}
Serial.print(hourCounter);
Serial.print(":");
if(minuteCounter < 10){
Serial.print("0");
}
Serial.print(minuteCounter);
Serial.print(":");
if(secondCounter < 10){
Serial.print("0");
}
Serial.println(secondCounter);
}
- Запуск двигателя постоянного тока в течение заданного промежутка времени
- Информация о времени от GPS-приемника: как определить, свежая она или просроченная?
- Помогите с millis, чтобы получить точное время
- Рассчитать часовой пояс по координатам GPS
- Последовательный буфер остается пустым, как только он становится пустым один раз.
- Как справиться с rollover millis()?
- Как получить текущее время и дату в Arduino без внешнего источника?
- Преобразование в Unix Timestamp и обратно
почему бы не использовать библиотеку времени?, @Juraj
Относительно «_[одна истинная секунда] может составлять от 700 до 1400 мс, измеренных Arduino_»: либо ваш Arduino физически сломан, либо вы делаете что-то _ужасно неправильно_ в своем коде., @Edgar Bonet
Многие вещи могут помешать точному подсчету времени Arduino; без контекста невозможно понять, почему вы видите такие результаты - это довольно далеко от всего, что я видел практически на любом Arduino или клоне. Почему бы не добавить RTC?, @Dave Newton