Самодельный измеритель сопротивления петли "фаза-ноль" иногда занижает напряжение

remontmob
Offline
Зарегистрирован: 27.01.2018

Здравствуйте, уважаемые форумчане. я-не специалист в программировании, занимаюсь электромонтажными работами.  решил сделать экспресс-тестер нагрузочной способности проводки  на арудино для себя.

Принцип действия такой. 

1. Сначала прибор измеряет напряжение без нагрузки и запоминает его.

2. Потом, по нажатию кнопки, включается реле, оно подключает нагрузки.

3. Прибор измеряет ток, измеряет напряжение под нагрузкой.

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

Все это выводится на дисплей  1602.

За несколько дней написал прогамму.

вот код.

#include <Wire.h> // библиотека для управления устройствами по I2C 
#include <LiquidCrystal_I2C.h> // подключаем библиотеку для LCD 1602

LiquidCrystal_I2C lcd(0x27, 16, 2); // присваиваем имя lcd для дисплея 16х2

//назначаем переменные
int Vpin = A0; // первый вход напряжения
int Vpin1 = A3;// второй вход напряжения
int Vpin2 = A2;// вход датчик тока


float voltage; // напряжение
float delta; // разница
float current;  // ток
float rezist; // сопротивление

int volts;  // без нагрузки
int  volts2; // под нагрузкой
int delta1; // дельта
float curr; //  ток
float rez; // сопротивление


//блок дефайнов
#define  RELE 2
#define KEY 3


byte delta_sumbol[8] =
{
  B00000,
  B00000,
  B00000,
  B00000,
  
  B00100,
  B01110,
  B11111,
  B00000,
}; //прорисовываем символ дельты

void setup() // процедура setup
{
  analogReference (EXTERNAL);
  Serial.begin(9600);
  lcd.init(); // инициализация LCD дисплея
  lcd.backlight(); // включение подсветки дисплея
  pinMode (RELE, OUTPUT);
  pinMode (KEY, INPUT) ;
  lcd.print("HELLO!");

  delay (500);
  lcd.clear();

lcd.createChar(1, delta_sumbol);// массив символа дельта


}

void loop ()



