Наткнулся в некоей чужой системе на красиво реализованный ramp-up шагового мотора. Код утянут с общедоступного Атмеловского, а тот, в свою очередь, основан
вот на этой публикации за авторством David Austin. А коль всё и так известно, то можно и рассказать.
В двух словах задачка формулируется следующим образом: чтобы обеспечить линейный разгон мотора, время каждого шага должно расчитываться как

. Брать корень на каждом шаге -- это очень накладно. И, как будто проблем мало, вычитание приводит к потере точности.
David красиво сводит задачу к отношению времён двух смежных пульсов, которое аппроксимирует первыми членами ряда Тейлора, получая магическое C
n = C
n-1 -- 2C
n-1/(4n + 1). И это прекрасно работает в текущем коде системы, обеспечивая линейный и предсказуемый рамп как вверх, так и вниз.
Вот только... линейный разгон -- плохое решение, сразу по многим причинам. Во-первых это долго. Мотор мучительно пробирается через низкочастотные резонансы. Запас по моменту на низких оборотах не используется, а нехватка его на высоких вынуждает снижать ускорение. Торможение с больших оборотов перегружает питание. И так далее, и так далее... Гораздо лучше получается, если вести разгон, задавшись постоянством энергии, добавляемой в систему на каждом шаге, то есть Δv
2 = const. При этом (не было печали) длительность пульса начинает зависеть не от квадратного, а от кубического корня от номера.
Так вот чего я придумал: если волшебную формулу изменить на C
n = C
n-1 -- C
n-1/(3n + 1), то рамп становится правильным, корнеквадратичным. Пока получено и проверено эмпирически, завтра надо аккуратно теорию расписать, тоже через разложение в ряд Тейлора :).
UPD: Расписал, да, сходится, только коэффициенты всё же не 1 и 3, а 2 и 6, или C
n = C
n-1 -- 2C
n-1/(6n + 1), так как taylor{(1+-x)^2/3, 0} -> 1 +- 2/3x -1/9x^2 + O (x^3), а дальше тривиально. Ну чё, я молодец :)