В контексте, это для управления несколькими шаговыми двигателями одновременно в высокоточном приложении.
Постановка задачи
Скажем, у меня есть цикл, который будет запускать итерации i. В ходе этих итераций экспрессия E_x должна оцениваться как truex раз (x <= i гарантирован).
Требования
- E_x должен оцениваться как trueточноx times
- E_x должен оцениваться до true через более или менее равномерно распределенные интервалы *
* «равномерно распределенные интервалы» означают, что максимальный размер интервала сведен к минимуму
Примеры
Для: i = 10, x = 7E_x будет истинным на итерациях с пометкой 1: 1101101101
Для: i = 10, x = 3E_x будет истинным на итерациях с пометкой 1: 0010010010
Для: i = 10, x = 2E_x будет истинным на итерациях с пометкой 1: 0001000100
Каков наилучший (или даже «хороший») способ получить оценку E_x до true через равные промежутки времени, гарантируя при этом, что это верно в точности x раз?
Этот вопрос близок к моему, однако он предполагает, что E_x всегда будет оценивать true в 1-й и последней итерациях, что не соответствует моим требованиям (см. 2-й пример выше).
пожалуйста, объясните свой ответ для i = 10, x = 4, почему бы не 1001001001
@Jasen, это хороший аргумент, я не выбрал лучший пример. Смысл в том, чтобы показать, что может быть нежелательно иметь 1 в первой и / или последней позиции. Я дополню свой вопрос лучшими примерами.
Кайл, я прав в том, что ваш процесс - это всего лишь один запуск, а не бесконечный цикл (периодический процесс)? В противном случае ваш пример i = 10, x = 2 выглядит странно: разрыв между последним событием в одном цикле и первым в следующем составляет 5 0.
@SergGr вы правы. Это будет расширено для одновременного вращения нескольких шаговых двигателей, но с разными скоростями в течение заданного периода времени (в данном случае i - это временной интервал, а x - количество шагов, которые конкретный двигатель должен повернуть за этот временной интервал).
Напоминает мне этот вопрос. x здесь соответствует количеству символов там.





Я буду использовать немного другое соглашение об именах: давайте по интервалам T запускать события [1..T] и N. Также давайте решим задачу как циклическую. Чтобы сделать это, давайте добавим один ложный шаг в конце, на котором мы гарантированно сработаем событие (и это также будет событие в момент времени 0, то есть перед циклом). Итак, мой T - это ваш i+1, а мой N - ваш x+1.
Если разделить T на N с напоминанием, получится T = w*N + r. Если r=0 дело тривиальное. Если r != 0, лучшее, что вы можете достичь, - это интервалы r размера w+1 и интервалы (N-r) размера w. Быстрое и простое, но достаточно хорошее решение будет примерно таким (псевдокод):
events = []
w = T / N
r = T % N
current = 0
for(i = 1; i<=N; i++) {
current += w;
if (i <= r)
current += 1;
events[i] = current;
}
Вы можете видеть, что последним значением в массиве будет T, как и было обещано нашим переформулированием как циклической проблемой. Это будет T, потому что в течение цикла мы добавим w к current, N раз и добавим r, умноженное на 1, так что сумма будет w*N+r, то есть T.
Главный недостаток этого решения состоит в том, что все «длинные» интервалы будут в начале, а все «короткие» интервалы будут в конце.
Вы можете распределять интервалы более равномерно, если будете немного умнее. И результирующая логика будет по существу такой же, как и за Линейный алгоритм Брезенхема, упомянутым в комментариях. Представьте, что вы рисуете линию на плоскости, где ось X представляет время, а ось Y представляет события, от (0,0) (которое является событием 0 до вашего временного интервала) до (i+1, x+1) (которое является событием x+1, просто по истечении вашего срока). Момент для создания события - это когда вы переключаетесь на следующий Y, то есть рисуете первый пиксель в данном Y.
Приносим извинения за задержку, у меня еще не было возможности ознакомиться с вашим решением. Я обязательно отмечу ответ как принятый после того, как сравню их.
@KyleG., Честно говоря, я не думаю, что любой из ответов идеален. Я не предоставляю явного кода для «лучшего» решения, и я считаю, что код Мэтта неверен в нециклических деталях вашей проблемы (рассмотрим случай x = 2 и n = 8, где решение, очевидно, должно быть 00100100, но я считаю, что код Мэтта выдает 01000100). Также разница между нашими ответами заключается в том, что я пытаюсь создать массив, в то время как код Мэтта представляет собой что-то вроде итератора / генератора, и неясно, что лучше для вашего варианта использования. Дайте мне знать, если вы хотите, чтобы я улучшил свой ответ более подробной информацией.
@KyleG., Спасибо, что приняли мой ответ. Вы не ответили на мой последний комментарий, но вы все равно можете сообщить мне здесь, если вам понадобится дополнительная помощь.
Если вы хотите делать приращения x по сравнению с итерациями n, вы можете сделать это следующим образом:
int incCount = 0;
int iterCount = 0;
boolean step() {
++iterCount;
int nextCount = (iterCount*x + n/2) / n; // this is rounding division
if (nextCount > incCount) {
++incCount;
return true;
}
else {
return false;
}
}
Это простой для понимания способ. Если у вас встроенный ЦП, где разделение дороже, вы можете выполнить точно то же самое, например:
int accum = n/2;
boolean step() {
accum+=x;
if (accum >= n) {
accum-=n;
return true;
}
else {
return false;
}
}
Общая сумма, добавленная к accum, здесь, как и в первом примере, равна iterCount*x + n/2, но деление заменено инкрементным повторным вычитанием. Так работает алгоритм рисования линий Брезенхема.
Приносим извинения за задержку, у меня еще не было возможности ознакомиться с вашим решением. Я обязательно отмечу ответ как принятый после того, как сравню их.