Перейти к содержанию

Сглаживание Отображаемой Информации


Рекомендуемые сообщения

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Не понял, а зачем? Разве это не усложняет алгоритм? Сумма ведь всегда считается строго по заданному числу отсчётов, или нет?

Я уже объяснил. Заполнение буфера процесс очень быстрый. Он происходит в прерывании, обычно это чтение счетчика на лету или очень быстро, чтобы не было мертвых интервалов. Поэтому подготовка адреса (указателя массива) происходит заранее, т.е. все что требуется при заполнении - одна пересылка.

Для Вашего алгоритма нужно всегда помнить кто был последним и держать старую сумму в памяти, т.е. массив не кольцевой, а линейный.

На деле нет никакой разницы кто первый, а кто последний, просто кажлая новая запись автоматически затирает самое древнее измерение в буфере.

Просчитать сумму восьми ячеек требуется мизерное время, даже при 16 разрядах это порядка 50 машинных циклов максимум. Т.е. практически мгновенно.

я говорю не про абсолютные значения, а про ИЗМЕНЕНИЯ оборотов.

А именения за какой интервал? Я уже сказал - холостой ход - резкое нажатие на педаль дает скорость изменения порядка 2000...3000 об/мин за треть секунды. Но эти показания можно точно не отслеживать, задержка в полсекунды совершенно нормальна, такую имеет и штатный стрелочный показометр. Какой смысл в случайных величинах на хх - там нет ничего интересного. Вот под нагрузкой другое дело, но там показания меняются очень и очень плавно, а точность выше чем в полсотни оборотов ничего кроме дизайна не дает...

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Насколько я понимаю, кольцевой массив отличается от линейного именно тем, что может быть "разорван" на две части, когда адрес его "хвоста" находится выше адреса "головы". Если так, то в моём алгоритме применяется именно кольцевой массив, для "головы" (вернее, головы+1) и "хвоста" которого используется один и тот же указатель, т. е. длина массива равна длине буфера.

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Дело не в адресе. Кольцевой массив реализуется из обычного, линейного. Просто заполнение идет по кольцу. Поэтому данные в нем фактически не нумерованы и при обработке они не могут быть локализованы по номеру. В линейных массивах есть четкая временнАя привязка данных к номеру. Вот Вы и обрабатываете массив фактически как линейный, да еще и храните последовательность индексов, что уж совсем нонсенс. При просчете реально скомпилированного кода по времени вы ничего не выиграете, а в структуре программы проиграете. Да и в объеме занятой памяти тоже. Фактически Вы вынуждены все переменные держать как глобальные... Это сосем не куртуазно...

Конечно делать можно как угодно, работать в данном случае будет, только это страшно дурной тон и при иных временах и объемах массива не прокатит...

Асинхронная обработка позволяет изменять массив даже во время расчета. А такое очень вероятно при режиме реального времени. В Вашем варианте во время расчета изменить массив нельзя, поскольку изменится текущий индекс, а он важен при вычитании самого старого измерения...

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

Последовательность индексов я нигде не храню, я храню только сами данные (buf) и индекс ячейки, куда будет писаться следующий отсчёт (i). Это необходимый минимум, верно? Кроме него я храню только текущую сумму всех элементов массива, и при поступлении очередного отсчёта вычитаю из неё самый старый отсчёт (он хранится как раз в той ячейке, которая будет затираться новым значением), и прибавляю новый.

Ссылка на комментарий
Поделиться на другие сайты

Текущий индекс нельзя хранить, это переменная изменяемая в прерывании, поэтому возможны коллизии: вычитаете по одному указателю, а прибавляете по другому. А вот хранение суммы и есть расход памяти, особенно если учесть ее многоразрядность.

Собственно я уже это все писал, в добавлении к предыдущему посту (Вы его не читали - писали ответ)

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

Для восьми значений согласен - это лишняя переменная, лишние две арифметических операции в обработчике прерываний. Но для буфера, скажем, на 1k отсчётов, мне кажется, это не такая большая плата за избавление основного цикла от тысячи операций.

Ссылка на комментарий
Поделиться на другие сайты

Как раз тут и есть ошибка. Пример.

При заполнении буфера в 1К требуется очень малое время на каждую пересылку, поскольку данных много. И самое лучшее решение в таких случаях использовать МК с DMA. Ну или разводить процессы обработки и заполнения совершенно. Вывод данных на дисплей не требует скорости (если это не потоковые данные, но там и другие алгоритмы и даже архитектуры МК (кольцевые буферы аппаратные, как в dsPIC33)), а потому не так уж важно сколько времени займет накопление. Кроме того, скользящее окно в 1К - это серьезно... нужны веские обоснования для подобных обработок, достаточно прикинуть полосу такого фильтра (добротность 1000), а еще нужно позаботится о стабильном интервале накопления, иначе проку с такого фильтра - чуть... А как раз обработка во время заполнения и не прибавляет стабильности, ибо увеличчивает латентность процесса...

Так что не все так очевидно...

В догон. Откомпилируйте Ваши "две лишних арифметических операции в прерывании" и Вы сильно удивитесь их длине... Те же 30...50 маш.циклов в прерывании это совсем другое....

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

Не о том спорите. +-50 оборотов конечно не важно, Но когда измеряемая величина будет находится на границе при любой простой фильтрации будет мерцание значений.

Тот алгоритм что я предлагаю, не требует применения никаких буферов, тем не менее сглаживает показания и отлично реагирует на быстрые(понятие весьма относительное и не означает "мгновенные") изменения.

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

При 0,5...1 сек периода регенерации дисплея никаких мерцаний с усреднением и гистерезисной "резинкой" нет. Это ПРАКТИКА. Показания тягуче и плавно меняются, их легко прочитать, задержка в реальных режимах практически неуловима.