// кнопку нажали. выводим напряжение без нагрузки + параметры
{
  //под нагрузкой


  if (digitalRead(KEY ) == LOW)


  {




    digitalWrite (RELE , HIGH); // включаем реле.



    //lcd.print("Uan="); // показываем  сохраненную  величину напряжения без нагрузки
    //lcd.print(volts);
    rez = 0; // обнуляем переменную на всякий случай
    rez = (delta1 / curr); // вычисляем сопротивление, деля дельту напряжнений на ток
    lcd.print ("R= ");
    lcd.print(rez);


    // первое напряжение конец
    lcd.setCursor (9, 0);
    //измеряем второе напряжение ПОД НАГРУЗКОЙ
    voltage = 0; // обнуляем переменую на всякий случай

    voltage = (analogRead(Vpin1) +  analogRead(Vpin1) + analogRead(Vpin1) + analogRead(Vpin1) + analogRead(Vpin1) + analogRead(Vpin1) + analogRead(Vpin1) + analogRead(Vpin1)) / 8;

    // voltage = analogRead(Vpin1);
    //Serial.println(Vpin1);

    // получаем измеряемое напряжение
    volts2 = voltage / 1023 * 332,025; // напряжение под нагрузкой. корректироватьu

    Serial.println(Vpin1);
    lcd.print("Uin=");
    lcd.print(volts2);



    // вычисляем разницу напряжений




    lcd.setCursor (0, 1);
    delta1 = (volts - volts2); // вычисляем дифферент напряжений,
    //беря сохраненное напряжение без нагрузки и вычитая из него напряженпие с нагрузкой



lcd.print("\1"); // выводим символ дельты

    //lcd.print("d");
    lcd.print(delta1); //  в этой переменной храниться дифферент напряжений

    lcd.setCursor (4, 1);

    //начинаем измерять ток
    current = 0; //обнуляем переменную на всякий случай
    current = (analogRead(Vpin2) + analogRead(Vpin2) + analogRead(Vpin2) + analogRead(Vpin2) + analogRead(Vpin2) + analogRead(Vpin2) + analogRead(Vpin2) + analogRead(Vpin2)) / 8 ;
    // получаем  среднее арифметическое по  току
    curr = current / 1023 * 33,91; // ток.

    lcd.print("I=");
    lcd.print(curr);

    //заканчиваем измерять ток
    lcd.setCursor (12, 1);
    lcd.print("U"); // показываем  сохраненную  величину напряжения без нагрузки
    lcd.print(volts);


    delay(500);
    lcd.clear();
    // блок ошибки нагрузки, НАЧАЛО

    if (current < 10 ) // если нагрузки нет или она слишком мала (НАСТРАИВАЕМЫЙ ПАРАМЕТР)
    {
      lcd.print("!!CONNECT LOAD!!");
      lcd.setCursor (0, 1); // выводим сообщение
      lcd.print("!MAX 10 А !");
      delay(1000);
      lcd.clear();
    }


    // блок ошибки нагрузки,, КОНЕЦ
  }

  else // пока не нажата кнопка, выводим напряжение без нагрузки и приглашение

  {
    digitalWrite (RELE , LOW ); // пока кнопка не нажата, реле отключено
    voltage = ( analogRead(Vpin) + analogRead(Vpin) + analogRead(Vpin) + analogRead(Vpin) + analogRead(Vpin) + analogRead(Vpin)) / 6;
    //находим среднее арифметическое
    volts = 0; //обнуляем переменную на всякий случай
    volts = voltage / 1023 * 332,025 ;


    lcd.setCursor (0, 0);
    lcd.print("U anLoad= ");
    lcd.print(volts);
    static int volts; // объявляем статическую переменную - напряжение без нагрузки, запоминаем ее для вычисления.
    lcd.print("V");
    lcd.setCursor (0, 1);
    lcd.print ("Press Key!");


    delay(500);
    lcd.clear();

  }

}

 

 

