Подскажите алгоритм

Доброго!
Имею проблемы с построением правильного алгоритма работы функции.
Устройство представляет собой регулятор мощности. Вводные данные: Замер мощности производиться с помощью PZEM 004t. Регулировка при помощи двух “переменных резисторов”, в функции они именуются StepMajor - грубая регулировка, и StepMinor - точная. Значения от 255 до 0, чем меньше значение, тем выше мощность на выходе.
Сейчас наговнокодил так - Допустим, нужная мощность 100. при включении устройства StepMajor = 255, StepMinor=128 т.е. один на минимуме, второй посередине. Плавно снижаю StepMajor, пока мощность не приблизиться к нужной, подгоняю ± и дальше вторым, StepMinor уже поддерживаю нужную цифру. В целом норм. Вот только проблемы начинаются если захочу в процессе изменить мощность, например на 20. Пока я так-же как и при старте скидываю значения и снова подгоняю к нужной мощности. Не нравится.
Если изменить на 1 ватт, то и двигать ничего не надо, само отрегулируется StepMinor. Если на 20 то уже надо StepMajor двигать. Плюс есть большая зависимость от подключенного устройства - если лампа накаливания на 100 ватт, то разброс довольно большой, шаги регулировки мелкие. Если ТЭН на киловатт, то уже и шаги резкие. Хочу универсальности. Так-же PZEMка имеет небольшую инертность, при регулировке могу скакать вверх и вниз, пока она отреагирует правильно. Что, соответственно влияет на время.
Могу всё описать IF-ELSE, добавить массив констант под разные мощности, но получиться портянка говнокода. Может кто поделиться правильными мыслями в подходе.

// Значения на входе функции:
  // power - текущая мощность от PZEM
  // npower - значения необходимой мощности
// Значения на выходе функции:
  // StepMajor - Значение грубой регулировки 0..255 (меньше - выше мощность)
  // StepMinor - Значение плавной регулировки 0..255

        if (PowerAdjust){                                 // Режим грубой настройки
          (power == 0 ? Temp = 1 : Temp = 3);             // Пока мощность на 0 читаем по 1 разу, потом суммируем из трёх замеров
          PowerCalc += power;
          if (Step++ >= Temp){
            PowerCalc /= Temp;
            int16_t calcPower = PowerCalc - npower;
            int16_t newCount = StepMajor;                 
              if (calcPower <= -30) {                     // в зависимости от различия нужной и текущей мощности изменяем количество ступеней 
                newCount-=10;
              } else if (calcPower <= -10){
                newCount-=2;
              } else if (calcPower <= -5){
                newCount-=1;
              } else if (calcPower <= -1){
                newCount-=1;
                down = true;
              } else if (calcPower == 0){
                PowerAdjust = false;                      // мощность совпала - выходим
              } else if (calcPower >= 30){
                newCount+=10;
              } else if (calcPower >= 10){
                newCount+=2;
              } else if (calcPower >= 5){
                newCount+=1;
              } else if (calcPower >= 1){
                newCount+=1;
                up = true;
              }
              if (newCount < 0){ 
                newCount = 0;
              } else if (newCount > 255) {
                newCount = 255;
              }
            StepMajor = newCount;
            if (up && down) { PowerAdjust = false; }      // если и вверх и вниз двигали, то переходим к плавной подгонке
            Step = 1;
            PowerCalc = 0;
            }
          if (!PowerAdjust){
            up = false;
            down = false;
            PowerCalc = 0;
            Step = 1;
          }
        } else {                                         // Режим плавной регулировки, поддержания
            PowerCalc += power;
            if (Step++ == 3){
              PowerCalc /= 3;
              int16_t calcPower = PowerCalc - npower;
              int16_t newCount = StepMinor;
              if (calcPower <= -10) {
                newCount-=10;
              } else if (calcPower <= -5){
                newCount-=3;
              } else if (calcPower <= -2){
                newCount-=1;
              } else if (calcPower >= 10){
                newCount+=10;
              } else if (calcPower >= 5){
                newCount+=3;
              } else if (calcPower >= 2){
                newCount+=1;
              }
              if (newCount < 0){ 
                newCount = 128;
                StepMajor--;
              } else if (newCount > 255) {
                newCount = 128;
                StepMajor++; 
              }
              Step = 1;
              PowerCalc = 0;
              StepMinor = newCount;
            }
          }

