Мне хотелось обложку, которая объясняет себя сама. Год Земли за 30 секунд, по одному снимку в день с одного спутника в одну и ту же минуту. Тогда двигается только то, что меняется. Himawari-9 висит над 140,7 градуса восточной долготы, а NICT хранит снимки полного диска маленькими файлами PNG. Выглядело как работа на вечер. Самым трудным, думал я, будет скачивание.
Полдень это очевидное время и заодно скучное: почти весь диск освещён каждый день и двигаются только облака. Я взял 21:00 UTC. Под спутником это примерно 06:23 по местному среднему времени, поэтому граница дня и ночи проходит через диск. У NASA Earth Observatory есть 4 снимка Meteosat, сделанных так же, по одному на каждое солнцестояние и равноденствие. В декабре граница наклонена в одну сторону, в июне в другую. Мне хотелось все дни между ними. Как собрать из кадров Himawari анимацию, Чарли Лойд описал ещё в 2015 году, так что сам ролик идея старая.
Год
Беру год с 1 октября 2025 по 30 сентября 2026. Я запросил у NICT 730 кадров, 550 на 550 пикселей, в естественных цветах. 365 из них на 21:00 UTC и 365 на 03:00 UTC для полуденной версии. Пришло 723. Все 7 недостающих это кадры рассвета и сервер отвечает на них кодом 403. В копии сырых данных Himawari у NOAA на 21:00 этих дат тоже пусто, значит спутник эти кадры не записал. В такой день в ролике на экране остаётся предыдущий кадр.
При 12 кадрах в секунду 365 кадров это 30,4 секунды. Видео собрал ffmpeg 6.1.1, GIF собрал gifsicle 1.94.
Когда я посмотрел его в первый раз, граница качалась как маятник и ещё сдвигалась вбок: осенью влево, зимой вправо. Качания я ожидал. Сдвиг вбок я сначала объяснить не смог. Из-за него у меня появился другой вопрос. Если граница за год движется в 2 направлениях, может быть, одного кадра хватит, чтобы сказать, какой это день.
Дата по одному кадру
Аналемма это известная фотография. Если снимать солнце с одного места в одно и то же время по часам весь год, оно рисует в небе восьмёрку. Вверх и вниз это сезон. Вбок это уравнение времени. В начале ноября солнце опережает часы на 16 минут, в середине февраля отстаёт на 14. До этого прогона я не ждал увидеть её на снимке метеоспутника.
Метод простой. Python 3.12, numpy 2.5.3, scipy 1.18.1, Pillow 12.3.0, skyfield 1.55 с эфемеридами DE421. В каждой строке кадра я нахожу самый западный освещённый пиксель. Освещённый значит яркость 3 из 255 или больше после сглаживания 5 на 5. Строки, где эта точка лежит на краю диска, выбрасываются. По формулам геостационарной проекции каждый пиксель границы переводится в широту и долготу. Потом для каждой из 365 дат я считаю, где было солнце в 21:00 UTC. Из этого получается, насколько оно ниже горизонта в каждой точке границы. Правильная дата та, при которой во всех точках границы солнце опущено под горизонт на один и тот же угол. Этот угол я брал по другой половине кадров. Чётные дни читаются со значением из нечётных и наоборот.
Первая версия читала большинство дат с ошибкой от 2 до 4 дней, то раньше, то позже. С ошибкой не больше дня попали только 20 кадров из 358.
Кадр снимается 9 минут
Сначала я решил, что в проекции постоянная ошибка. Поэтому дал программе подобрать 2 дополнительных параметра: сдвиг по времени и его рост с севера на юг. Подгонка тянула начало кадра раньше 21:00 и упиралась в предел любого диапазона, который я разрешал. Спутник не может снимать раньше, чем начинается его расписание. Потом я увидел, что сдвиг просто компенсировался углом солнца на границе. Близко к настоящей развёртке вышел только рост с севера на юг.
Ответ лежал в сырых файлах. NOAA хранит исходные данные Himawari, 10 сегментов на полный диск. В заголовке каждого сегмента записано время начала и конца. Я скачивал только первые 300 КБ каждого. Северный край снимается в 21:00:21, экватор примерно в 21:05:05, южный край в 21:09:40. На всех 3 проверенных датах это совпадает с точностью до секунды. Я считал “кадр в 21:00” одним моментом, а заголовки показывают развёртку длиной 9 минут 19 секунд. За 5 минут солнце уходит на 1,25 градуса к западу. На экваторе этой картинки это около 7 пикселей. Ошибка ещё и растёт с севера на юг, так что граница получает неправильную форму. Этого хватает, чтобы поиск предпочёл дату, отстоящую от настоящей на 2 или 3 дня.
С настоящим временем каждой строки результат такой. 241 кадр из 358 даёт точную дату, у 335 ошибка не больше дня, у 353 не больше 3 дней. Без сдвига вбок, по одному наклону границы, с ошибкой не больше дня 191.
Где не получается
Промахи не случайные и это мне нравится больше попаданий. 4 кадра ошибаются на месяцы: 13, 14 и 15 апреля прочитаны как 27 или 28 августа, а 30 августа как 12 апреля. Это точка, где восьмёрка пересекает саму себя. 14 апреля и 28 августа солнце стоит над 9,6 и 9,5 градуса северной широты. По уравнению времени эти 2 даты расходятся меньше чем на минуту, так что в кадре разницы нет.
Второе слабое место это июнь. В декабре с ошибкой не больше дня 30 кадров из 31, в июне только 16 из 30 и худший промах 4 дня. На обоих солнцестояниях наклон перестаёт меняться. Около декабрьского солнцестояния уравнение времени ещё меняется примерно на 30 секунд в сутки и это выручает, в июне примерно на 13.
Когда я построил измеренный наклон против измеренного сдвига для каждого кадра, без всякого астрономического календаря, восьмёрка нарисовалась сама. Наклон следует за склонением солнца, корреляция 0,9995. Сдвиг следует за уравнением времени почти так же точно, 0,998. На минуту уравнения времени приходится около 1,31 пикселя сдвига.
Сама обложка
Потом я готовил её к публикации. В виде GIF год рассветов весит 50,6 МБ, год полудней 79,7 МБ. X пускает анимированный GIF не больше 15 МБ и советует не больше 350 кадров, а в году 365 дней. MP4 с H.264 при CRF 28 весит 3,1 МБ для рассвета и 7,7 МБ для полудня. Рассветная версия меньше, вероятно потому, что значительная часть каждого диска тёмная. На чём именно экономит кодек, я не проверял.
Чего я не проверял
Порог 3 из 255 оказался лучшим из 3 опробованных. При 6 попаданий становится 304 из 358, при 12 всего 163, так что метод держится на том, чтобы читать самый тёмный край сумерек. Угол солнца на границе откалиброван по настоящим датам другой половины кадров, поэтому это не слепой тест. Я взял один год одного спутника, при разрешении 550 пикселей. А заставит ли ролик кого-то перестать листать ленту, пока сказать не могу, он ещё не выложен.