напряжение сети измеряется через трансформатор 220/12, далее- выпрямляется  и через резистивный делитель ( и конденсатор подается на аналоговый выход .

Ток -через измерительный трансформатор -несколько витков на ферритовом кольце, далее-  диод , конденсатор- и на аналоговый вход.

 

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

 

стал тестировать, носить по разным квартирам, проверять.

на большинстве объектов напряжение показывает верно.

но в одной квартире постоянно занижает , показывает 207 вольт вместо 227 по простому тестеру.

 

стал думать. думал, может быть, из=-за большой реактивной мощности в сети ухудшаются параметры трансформатора. ( на подстанции , которая питает дом, висит большая котельная с движками).

ОК, переделал входную измерительную цепь напряжения, вообще транс убрал, пожертвовал гальванической развязкой.  сетевое напряжение  выпрямил мостом, сгладил конером 10,0*400 В и подал через делитель 270 кОм+1,5 кОм ( знаю, что  делитель максимум 10 К по даташиту на ардуино должен быть), выставил все коэффициенты заново. У меня дома все идеально показывает. Приехал туда-  те же 207 В при 227 по китайскому тестер, даже по двум..

 

скажите, что я не понимаю???

 

вот сам тестер.

 
 
 
remontmob
Offline
Зарегистрирован: 27.01.2018

svm
Offline
Зарегистрирован: 06.11.2016

Или какая-то ассиметрия полуволн или мощная импульсная помеха, пики которой мультиметры видят, а Ваш прибор усредняет.

Если питание прибора от той-же сети через импульсный БП, то возможно в квартире есть что-то, что вносит погрешность через цепи питания.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

remontmob, Вы вообще понимаете, что такое переменное напряжение, чем оно отличается от постоянного, и, следовательно, чем способ измерения переменного напряжения отличается от способа измерения постоянного?

И еще: в принципе, если скетч измерения постоянного напряжения еще как-то можно обсуждать без схемы, то обсуждать без схемы измерение переменного напряжения - абсурдно.

1. Опубликуйте на форуме схему измерения.

2. Подробно напишите по-русски, как именно Вы собираетесь измерять величину переменного напряжения. (заодно: какую именно характеристику переменного напряжения Вы хотите измерить? Амплитуду? Среднеквадратичное? Среднее?)

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Во всех розетках пробовали? А на отводе на квартиру?

Исследования, батенька, эксперименты дадут Вам понимание проблем этого мира.

Итак - Вы проверили эту фазу в стояке? Проблема в кабеле от стояка до квартиры? Сделайте замер на вводе в квартиру. Сделайте замеры в нескольких точках квартиры. Возможно при монтаже перепутали нейтраль и землю - бывает, только УЗО вышибает. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

mykaida, какой смысл носиться с прибором по всей квартире, если прибор изначально измеряет мгновенное напряжение в случайном месте синусоиды?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

andriano пишет:

mykaida, какой смысл носиться с прибором по всей квартире, если прибор изначально измеряет мгновенное напряжение в случайном месте синусоиды?

Сомнительно. Я думаю ТС проверил свой прибор. Тут проблема интереснее. Монтаж херовый.

OK0
Offline
Зарегистрирован: 06.03.2020

andriano, 

ТС пишет:

"напряжение сети измеряется через трансформатор 220/12, далее- выпрямляется  и через резистивный делитель ( и конденсатор подается на аналоговый ..."

Так измеряется мгновенное значение напряжения? Все-таки стоит предварительно читать сообщение... (личное мнение).

OK0
Offline
Зарегистрирован: 06.03.2020

remontmob, после выпрямителя вы измеряете своим прибором  амплитудное значение и рассчитываете действующее. Если сигнал не идеально синусоидальный, то будет ошибка. "Китайский мультиметр"  по-видимому измеряет RMS  и показывает правильно. 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Господа - ТС говорит, что всё это происходит только в одной "нехорошей квартире"

В остальных - всё нормально. Давайте отсечём бритвой Оккамы ненужные части!

OK0
Offline
Зарегистрирован: 06.03.2020

mykaida, я так понял, что речь идет об "объекте" - квартира в доме подключенном к "подстанции , которая питает дом, висит большая котельная с движками". Классический генератор искажений синуса. На остальных "объектах" (не этот дом) - всё нормально.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Да если-б на этой фазе от "подстанции" сидела б только одна квартира, то я с Вами согласился бы.

Не...е проблема малость глубже :)

nik182
Offline
Зарегистрирован: 04.05.2015

Для таких измерений необходимо рассчитывать RMS полного периода напряжения сети насколько раз и усреднять. Отдельно для случаев без и с нагрузкой. 328 не потянет. Нужен как минимум блюпил, а лучше блакпил. Кроме того, если нарисовать сему замещения, то при расчёте сопротивление сети необходимо знать текущую нагрузку стоящую параллельно подключаемой для измерений. То есть надо знать мощность или ток через входной фидер. Параллельное сопротивление  надо вводить в расчет до измерений. Делал я такой прибор 15 лет назад на msp430 с аппаратным умножителем 16 битных данных. RMS считался по 200 точкам на период. 12 бит АЦП. Измерял устойчиво. Плохих квартир не встречалось.  

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

Цитата:
328 не потянет

С каково ***(нужное вставить) это она не потянет?

П.С. Я выкладывал, в ветке о стабилизаторе, как измерить ток напряжение, мощность, cosF средствами ардуины.

nik182
Offline
Зарегистрирован: 04.05.2015

Не потянет каждый период. Тут очень важно как можно ближе измерения с и без нагрузки. Если что то включиться в момент измерений между с и без нагрузкой - очень замечательный пример микроволновка, которая регулирует мощность ШИМ с периодом несколько сотен миллисекунд - измерение будет не точным, поэтому надо измерять несколько раз с нагрузкой и без, чередуя. Подключать семисторонним ключом под управлением. 328 только RMS периода считать будет около 200 миллисекунд. А надо сделать как минимум 8 измерений. Общее время измерений более двух секунд. Блюпилы справляются десять раз быстрее.       

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Хей, топикстартер