Нужен полный код, чтобы можно было скомпилировать и запустить. А это огрызок.
Как ставить диагноз, если пациент только карточку заполнил???

Так тут до алгоритма еще далеко.
Последовательность такая:

  • сначала физика,
  • затем математика,
  • и только потом алгоритм.

Сейчас попробую в эмуляторе сварганить.

Вместо 2-х резисторов ставится 1 энкодер. Медленно крутишь - плавная регулировка, быстро - грубая.

1 лайк

Вот некий симулятор.
Потенциометр типа показания от PZEM. На LCD текущие и нужная мощность.
StepMinor & StepMajor в порт. Новую мощность так-же можно в порт забить, только потом сразу потенциометр в 0 надо убрать.

Сначала надо определиться в каких пределах нужна регулировка и с каким шагом. Если очень хочется задавать мощность двумя резисторами то я бы включил два резистора последовательно, типа 10к грубо и 1к плавно и с одного входа АЦП читал значение. Если сможешь хорошо сделать разводку то от 0 до 1квт с шагом 1 вт ещё можно добиться. Но я бы энкодер использовал. Крутишь нажатый +/-10вт, не нажатый +/-1вт.

Да причём тут энкодеры. Я же выделил резисторы в кавычки, они виртуальные, представлены в виде двух переменных. Вопрос именно в том, как на основании данных о текущей мощности и новой выставленной, быстро отрегулировать значение этими переменными. Вопрос именно математический. Мне не нравится, то, как это сделал я. Вот и интересует, кто бы как написал такую функцию. Две переменные на входе, и две на выходе с некоторой зависимостью. Задача их быстро стабилизировать, и не важно чего они делают, мощность регулируют или уровень воды в баке поддерживают.

Что значит “быстро стабилизировать”? Относительно чего?

Ну раз виртуальные то и крутите их виртуально. Какие проблемы то. Повернул витруально на 874 градуса и всем хорошо стало. В виртуальном мире же че угодно накрутить можно. Правда там переменные ограничены значением 255. Зато резисторы при включении сами занимают нужные положения в зависимости от того, в какую сторону их потом крутить будут.

я не понял PID регулятор не подходит?

1 лайк

Да, что-то вроде. Просто думаю, не слишком мудрено для моей задачи? Или это как раз мой случай?

Примерно в 20 раз проще твоего фарша

Спасибо, норм тема!
Никогда не пользовался, сейчас с коэффициентами разбираюсь.


Если речь о некоем регуляторе, то там может быть несколько входов, но только один выход!
Каков физический смысл крутить виртуальные крутилки? Чтобы что?

1 лайк

Виртуальные крутилки, это в контексте вопроса. Две переменные, от значения которых зависит мощность на выходе.
Какой смысл несет ваш вопрос? Чтобы что?

Чтобы то. Понять воспалённые фантазии)

Две переменные суммировать с нужными коэффициентами, получив одно значение. Его и использовать.

Или то же самое, но второго порядка:
z = a*x^2 + b*y^2 + c*x*y + d*x + e*y + f

2 лайка

ТСу нужна была математика, вот она)

У меня два узла регулировки, всё в стартовом топике описал. На каждый узел своя переменная. По сути, мне нормально подошёл ПИД, только он тоже не быстрее, из-за PZEM, только красивый. Регулировать достаточно грубую переменную, вторая только поддерживает точность установки, медленными шагами изменения сопротивления.
Поэтому, энкодеры, объединения и прочее - вне сути вопроса.