Так делают все цифровые приборы с относительно динамичными показаниями (спидометр и тахометр).

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

Мда, дисскуссиия серьезная :)

Понятно на практическом уровне, но не совсем понял на программном, как предлагает сделать ув.my504.

За пол дня раздумий я родил примерно такой код для сглаживания:

//период буду считать не с 1 оборота, а с 8-ми (ИМХО 1 оборот это слишком)

unsigned char d[8];//массив для хранения приращений последних 8 значений показаний

unsigned char Result; //переменная оконечного рез-та, вывод. на дисплей
unsigned char Result1; //переменная, хранящая данные о текущем расчете частоты вращения КВ.
unsigned char Result2; //переменная хранения предыдущего результата измерений (==Result, вывод в прошлый раз)
us char i;

for(i=6;i>0;i--){   //сдвиг результатов вычислений приращений на 1 позицию "вверх" по массиву данных
d (i+2)= d (i++); //для первого прохода цикла занчит д8=д7, для 2-го д7=д6 и т.д.
}

d 1= Result1-Result2; //вычисление последнего приращения

prirost=((d1+d2+d3...+d8)>>3);//прирост величины с учетом последнего приращения

Result=Result1+ prirost; //вычисление оконечного рез-та, выводимого на экран

Result1=Result;//обновление переменной предыдущего зн-я результата

Просьба исправить что не так. Или, если это полная глупость, то скажите :unsure:

Если все будет хорошо, завтра все проверю. Сейчас решаю вопрос о генераторе со звуковухой.

Впринципе, при таком раскладе, период обновлений на частоте в 3000 об/мин, составляет (по моему) около 1 секунды. Этого с головой. Вопрос, как раз в плавности. На высокой частоте, погрешность даже в 300 оборотов не есть вешь фатальная - все равно при езде тахометр вещь чисто оценочная. А при настройке ХХ, точность показаний возрастает, т.к. нет скачков. Выставил себе и все :) :) :)

P.S. Еще вопрос в догонку: если я к МК подцеплю керамический излучатель и ШИМ реализую, чтобы пикал, то будет работать? Какая частота ШИМ нужна? Хочу на заднюю крышку сделать, чтобы пикало при достижении 6000.

Изменено пользователем Дмитрий Андреевич
Ссылка на комментарий
Поделиться на другие сайты

Спасибо большое!

Можете, если так проще, просто описать текстом. Циклы, условия я набросаю :)

Еще раз спасибо за помощь...

Ссылка на комментарий
Поделиться на другие сайты

:)

Нетерпится, Дмитрий?

Извините, вчера не успел, занимался до поздна автомобилем...

По теме.

Итак, имеем тахометр с диапазоном измерений периодов 8...150мс, что соответствует диапазону частот коленвала 400...7500 об/мин.

Если ограничится разрешением измерения на верхней частоте вращения 10 об/мин (на нижней будет 1об/мин), то достаточно измерять период с разрешением в 4 мкс и тогда для него хватает разрядности 16.

Таким образом берем 16 разрядный счетчик/таймер конфигурируем его в режим счета опорной частоты 250кгц (период 4 мкс) и импульсами с датчика коленвала производим захват его показаний и одновременный его сброс. Не знаю как это конфигурируется в Ваших любимых AVR, а в ПИКах это осуществляется режимом Capture модуля CaptureComparePWM (CCP).

Таким образом, получается поток данных в прерываниях от упомянутого модуля.

Заводим в нашей программе переменную-счетчик-указатель массива. В каждом прерывании ПОСЛЕ пересылки полученной от таймера величины в массив мы инкрементируем ( i = i+1 ) эту переменную и накладываем на нее маску ( i = i & 0x07 ). Это для 8-элементного массива (для 4-х элементного маска будет 0х03, для 16-элементного соответственно 0х0F).

После этих мероприятий у нас счетчик-указатель будет обеспечивать кольцевое заполнение массива int (помним, что у нас 16 разрядные данные поступают от таймера) в перывании.

Теперь об основной программе.

Для упомянутых длин массивов (4, 8 или 16) заводим 24 разрядную переменную temp_AVG (временное среднее). По сути это будет сумма всех элементов массива. Далее я буду говорить только о массиве в 8 элементов, но подразумеваются варианты на 4 или 16.

1. Находим сумму всех элементов массива temp_AVG. Есть одно замечание по этому пункту. Так как суммируются 16 разрядные элементы, а контроллер 8 разрядный, то во избежании коллизий в цикле суммы необходимо непосредственно перед строкой суммы запретить прерывание, скопировать текущий суммируемый элемент массива в локальную переменную типа int (просто временную), разрешить прерывание, а затем суммировать уже эту временную локальную переменную. Иначе данные могут быть изменены во время суммирования и результат будет некорректный.

2. Сдвигаем вправо эту сумму на 3 разряда и приводим к типу int (далее это будет переменная AVG).

3. Вычисляем обороты по формуле: int RPM = 15000000/AVG. Ранее я Вам приводил упрощение этой формулы, но в данном случае на Си этого делать нельзя, поскольку будут потеряны значащие разряды.

4. Вычитаем из полученной величины значение оборотов предыдущего измерения. Для этого нужно в начале завести переменную int old_RPM. Разницу (delta) проанализировать:

- если ((delta<-5) & (delta> 5)), то old_RPM = RPM, иначе оставить старое значение old_RPM. (гистерезис +/-5).

5. Преобразовать old_RPM в двоично-десятичную форму. Вывести на дисплей.

6. Вернутся к пункту 1. Бесконечный цикл.

Таким образом есть два процесса. Один через прерывание заполняет массив, второй обрабатывает его и выводит на индикацию.

Изменено пользователем my504

戦う前に相手のベルトの色に注目

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...