Ты ещё там жив?

(под  Pink Floyd)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Сопротивление петли фаза-ноль измеряется методом МС-08

OK0
Offline
Зарегистрирован: 06.03.2020

nik182 пишет:

 328 только RMS периода считать будет около 200 миллисекунд. 

Не понял. Что вы имеете ввиду? Основные вычисления происходят  пока АЦП (медленное) готовит следующее преобразование. Потом фактически остается квадратный корень извлечь. Или вы храните где-то результаты измерений за период? 

За период на 328 можно сделать не более 120-160 измерений без потери точности. Время между измерениями - вагон. Считать квадраты, складывать, делить.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Господа. Не советую обсуждать результаты измерений ТС, пока он не опубликует методики.

nik182
Offline
Зарегистрирован: 04.05.2015

RMS это возведение в квадрат или умножение. Если взять 200 точек на период - АЦП 100 мкс оцифровка, нужно умножить 200 раз сложить и вычесть корень. Т.к. АЦП 10 бит, то результат в 16 битном слове, после перемножения - в 32 битном. Их надо складывать потом из суммы извлекать корень. И помнить что в 32 битном слове помещается сумма 64 измерений, для большего количества потребуется 64 битное слово. Посчитайте по тактам процессора сколько это занимает время на 328. Можно уменьшить количество точек оцифровки на период до 50, но при этом падает точность. Для метода двух измерений это предел, после которого быстро растёт ошибка. Соответственно уменьшиться время одного измерения. Но если хочется не индикатор, а измеритель лучше меньше 100 точек на период не опускаться и обязательно ставить НЧ фильтр на половину времени оцифровки. Что тоже дает ошибку в современных условиях нагрузки сети импульсными блоками питания, если частота среза фильтра меньше фронтов бросков напряжения от включения - выключения ИП на вершинах синусоиды. Поэтому надо искать баланс между частотой оцифровки периода сети и временем обработки. 

Но если это только для себя, что бы найти разболтавшиеся крепления проводов в розетках и автоматах, то 50 точек на период хватит для оценки.       

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

RMS это возведение в квадрат или умножение. Если взять 200 точек на период - АЦП 100 мкс оцифровка, нужно умножить 200 раз сложить и вычесть корень. Т.к. АЦП 10 бит, то результат в 16 битном слове, после перемножения - в 32 битном. Их надо складывать потом из суммы извлекать корень. И помнить что в 32 битном слове помещается сумма 64 измерений, для большего количества потребуется 64 битное слово. Посчитайте по тактам процессора сколько это занимает время на 328. Можно уменьшить количество точек оцифровки на период до 50, но при этом падает точность. Для метода двух измерений это предел, после которого быстро растёт ошибка. Соответственно уменьшиться время одного измерения. Но если хочется не индикатор, а измеритель лучше меньше 100 точек на период не опускаться и обязательно ставить НЧ фильтр на половину времени оцифровки. Что тоже дает ошибку в современных условиях нагрузки сети импульсными блоками питания, если частота среза фильтра меньше фронтов бросков напряжения от включения - выключения ИП на вершинах синусоиды. Поэтому надо искать баланс между частотой оцифровки периода сети и временем обработки. 

Но если это только для себя, что бы найти разболтавшиеся крепления проводов в розетках и автоматах, то 50 точек на период хватит для оценки.       

Гля - чукча писатель?

ТС сказал, что проверял аппарат в нескольких точках, а в этой, конкретной, не сложилось.

Гля - да не надо искать проблему в аппарате. Не там она!

OK0
Offline
Зарегистрирован: 06.03.2020

