Среднеквадратичное значение напряжения

Прошла неделя, когда я боролся с Arduino, чтобы измерить среднеквадратичное значение напряжения. По OSC я вижу, что среднеквадратичное значение напряжения изменяется примерно на 3 В. Но я не вижу его через последовательный порт. Я думаю, что у моей выборки или преобразования есть проблема, и я не могу ее найти. Я очень ценю, если кто-нибудь может взглянуть на мои коды и предложить что-нибудь.

float readRMS_new(int pin, int vref) {
  int numReadings[100];
  const unsigned long samplingInterval = 2;  // Интервал между вычислениями RMS в миллисекундах
  unsigned int readingsSum = 0;   // Сумма квадратов показаний
  unsigned int readingsCount = 0; // Количество снятых показаний
  unsigned long lastSamplingTime = 0;  // Время последнего расчета RMS
  float rmsVoltage = 0;
  float finalVoltage = 0;
  float circuitGain = 4.31;  // Коэффициент усиления схемы

  unsigned long currentTime = millis();  // Текущее время

  // Проверяем, не пора ли выполнить вычисление среднеквадратичного значения
  if (currentTime - lastSamplingTime >= samplingInterval) {
    lastSamplingTime = currentTime;  // Обновить время последней выборки

    // Выполняем вычисление среднеквадратичного значения
    for (int i = 0; i < 100; i++) {
      numReadings[i] = analogRead(pin); 
      readingsSum += pow(numReadings[i] - vref, 2);
      readingsCount++;
    }


    // Расчет среднеквадратичного значения напряжения
    float rms = sqrt(readingsSum / readingsCount);
    rmsVoltage = rms * 0.0048;
    finalVoltage = rmsVoltage * circuitGain;

    if (finalVoltage > 0.0f) {
      // Печать среднеквадратичного значения напряжения
      Serial.print("RMS Voltage: ");
      Serial.println(finalVoltage, 3);  // Печать с 3 знаками после запятой
    }

    // Сброс переменных для следующего вычисления RMS
    readingsSum = 0;
    readingsCount = 0;

    return finalVoltage;
  }

  return 0.0f;  // Возвращаем 0, если еще не время выполнять вычисление среднеквадратичного значения
}

С уважением

Фарзане

, 👍0

Обсуждение

Что вызывает readRMS_new()? Подпрограмма обслуживания прерываний или из цикла ()? Но как бы то ни было, со всеми этими математическими функциями он будет медленным., @6v6gt

пожалуйста, опишите сэмплируемый сигнал... добавьте описание к своему вопросу... **не** добавляйте комментарий, @jsotola


2 ответа


2

С этим фрагментом кода связано несколько проблем:

  1. Локальные переменные, т. е. переменные, определенные внутри функций или заключенные в фигурные скобки. блоки, создаются каждый раз, когда выполнение входит в функцию или блок, и уничтожается, когда он покидает его. Таким образом, lastSamplingTime будет всегда равен нулю, когда он проверяется. Если вы хотите, чтобы переменная сохранить его значение при вызовах функции, вы должны либо сделайте его глобальным, либо определите его как static.

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

  3. Ардуино не сможет выполнять более одного считывания каждый раз. 112 мкс или 100 показаний за 11,2 мс. Нет никакого смысла пытаясь обеспечить интервал 2 мс между вычислениями RMS.

  4. Нет смысла считать показания: вы знаете, что снимаете 100 из них.

  5. Следует избегать использования pow() для возведения в квадрат целого числа: это функция с плавающей запятой, которая подвержена ошибкам округления.

  6. Возможно, самая серьезная проблема: на Mega unsigned int 16-битный и не может хранить числа больше 65 535. Сумма показаний очень вероятно, что он переполнится и даст вам бессмысленный результат.

  7. Возврат нуля для обозначения отсутствия данных, вероятно, не очень хороший выбор, так как ноль также является вполне допустимым результатом. Вам следует рассмотрите возможность возврата невозможного значения, например -1 (среднеквадратичное значение не может быть отрицательным).

Вот как я бы написал вычисление среднеквадратичного значения:

long readingsSum = 0;
for (int i =0; i < 100; i++) {
    long reading = analogRead(pin) - vref;
    readingsSum += reading * reading;
}
float rms = sqrt(readingsSum / 100);

Обратите внимание, что reading имеет тип long, чтобы избежать возведения в квадрат переполнение.

,

0

Спасибо всем за потраченное время. Наконец, увеличив выборку и оптимизировав те же коды, я смог достичь своих целей. Я выложу работающий код для тех, кому он может понадобиться.

float readRMS(int pin, int vref) {

  int lecturas[200]; // объявление матрицы

  float suma = 0; // сумма квадратов

  float rms = 0;  // квадраты означают

  float volt = 0;  //

  float Volt_Final = 0;

  for (int cont = 0; cont < 200; cont++) { 

    lecturas[cont] = analogRead(pin);  

    delayMicroseconds(200);           
  }
  for (int j = 0; j < 200; j++) { 

    //Serial.println(lecturas[j]);

    suma = suma + pow((lecturas[j] - vref), 2);
 
    //Serial.println(сумма);
  }
  rms = sqrt((suma / 200));

  volt = (rms / 1024) * 5; 

  //Serial.println(volt);

  //сумма=0;

  // Сброс переменных для следующего вычисления RMS

  rms = 0;

  lecturas[200] = 0;

  //Volt_Final = (вольт * 4,31); //реальное напряжение с коэффициентом усиления цепи

  return volt;
}
,

lecturas[200] = 0; выходит за границы. Индексы массива от 0 до 199, @SBF