nik182, что-то у нас свами цифры не бьются. Возведение в квадрат 32 бита - 6 микросекунд, сложение - 2 микросекунды. Сто вычислений - 0,8 миллисекунды. Эти вычисления времени не занимают совсем, параллельно измерению происходят. На выходе несколько 32 битных чисел (вы совершенно правильно заметили - в одно не влезет). Нужно найти среднее и извлечь корень. Сколько на это нужно времени? Ну уж точно - меньше полупериода, который все равно потерян.

nik182
Offline
Зарегистрирован: 04.05.2015

Да, погорячился. Цифры для АЛУ без аппаратного умножения. У 328 есть. будет быстрее. Надо бы проверить на натуре. Давно это было с восьмибитными. Когда пять лет назад потребовалось сделать подобное то оказалось что блюпил шесть каналов напряжения и два тока тока на 200 точках считает RMS меньше миллисекунды, то в два буфера по 6 каналов АЦП попеременно периоды не теряются.         

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

Да, погорячился. 

Бывает.

Я надеюсь, что Вы поддержите методику измерения в разных точках, особенно на вводящей фазе? ;) 

nik182
Offline
Зарегистрирован: 04.05.2015

Я не понимаю что Вы называете методикой. Где описание? Обычно всё просто. Сначала измеряешь с наружи до входного автомата. Потом в розетках по комнатам. Сравниваешь. Где сопротивление явно больше идешь по цепи до входного автомата. Обычно находишь точку где винты ослабли. 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

Я не понимаю что Вы называете методикой?

Ну я прямо сейчас начал писать методику. Прямо вот так- волосы назад :) И бесплатно :)

nik182
Offline
Зарегистрирован: 04.05.2015

Я не просил писать, хочу узнать, что Вы подразумеваете под этим словом? Что я должен поддержать? В каких разных точках?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

nik182 пишет:

Я не просил писать, хочу узнать, что Вы подразумеваете под этим словом? Что я должен поддержать? В каких разных точках?

Есть точка отвода от стояка - скажем точка 1.

Есть точка ввода в квартиру - условно - точка 2

Точка на отводе щитка(если он есть) - точка 2 штрих

Розетки - это уровень 3 - вот тут косяки и происходят.

Вы проведите измерения на точках 1-3.

Потом поговорим.

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

nik182 пишет:

Т.к. АЦП 10 бит, то результат в 16 битном слове, после перемножения - в 32 битном. Их надо складывать потом из суммы извлекать корень. И помнить что в 32 битном слове помещается сумма 64 измерений, для большего количества потребуется 64 битное слово. 

Быстро в школу учиться считать! Очередной бредоносец.

АЦП 10 бит, да в 16 битном слове (int). НО! при возведении в квадрат получится максимум 20бит (хоть ты тресни). В 32 бита (unsigned long) влезает 4096 сложений 20 битного числа! Мало тебе отсчетов?!

Если уйти от ардуинизма и использовать прерывания АЦП то:

-получим ~200 измерений на период, без потери точности (как по даташиту);

- возведение в степень (~20тактов) и сложение (~10тактов) можно делать прямо в прерывании (всего доступно ~120 тактов);

-Взятие квадратного корня и все остальное делается в основном цикле.

В итоге измерения можно делать непрерывно.

remontmob
Offline
Зарегистрирован: 27.01.2018

Здравствуйте! спасибо за ответы и извините за долгое молчание - был занят.

 

Косинус фи в сети никак не влияет на показания тестера-  что при 0,87, что при 1 занижает показания. 217 вольт против  227 по встроенному вольтметру счетчика "меркурий" Измерял в электрощитовой дома, косинус фи понижал запуском лифта. 

Прибор питается от обычного трансформаторного блока питания (диодный мост и конденсатор  большой емкости),  потом 7805.

 

Напряжение в сети измеряется амплитудное, потом из него уже высчитывается среднедействующее  (возможно, в этом и ошибка_)

Хотя,  тут http://sagis.ru/blog/?p=53  вольтметр работает по такому же принципу.

 

вот схема входных цепей, она стандартна и ничего нового. 

 

 

возможно, я где-то я глобально ошибаюсь и таким образом точно измерить переменное напряжение нельзя...

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ну, наконец-то хоть в 29-м сообщении появилась схема.

Я правильно прочитал номиналы: 27 Ом и 1.25 Ом?

А какова емкость конденсатора?

remontmob
Offline
Зарегистрирован: 27.01.2018

andriano пишет:

Ну, наконец-то хоть в 29-м сообщении появилась схема.

Я правильно прочитал номиналы: 27 Ом и 1.25 Ом?

А какова емкость конденсатора?

270 кОм и 1,25 кОм, конечно же.))) при 

 

Емкость конденсатора в случае с трансформаторной измерительной цепью- 100 мкФ, во втором случае- 10 мкф

OK0
Offline
Зарегистрирован: 06.03.2020

У меня есть самодельный прибор для измерения действующего напряжения синусоидального сигнала и промышленный прибор для измерения любого сигнала. Когда я измеряю синусоидальный сигнал, они показывают одинаково. Когда я измеряю предположительно несинусоидальный сигнал - по разному. В чем может быть причина? Опережая вопросы местных знатоков, сообщаю. Схема прибора нарисована выше (такая же) только номиналы конденсаторов в 10 раз больше. Корпус трансформатора - черный.

SLKH
Offline
Зарегистрирован: 17.08.2015

remontmob пишет:

Напряжение в сети измеряется амплитудное, потом из него уже высчитывается среднедействующее  (возможно, в этом и ошибка_)

..

возможно, я где-то я глобально ошибаюсь и таким образом точно измерить переменное напряжение нельзя...

Да.

SLKH
Offline
Зарегистрирован: 17.08.2015

OK0 пишет:

У меня есть самодельный прибор для измерения действующего напряжения синусоидального сигнала и промышленный прибор для измерения любого сигнала. Когда я измеряю синусоидальный сигнал, они показывают одинаково. Когда я измеряю предположительно несинусоидальный сигнал - по разному. В чем может быть причина? Опережая вопросы местных знатоков, сообщаю. Схема прибора нарисована выше (такая же) только номиналы конденсаторов в 10 раз больше. Корпус трансформатора - черный.

#34

SLKH
Offline
Зарегистрирован: 17.08.2015

batbaza пишет:

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

вот он те рубильник-то отключит - и чё ты напрограммируешь?

"Раз он центре сымается, то и пущай одной рукой поет, другой свет зажигает. Думает -- тенор, так ему и свети все время.

Теноров нынче нету!"

 

OK0
Offline
Зарегистрирован: 06.03.2020

SLKH пишет:

#34

#8

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

Библа TrueRMS https://github.com/MartinStokroos/TrueRMS

Код проверенный

#include <TrueRMS.h>
#define LPERIOD 250 // Период одного опроса мкС, быстрее в стандартном варианте не получается
#define RMS_WINDOW 160 // Количество семплов, 160 = 2 периода 50Гц
#define ADC_VIN A0
#define ADC_IIN A1
#define I_RANGE 1000  //Коэффициент преобразования тока
#define U_RANGE 1000   //Коэффициент преобразования напряжения
int adcVal_U[170], adcVal_I[170]; //Буфер. Нужно 160, но не хватает, не стал разбираться почему
unsigned long prevMicros;
float acVolts, acCurrents;
Rms RMS_U;  // Напряжение
Rms RMS_I;  //Ток
void setup() {

}
void loop() {
  while (analogRead(ADC_VIN) < 510) {}  //ждем перехода через "0", можно и без этого но так точнее
  while (analogRead(ADC_VIN) > 510) {}
  prevMicros = micros();
  for (int i = 0; i < 170; i++)  //собираем буфер.
  {
    adcVal_U[i] = analogRead(ADC_VIN);
    adcVal_I[i] = analogRead(ADC_IIN);
    while ((micros() - prevMicros) < LPERIOD) {}  //ждем окончания периода
    prevMicros += LPERIOD;
  }


  RMS_U.begin(U_RANGE, RMS_WINDOW, ADC_10BIT, BLR_ON, SGL_SCAN);
  RMS_U.start(); //start measuring
  RMS_I.begin(I_RANGE, RMS_WINDOW, ADC_10BIT, BLR_ON, SGL_SCAN);
  RMS_I.start(); //start measuring



  for (int i = 0; i < 170; i++)
  {

    RMS_U.update(adcVal_U[i]);
    RMS_I.update(adcVal_I[i]);
    if (RMS_U.acqRdy && RMS_I.acqRdy) break;  //если расчет окончен уходим
  }



 RMS_U.publish();
 RMS_I.publish();
  acVolts = RMS_U.rmsVal;
  acCurrents = RMS_I.rmsVal;
}

OK0
Offline
Зарегистрирован: 06.03.2020

отпишусь

nik182
Offline
Зарегистрирован: 04.05.2015

anatoli_nik пишет:

Быстро в школу учиться считать! Очередной бредоносец.

АЦП 10 бит, да в 16 битном слове (int). НО! при возведении в квадрат получится максимум 20бит (хоть ты тресни). В 32 бита (unsigned long) влезает 4096 сложений 20 битного числа! Мало тебе отсчетов?!

Если уйти от ардуинизма и использовать прерывания АЦП то:

-получим ~200 измерений на период, без потери точности (как по даташиту);

- возведение в степень (~20тактов) и сложение (~10тактов) можно делать прямо в прерывании (всего доступно ~120 тактов);

-Взятие квадратного корня и все остальное делается в основном цикле.

В итоге измерения можно делать непрерывно.

Ну ну. Ты мил человек рот свой попредержи немного. Подумай, почитай. Может что полезное выйдет...  в каждом прерывании квадрат...

RMS рассчитывается для переменной составляющей. Любая примесь постоянной даёт ошибку. Подавать на АЦП надо с примесью постоянной составляющей, что бы оцифровать обе полуволны - отрицательную и положительную. Ты точно уверен, что делитель постоянную составляющую будет держать вечно и её можно внести как константу в программу? Нет? Поэтому приходится накапливать буфер за период, считать среднее, отрезать постоянную составляющую, ну RMS потом. Вот только в целых числах не получается. Пример - считает RMS в целых и плавающих. Синусоиду с почти максимальным размахом и не большим смещением и дребезгом. Как раз на пределе суммирования  квадратов int в 32 бита. Что то 4096 не получается. 200 для синуса - предел. Время опять же дает расчёта RMS. Может быстрее сумеешь?  

int data1[200], data2[200], r1;
byte i;
unsigned long t1;

float data3[200];
float r2;

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(0));
}

void loop() {
  for (i = 0; i < 200; i++) data1[i] = (int)(512.0 * sin(3.1415926 * i / 100.0  ) + 500+random(12));
  t1 = micros();
  r1 = rmsi();
  t1 = micros() - t1;
  Serial.print("ti=");
  Serial.print(t1);
  Serial.print(" RMSi=");
  Serial.println(r1);
  t1 = micros();
  r2 = rmsf();
  t1 = micros() - t1;
  Serial.print("tf=");
  Serial.print(t1);
  Serial.print(" RMSf=");
  Serial.println(r2);
  Serial.println();
  delay(5000);
}

int rmsi(void)
{
  int32_t sum;
  byte i;
  sum = 0;
  for (i = 0; i < 200; i++) sum += data1[i];
  sum = sum / 200;
  for (i = 0; i < 200; i++) data2[i] = data1[i] - sum;
  sum = 0;
  for (i = 0; i < 200; i++)  sum += data2[i] * data2[i];
  Serial.print("Sumi=");
  Serial.println(sum);
  return (int)(sqrt(sum / 200));
}

float rmsf(void)
{
  float sum;
  byte i;
  sum = 0;
  for (i = 0; i < 200; i++) sum += data1[i];
  sum = sum / 200.0;
  for (i = 0; i < 200; i++) data3[i] = (float) data1[i] - sum;
  sum = 0;
  for (i = 0; i < 200; i++)  sum += data3[i] * data3[i];
  Serial.print("Sumf=");
  Serial.println(sum);
  return (sqrt(sum / 200.0));
}

Результат:

Sumi=180409
ti=1172 RMSi=30
Sumf=26198016.00
tf=9264 RMSf=361.93
 
Sumi=4294764313
ti=1324 RMSi=0
Sumf=26208012.00
tf=9324 RMSf=361.99
 
Два цикла. Рандом всего на 12 единичек. А какие разные результаты в целых и плавающих! В плавающих точное значение RMS (с последней буквой f в именах). Время расчёта 9.37 мс В целых получается иногда переполнение да и RMS ни разу не посчитался почему то правильно, зато время чуть больше миллисекунды.  
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Исправил ошибку в строке 42:

Sumi=26250696
ti=1704 RMSi=362
Sumf=26250688.00
tf=9272 RMSf=362.00
 
Sumi=26242174
ti=1708 RMSi=362
Sumf=26242136.00
tf=9280 RMSf=362.00
 
Sumi=26162741
ti=1712 RMSi=361
Sumf=26162734.00
tf=9252 RMSf=361.00
 
Sumi=26175605
ti=1712 RMSi=361
Sumf=26175464.00
tf=9280 RMSf=361.00
 
Sumi=26197608
ti=1712 RMSi=361
Sumf=26197602.00
tf=9256 RMSf=361.00
 
Sumi=26176032
ti=1708 RMSi=361
Sumf=26176022.00
tf=9268 RMSf=361.00
 
Sumi=26139566
ti=1708 RMSi=361
Sumf=26139568.00
tf=9244 RMSf=361.00
 
При том, что ошибки в программе еще остались.
 
nik182
Offline
Зарегистрирован: 04.05.2015

Спасибо! Я и не претендую на не погрешимость. Вот только не понимаю в чём ошибка. Замена data2[i] * data2[i] на pow(data2[i],2) приводит к правильному расчёту RMS в целых, но время возрастает до почти 7 мс. Или первое надо в 32 бит конвертить? (int32_t)data2[i]*data2[i] сработало.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

nik182 пишет:

Спасибо! Я и не претендую на не погрешимость. Вот только не понимаю в чём ошибка. Замена data2[i] * data2[i] на pow(data2[i],2) приводит к правильному расчёту RMS в целых, но время возрастает до почти 7 мс. Или первое надо в 32 бит конвертить?

В этой строке происходит переполнение. Нужно:     sum += (long)data2[i] * data2[i];

В этом случае время вычисления тоже возрастает, но не столь радикально.

Ну и еще обратите внимание на строку 14: там время от времени получаются отрицательные числа.

nik182
Offline
Зарегистрирован: 04.05.2015

Поменять 512 на 500.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Да это понятно.

А уж коль скоро Вы приняли решение добавить в сигнал постоянную составляющую, было бы разумно определять ее также через random (один раз на весь массив отсчетов). Еще можно добавить небольшие элементы случайности для частоты и фазы сигнала. Ну, в общем, если уж имитировать реальный сигнал, то ни в чем себе не отказывать. )))

nik182
Offline
Зарегистрирован: 04.05.2015

Можно конечно, но я быстро на коленке сточал исключительно проверить как там со временем. STM в больше чем в 10 раз быстрее. Этого достаточно.  

Собственно результат для блакпила

Sumi=25047595
ti=108 RMSi=353
Sumf=25047578.00
tf=130 RMSf=353.89
 
Sumi=25053676
ti=108 RMSi=353
Sumf=25053664.00
tf=130 RMSf=353.93
 
Разница между int и float минимальная - 108 и 130 микросекунд соответственно.  
remontmob
Offline
Зарегистрирован: 27.01.2018

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

я все понял. не стОит ожидать большой точности от моего метода измерения. 

Отдельное спасибо anatoli_nik  за скетч. 

я все понял.

всем спасибо еще раз

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Ну вот...

Такое хорошее, практически детективное, начало про "нехорошую квартиру" в которой напряжение не мерится и такой слив.