#1 2016-06-10 09:29:15

Terraformer
Учасник
Зареєстрований: 2016-06-10
Повідомлень: 5

Наладка преобразователя частоты

Мой дипломный проект - система ПЧ-АД со звеном постоянного тока. Делается это на основе Arduino Due, частота ШИМ - 5 кГц и всё бы хорошо, но вот двигатель подозрительно дёргается в процессе работы. Дёргается он так, как будто бы в определённые моменты времени тормозит. Сколько не снимал я осциллограмм, ничего внятного не обнаружил, пытался избавляться от помех, менять выводы, генерирующие ШИМ с таймерных на выводы ШИМ-контроллера, всё без толку. Вот код:

/* Програмне забезпечення для 
 * системи ПЧ-АД на основі Arduino Due
 * 
 * 17.05.2016, версія програми 0.17
 * 
 * Автор ст. гр. ЭПА-12 Швыдкий Д. О.
 * 
 */

#include <LiquidCrystal.h>
// Кількість кроків синусоїди (повинно бути кратно 6)
#define stepsNum 60
// Індикатори роботи системи
#define ledR 22
#define ledL 23
#define led 13
// Кнопки
#define stopB 33
#define setB 37
#define rightB 35
#define leftB 36
#define upB 39
#define downB 34
#define backB 32
// Вивід, до якого підключено потенціометр
#define potPin 0
// Виводи плати, що контролюють активацію певних транзисторів
#define vt1 24
#define vt3 25
#define vt5 26
#define vt4 27
#define vt6 28
#define vt2 29
// Виводи для ШІМ фаз А, В та С
#define PWMa 6
#define PWMb 7
#define PWMc 8
// Вивод, що контролює зарядний контактор
#define relayPin 44
// Виводи аварійного зворотнього зв'язку
#define overloadPin 46
#define overheatPin 47
// Виводи перевірки нормальної роботи плати
#define securityPin1 30
#define securityPin2 31
// Максимальне отримуване значення з потенціометра
#define pMax 4096
// Мінімальне отримуване значення з потенціометра
#define pMin 0
// Коефіцієнт пропорційності частоти
// (використовується під час налагодження)
#define k 1
// Прив'язка дисплея до певних виводів плати
// d7 - 38, d6 - 41, d5 - 40, d4 - 43, e - 42, rs - 45
LiquidCrystal lcd(45, 42, 43, 40, 41, 38);

// Інформація про стан системи
char* message[] ={"", "  !!OVERHEAT!!  ", "  !!OVERLOAD!!  ", "   !!TESTING!!  "};
byte mesNum = 0;

// Значення напруг, що необхідно отримати на виході
int Ua, Ub, Uc,
// Етап модуляції синусоїди для кожної фази
stepA, stepB, stepC,
// Дані з потенціометра
pData;

// Допоміжні параметри
float Df, a1,
// Частота, яку необхідно досягти на виході
fTarget = 10,
// Мінімальна припустима частота
fMin = 10,
// Максимальна частота
fMax = 50,
// Поточне значення частоти
f = 10,
// На скільки буде зростати частота при оновленні
df,
// Швидкість зміни частоти {Гц/с}
dfRate = 8,
// Коефіцієнт пропорційності для пропорційного закону скалярного керування
kU = 81.92;

// Таблиця значень синуса
// (розраховується на початку програми)
float sinHalph[stepsNum];

// Всі змінні часу у мікросекундах
// Амплітуда вихідної напруги
long amplitude,
// Час кожного кроку
stepLength,
// Час початку поточного кроку синусоїди
currentStepTime,
// Інтервал оновлення внутрішніх параметрів системи
// (інтервал виклику функції update())
updateInterval = 8000,
// Інтервал виводу даних на дисплей
outputInterval = 200000,
// Час останнього виводу даних
prevOutputTime = 0,
// Час останнього оновлення внутрішніх параметрів
prevUpdateTime = 0;

// Якщо true, то напруга подана на двигун
bool activated = false,
// Параметри активації верхніх транзисторів моста інвертора
HA = true,
HB = false,
HC = true,
// Якщо true, частота f поступово наближається до fTarget
fChanging = false,
// Флаги кнопок
up = false,
down = false,
right = false,
left = false,
back = false,
set = false;

// Налаштування параметрів роботи плати і завдання початкових значень для змінних
void setup() {
  //PWMC_ConfigureClocks(5000 * PWM_MAX_DUTY_CYCLE , 0, VARIANT_MCK);
  // ініціалізація дисплея
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("starting");
  // Налаштування виводів плати на прийом чи передачу
  pinMode(led, OUTPUT);
  pinMode(vt1, OUTPUT);
  pinMode(vt2, OUTPUT);
  pinMode(vt3, OUTPUT);
  pinMode(vt4, OUTPUT);
  pinMode(vt5, OUTPUT);
  pinMode(vt6, OUTPUT);
  pinMode(ledL, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(securityPin1, OUTPUT);
  pinMode(securityPin2, OUTPUT);
  pinMode(stopB, INPUT);
  pinMode(setB, INPUT);
  pinMode(rightB, INPUT);
  pinMode(leftB, INPUT);
  pinMode(upB, INPUT);
  pinMode(downB, INPUT);
  pinMode(backB, INPUT);
  pinMode(overloadPin, INPUT);
  pinMode(overheatPin, INPUT);
  // Ініціалізація з'єднання з ПК
  Serial.begin(115200);
  // Індикація робочого стану плати
  digitalWrite(led, HIGH);
  digitalWrite(ledR, HIGH);
  delay(200);
  digitalWrite(led, LOW);
  digitalWrite(ledR, LOW);
  // Використання 12-бітної ШІМ
  analogWriteResolution(12);
  // Використання 12-бітного АЦП
  analogReadResolution(12);
  // Розрахунок допоміжних параметрів
  addParSetup();
  // Крок, з яким буде розрахована таблиця синуса
  float sinStep = 3.1416/stepsNum;
  // Розрахунок таблиці синуса
  for(int i = 0; i <= stepsNum; i++){                       
    sinHalph[i] = sin(i*sinStep);
  }
  // Завдання початкових точок для ШІМ-сигналів
  stepA = 0; 
  stepB = stepsNum/3;
  stepC = (stepsNum/3)*2;
  //Зарядка конденсаторів ланки постійного струму 
  lcd.clear();
  lcd.print("charging");
  delay(1000);
  digitalWrite(relayPin, HIGH);
  lcd.clear();
  digitalWrite(securityPin1, LOW);
  digitalWrite(securityPin2, LOW);
  // Початкове оновлення основних параметрів
  update(); 
  // Перше зчитування завдання на частоту
  fTargetRead();
  //Початок роботи системи
  currentStepTime = micros();
}

// Головна частина програми, яка буде повторюватись у нескінченному циклі
void loop() {
  // Перевірка стану аварійного зворотнього зв'язку
  if(digitalRead(overloadPin) == LOW){
    stopSystem();
    mesNum = 2;
  }
  else if (digitalRead(overheatPin) == LOW){
    mesNum = 1;
    stopSystem();
  }
  else mesNum = 0;
  // Перехід на інший крок синусоїди якщо прийшов час це зробити
  if((micros() - currentStepTime >= stepLength)){
    stepService();
  }
  // Оновлення параметрів системи якщо прийшов час це зробити
  if(micros() - prevUpdateTime >= updateInterval){
    // Зчитування даних з пульта керування
    buttonService();
    // Оновлення
    update();
  }
  // Перехід на інший крок синусоїди якщо прийшов час це зробити
  if((micros() - currentStepTime >= stepLength)){
    stepService();
  }
  // Виведення даних на дисплей якщо прийшов час це зробити
  if(micros() - prevOutputTime >= outputInterval){
    output();
  }
  // Перехід на інший крок синусоїди якщо прийшов час це зробити
  if((micros() - currentStepTime >= stepLength)){
    stepService();
  }
}

// Оновлення стану системи в залежності від часу і керуючих сигналів
void update(){
  // тут забеспечено плавну зміну частоти
  if(fChanging == true){
    digitalWrite(ledL, HIGH);
    if(f < fTarget){
      f = f + df;
    }
    else{
      f = f - df;
    }
    // Визначення довжини кроку синусоїди після зміни частоти
    stepLength = k * 1000000 / (f * stepsNum);
    // Зміна напруги пропорційно частоті
    amplitude = f * kU;
  }
  if(activated == false){
    amplitude = 0;
  }
  // Якщо досягнуто значення необхідної частоти, її зміна припиняється
  if(abs(f - fTarget) <= 2.0*df){
    fChanging = false;
    digitalWrite(ledL, LOW);
  }
  // Визначення часу наступного оновлення параметрів
  prevUpdateTime = micros();
}

// Обслуговування кнопок
void buttonService(){
  // Зупинка системи
  if(digitalRead(stopB) == LOW){
    stopSystem();
  }
  else{
    // Активація 
    if((activated == false) & (digitalRead(rightB) == LOW)){
      update();
      activated = true;
      fChanging = true;
    }
    else{
      // Зміна частоти
      if((activated == true) & (digitalRead(setB) == LOW)){
        if(f != fTarget){
          fChanging = true;
        }
      // Зчитування інших кнопок
        // Вгору
        if(digitalRead(upB) == LOW){
          up = true;
        }
        else{
          up = false;
        }
        // Вниз
        if(digitalRead(downB) == LOW){
          down = true;
        }
        else{
          down = false;
        }
        //Вправо
        if(digitalRead(rightB) == LOW){
          right = true;
        }
        else{
          right = false;
        }
        //Вліво
        if(digitalRead(leftB) == LOW){
          left = true;
        }
        else{
          left = false;
        }
        //Центр
        if(digitalRead(setB) == LOW){
          set = true;
        }
        else{
          set = false;
        }
        // Назад
        if(digitalRead(backB) == LOW){
          back = true;
        }
        else{
          back = false;
        }
      }
    }
  }
}

// Зупинка привода
void stopSystem(){      
  activated = false;
  fChanging = false;
  f = fMin;
}

// Зчитування необхідної частоти
void fTargetRead(){
  // Зчитування напруги потенціометра
  pData = analogRead(potPin);
  // Розрахунок частоти
  fTarget = (pData * Df + a1)/pMax;
}

// Виведення інйормації на дисплей
void output(){
  fTargetRead();
  lcd.setCursor(0,0);
  lcd.print("Set f=");
  lcd.setCursor(6,0);
  lcd.print(fTarget);
  lcd.print("  ");
  lcd.setCursor(0, 1);
  lcd.print("U=");
  lcd.print(map(amplitude, 0, 4086, 0, 380));
  lcd.print("  ");
  lcd.setCursor(6, 1);
  lcd.print("f=");
  lcd.print(f);
  lcd.setCursor(0, 0);
  lcd.print(message[mesNum]);
  prevOutputTime = micros();
}

// Оновлення стану керуючих виводів
void stepService(){
  // Завдання коефіцієнта заповнення ШІМ на даний часовий проміжок
  analogWrite(PWMa, Ua);
  analogWrite(PWMb, Ub);
  analogWrite(PWMc, Uc);
  // Перевірка на необхідність вмикання верхнього
  // чи нижнього транзистора фази А
  if((stepA > 1) & (stepA < (stepsNum - 1))){
    // Якщо HA має значення true, то вмикається верхній транзистор
    if(HA == true){
      digitalWrite(vt1, HIGH);
      digitalWrite(vt4, LOW);
    }
    // Інакше вмикається нижній
    else {
      digitalWrite(vt1, LOW);
      digitalWrite(vt4, HIGH);
    }
  }
  // В момент закінчення напівхвилі обидва транзистора закриті
  else{
    digitalWrite(vt1, LOW);
    digitalWrite(vt4, LOW);
  }
  // Аналогічно для фази В
  if((stepB > 1) & (stepB < (stepsNum - 1))){
    if(HB == true){
      digitalWrite(vt3, HIGH);
      digitalWrite(vt6, LOW);
    }
    else {
      digitalWrite(vt3, LOW);
      digitalWrite(vt6, HIGH);
    }
  }
  else{
    digitalWrite(vt3, LOW);
    digitalWrite(vt6, LOW);
  }
  // І для С
  if((stepC > 1) & (stepC < (stepsNum - 1))){
    if(HC == true){
      digitalWrite(vt5, HIGH);
      digitalWrite(vt2, LOW);
    }
    else {
      digitalWrite(vt5, LOW);
      digitalWrite(vt2, HIGH);
    }
  }
  else{
    digitalWrite(vt5, LOW);
    digitalWrite(vt2, LOW);
  }
  // Перехід на інший крок
  stepA++;
  stepB++;
  stepC++;
  // Обнулення лічильника кроків для забезпечення циклічності процесу
  if(stepA > stepsNum){
    stepA = 0;
    if(HA) HA = false;
    else HA = true;
  }
  if(stepB > stepsNum){
    stepB = 0;
    if(HB) HB = false;
    else HB = true;
  }
  if(stepC > stepsNum){
    stepC = 0;
    if(HC) HC = false;
    else HC = true;
  }
  // Розрахунок коефіцієнта заповнення для наступного кроку
  Ua = sinHalph[stepA] * amplitude;
  Ub = sinHalph[stepB] * amplitude;
  Uc = sinHalph[stepC] * amplitude;
  currentStepTime += stepLength;
}

// Альтернатива функції map для роботи з дробовими числами
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max){
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//Розрахунок додаткових параметрів, необхідних в обчисленнях
void addParSetup(){
  Df = fMax-fMin;
  a1 = fMin*pMax;
  df = dfRate*updateInterval/1000000;
}

Принципиальная схема всей системы:
Principialnaja-skhema_20160610-0931.jpeg

Времянные диаграммы управляющих сигналов
Vremjannye-diagrammy-ShIM.jpeg

Осциллограмма управляющего сигнала для одного транзистора (в моём IGBT-модуле они открываются низким уровнем):
lFtamlAo60w.jpg

Осциллограмма линейного напряжения на выходе преобразователя:
efOQ6-DHBTU.jpg

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

Остання редакція Terraformer (2016-06-10 09:32:05)

Неактивний

#2 2016-06-10 10:00:15

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Наладка преобразователя частоты

вы молодцы, Вы один из самых толковых авторов! )

в вашем случае я бы вообще избавился от математики  float,  переведите все на long  or  int64_t (uint64_t)  (float)1,0000 equ 10000
лично я  PWM заполнял бы с DMA, если в данном устройстве  нет DMA  меняйте  контроллер, как вариант на тинси, 1 шт можно забить на цену 
все остальные от лукавого, но как для диплома подойдет )
тут уже сами, по времени, работающий вариант гораздо лучше идеологически правильного , но не работающего устройства )

add
уберите все лишнее из рабочего цикла, те сбои что ищите осцилографом не увидите
де то неравномерность вывода  дает такой эффект,
обновление PWM на таймер сделайте что ли
уберите индикатор
add
это 100% убрать,

  // Виведення даних на дисплей якщо прийшов час це зробити
  if(micros() - prevOutputTime >= outputInterval){
    output();
  }
когда переведете на таймер рабочий цикл по синусу
вернете )
успеха

Остання редакція NoName (2016-06-10 10:07:05)

Неактивний

#3 2016-06-10 23:30:18

Terraformer
Учасник
Зареєстрований: 2016-06-10
Повідомлень: 5

Re: Наладка преобразователя частоты

NoName пише:

вы молодцы, Вы один из самых толковых авторов! )

в вашем случае я бы вообще избавился от математики  float,  переведите все на long  or  int64_t (uint64_t)  (float)1,0000 equ 10000
лично я  PWM заполнял бы с DMA, если в данном устройстве  нет DMA  меняйте  контроллер, как вариант на тинси, 1 шт можно забить на цену 
все остальные от лукавого, но как для диплома подойдет )
тут уже сами, по времени, работающий вариант гораздо лучше идеологически правильного , но не работающего устройства )

add
уберите все лишнее из рабочего цикла, те сбои что ищите осцилографом не увидите
де то неравномерность вывода  дает такой эффект,
обновление PWM на таймер сделайте что ли
уберите индикатор
add
это 100% убрать,

  // Виведення даних на дисплей якщо прийшов час це зробити
  if(micros() - prevOutputTime >= outputInterval){
    output();
  }
когда переведете на таймер рабочий цикл по синусу
вернете )
успеха

Скачал библиотеку DueTimer.h, по быстрому переделал код, так как времени было в обрез, залил. Слава прерываниям, всё заработало, но возникла ещё одна проблема - несинусоидальность тока в обмотках двигателя:
ad-50--kopija.jpg
Вверху - напряжение, внизу - ток, частота - 50 Гц.

Переделаный код выглядит так:

/* Програмне забезпечення для 
 * системи ПЧ-АД на основі Arduino Due
 * 
 * 17.05.2016, версія програми 0.18
 * 
 * Автор ст. гр. ЭПА-12 Швыдкий Д. О.
 * 
 */

#include <LiquidCrystal.h>
#include <DueTimer.h>
// Кількість кроків синусоїди (повинно бути кратно 6)
#define stepsNum 60
// Індикатори роботи системи
#define ledR 22
#define ledL 23
#define led 13
// Кнопки
#define stopB 33
#define setB 37
#define rightB 35
#define leftB 36
#define upB 39
#define downB 34
#define backB 32
// Вивід, до якого підключено потенціометр
#define potPin 0
// Виводи плати, що контролюють активацію певних транзисторів
#define vt1 24
#define vt3 25
#define vt5 26
#define vt4 27
#define vt6 28
#define vt2 29
// Виводи для ШІМ фаз А, В та С
#define PWMa 6
#define PWMb 7
#define PWMc 8
// Вивод, що контролює зарядний контактор
#define relayPin 44
// Виводи аварійного зворотнього зв'язку
#define overloadPin 46
#define overheatPin 47
// Виводи перевірки нормальної роботи плати
#define securityPin1 30
#define securityPin2 31
// Максимальне отримуване значення з потенціометра
#define pMax 4096
// Мінімальне отримуване значення з потенціометра
#define pMin 0
// Коефіцієнт пропорційності частоти
// (використовується під час налагодження)
#define k 1
// Прив'язка дисплея до певних виводів плати
// d7 - 38, d6 - 41, d5 - 40, d4 - 43, e - 42, rs - 45
LiquidCrystal lcd(45, 42, 43, 40, 41, 38);

// Інформація про стан системи
char* message[] ={"", "  !!OVERHEAT!!  ", "  !!OVERLOAD!!  ", "   !!TESTING!!  "};
byte mesNum = 0;

// Значення напруг, що необхідно отримати на виході
int Ua, Ub, Uc,
// Етап модуляції синусоїди для кожної фази
stepA, stepB, stepC,
// Дані з потенціометра
pData;

// Допоміжні параметри
float Df, a1,
// Частота, яку необхідно досягти на виході
fTarget = 10,
// Мінімальна припустима частота
fMin = 10,
// Максимальна частота
fMax = 50,
// Поточне значення частоти
f = 10,
// На скільки буде зростати частота при оновленні
df,
// Швидкість зміни частоти {Гц/с}
dfRate = 8,
// Коефіцієнт пропорційності для пропорційного закону скалярного керування
kU = 81.92;

// Таблиця значень синуса
// (розраховується на початку програми)
float sinHalph[stepsNum];

// Всі змінні часу у мікросекундах
// Амплітуда вихідної напруги
long amplitude,
// Час кожного кроку
stepLength,
// Час початку поточного кроку синусоїди
currentStepTime,
// Інтервал оновлення внутрішніх параметрів системи
// (інтервал виклику функції update())
updateInterval = 8000,
// Інтервал виводу даних на дисплей
outputInterval = 200000,
// Час останнього виводу даних
prevOutputTime = 0,
// Час останнього оновлення внутрішніх параметрів
prevUpdateTime = 0;

// Якщо true, то напруга подана на двигун
bool activated = false,
// Параметри активації верхніх транзисторів моста інвертора
HA = true,
HB = false,
HC = true,
// Якщо true, частота f поступово наближається до fTarget
fChanging = false,
// Флаги кнопок
up = false,
down = false,
right = false,
left = false,
back = false,
set = false;

// Налаштування параметрів роботи плати і завдання початкових значень для змінних
void setup() {
  //PWMC_ConfigureClocks(5000 * PWM_MAX_DUTY_CYCLE , 0, VARIANT_MCK);
  // ініціалізація дисплея
  lcd.begin(16, 2);
  lcd.clear();
  lcd.print("starting");
  // Налаштування виводів плати на прийом чи передачу
  pinMode(led, OUTPUT);
  pinMode(vt1, OUTPUT);
  pinMode(vt2, OUTPUT);
  pinMode(vt3, OUTPUT);
  pinMode(vt4, OUTPUT);
  pinMode(vt5, OUTPUT);
  pinMode(vt6, OUTPUT);
  pinMode(ledL, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(securityPin1, OUTPUT);
  pinMode(securityPin2, OUTPUT);
  pinMode(stopB, INPUT);
  pinMode(setB, INPUT);
  pinMode(rightB, INPUT);
  pinMode(leftB, INPUT);
  pinMode(upB, INPUT);
  pinMode(downB, INPUT);
  pinMode(backB, INPUT);
  pinMode(overloadPin, INPUT);
  pinMode(overheatPin, INPUT);
  // Ініціалізація з'єднання з ПК
  Serial.begin(115200);
  // Індикація робочого стану плати
  digitalWrite(led, HIGH);
  digitalWrite(ledR, HIGH);
  delay(200);
  digitalWrite(led, LOW);
  digitalWrite(ledR, LOW);
  // Використання 12-бітної ШІМ
  analogWriteResolution(12);
  // Використання 12-бітного АЦП
  analogReadResolution(12);
  // Розрахунок допоміжних параметрів
  addParSetup();
  // Крок, з яким буде розрахована таблиця синуса
  float sinStep = 3.1416/stepsNum;
  // Розрахунок таблиці синуса
  for(int i = 0; i <= stepsNum; i++){                       
    sinHalph[i] = sin(i*sinStep);
  }
  // Завдання початкових точок для ШІМ-сигналів
  stepA = 0; 
  stepB = stepsNum/3;
  stepC = (stepsNum/3)*2;
  //Зарядка конденсаторів ланки постійного струму 
  lcd.clear();
  lcd.print("charging");
  delay(1000);
  digitalWrite(relayPin, HIGH);
  lcd.clear();
  digitalWrite(securityPin1, LOW);
  digitalWrite(securityPin2, LOW);
  // Початкове оновлення основних параметрів
  update(); 
  // Перше зчитування завдання на частоту
  fTargetRead();
  
  Timer3.attachInterrupt(stepService);
  Timer3.start(stepLength);
  
  //Початок роботи системи
  currentStepTime = micros();
}

// Головна частина програми, яка буде повторюватись у нескінченному циклі
void loop() {
  // Перевірка стану аварійного зворотнього зв'язку
  if(digitalRead(overloadPin) == LOW){
    stopSystem();
    mesNum = 2;
  }
  else if (digitalRead(overheatPin) == LOW){
    mesNum = 1;
    stopSystem();
  }
  else mesNum = 0;
  /*
  // Перехід на інший крок синусоїди якщо прийшов час це зробити
  if((micros() - currentStepTime >= stepLength)){
    stepService();
  }
  */
  // Оновлення параметрів системи якщо прийшов час це зробити
  if(micros() - prevUpdateTime >= updateInterval){
    // Зчитування даних з пульта керування
    buttonService();
    // Оновлення
    update();
  }
  /*
  // Перехід на інший крок синусоїди якщо прийшов час це зробити
  if((micros() - currentStepTime >= stepLength)){
    stepService();
  */
  // Виведення даних на дисплей якщо прийшов час це зробити
  if(micros() - prevOutputTime >= outputInterval){
    output();
  }
  /*
  // Перехід на інший крок синусоїди якщо прийшов час це зробити
  if((micros() - currentStepTime >= stepLength)){
    stepService();
  }
  */
}

// Оновлення стану системи в залежності від часу і керуючих сигналів
void update(){
  // тут забеспечено плавну зміну частоти
  if(fChanging == true){
    digitalWrite(ledL, HIGH);
    if(f < fTarget){
      f = f + df;
    }
    else{
      f = f - df;
    }
    // Визначення довжини кроку синусоїди після зміни частоти
    stepLength = k * 1000000 / (f * stepsNum);
    // Зміна напруги пропорційно частоті
    amplitude = f * kU;
  }
  if(activated == false){
    amplitude = 0;
  }
  // Якщо досягнуто значення необхідної частоти, її зміна припиняється
  if(abs(f - fTarget) <= 2.0*df){
    fChanging = false;
    digitalWrite(ledL, LOW);
  }
  // Визначення часу наступного оновлення параметрів
  prevUpdateTime = micros();
}

// Обслуговування кнопок
void buttonService(){
  // Зупинка системи
  if(digitalRead(stopB) == LOW){
    stopSystem();
  }
  else{
    // Активація 
    if((activated == false) & (digitalRead(rightB) == LOW)){
      update();
      activated = true;
      fChanging = true;
    }
    else{
      // Зміна частоти
      if((activated == true) & (digitalRead(setB) == LOW)){
        if(f != fTarget){
          fChanging = true;
        }
      // Зчитування інших кнопок
        // Вгору
        if(digitalRead(upB) == LOW){
          up = true;
        }
        else{
          up = false;
        }
        // Вниз
        if(digitalRead(downB) == LOW){
          down = true;
        }
        else{
          down = false;
        }
        //Вправо
        if(digitalRead(rightB) == LOW){
          right = true;
        }
        else{
          right = false;
        }
        //Вліво
        if(digitalRead(leftB) == LOW){
          left = true;
        }
        else{
          left = false;
        }
        //Центр
        if(digitalRead(setB) == LOW){
          set = true;
        }
        else{
          set = false;
        }
        // Назад
        if(digitalRead(backB) == LOW){
          back = true;
        }
        else{
          back = false;
        }
      }
    }
  }
}

// Зупинка привода
void stopSystem(){      
  activated = false;
  fChanging = false;
  f = fMin;
}

// Зчитування необхідної частоти
void fTargetRead(){
  // Зчитування напруги потенціометра
  pData = analogRead(potPin);
  // Розрахунок частоти
  fTarget = (pData * Df + a1)/pMax;
}

// Виведення інйормації на дисплей
void output(){
  fTargetRead();
  lcd.setCursor(0,0);
  lcd.print("Set f=");
  lcd.setCursor(6,0);
  lcd.print(fTarget);
  lcd.print("  ");
  lcd.setCursor(0, 1);
  lcd.print("U=");
  lcd.print(map(amplitude, 0, 4086, 0, 380));
  lcd.print("  ");
  lcd.setCursor(6, 1);
  lcd.print("f=");
  lcd.print(f);
  lcd.setCursor(0, 0);
  lcd.print(message[mesNum]);
  prevOutputTime = micros();
}

// Оновлення стану керуючих виводів
void stepService(){
  // Завдання коефіцієнта заповнення ШІМ на даний часовий проміжок
  analogWrite(PWMa, Ua);
  analogWrite(PWMb, Ub);
  analogWrite(PWMc, Uc);
  // Перевірка на необхідність вмикання верхнього
  // чи нижнього транзистора фази А
  if((stepA > 1) & (stepA < (stepsNum - 1))){
    // Якщо HA має значення true, то вмикається верхній транзистор
    if(HA == true){
      digitalWrite(vt1, HIGH);
      digitalWrite(vt4, LOW);
    }
    // Інакше вмикається нижній
    else {
      digitalWrite(vt1, LOW);
      digitalWrite(vt4, HIGH);
    }
  }
  // В момент закінчення напівхвилі обидва транзистора закриті
  else{
    digitalWrite(vt1, LOW);
    digitalWrite(vt4, LOW);
  }
  // Аналогічно для фази В
  if((stepB > 1) & (stepB < (stepsNum - 1))){
    if(HB == true){
      digitalWrite(vt3, HIGH);
      digitalWrite(vt6, LOW);
    }
    else {
      digitalWrite(vt3, LOW);
      digitalWrite(vt6, HIGH);
    }
  }
  else{
    digitalWrite(vt3, LOW);
    digitalWrite(vt6, LOW);
  }
  // І для С
  if((stepC > 1) & (stepC < (stepsNum - 1))){
    if(HC == true){
      digitalWrite(vt5, HIGH);
      digitalWrite(vt2, LOW);
    }
    else {
      digitalWrite(vt5, LOW);
      digitalWrite(vt2, HIGH);
    }
  }
  else{
    digitalWrite(vt5, LOW);
    digitalWrite(vt2, LOW);
  }
  // Перехід на інший крок
  stepA++;
  stepB++;
  stepC++;
  // Обнулення лічильника кроків для забезпечення циклічності процесу
  if(stepA > stepsNum){
    stepA = 0;
    if(HA) HA = false;
    else HA = true;
  }
  if(stepB > stepsNum){
    stepB = 0;
    if(HB) HB = false;
    else HB = true;
  }
  if(stepC > stepsNum){
    stepC = 0;
    if(HC) HC = false;
    else HC = true;
  }
  // Розрахунок коефіцієнта заповнення для наступного кроку
  Ua = sinHalph[stepA] * amplitude;
  Ub = sinHalph[stepB] * amplitude;
  Uc = sinHalph[stepC] * amplitude;
  Timer3.start(stepLength);
  //currentStepTime += stepLength;
}

// Альтернатива функції map для роботи з дробовими числами
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max){
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

//Розрахунок додаткових параметрів, необхідних в обчисленнях
void addParSetup(){
  Df = fMax-fMin;
  a1 = fMin*pMax;
  df = dfRate*updateInterval/1000000;
}

Времени у меня нет на смену платформы или переделку математики, так как защита уже на следующей неделе, однако и на этом спасибо.

Неактивний

#4 2016-06-11 13:38:14

Terraformer
Учасник
Зареєстрований: 2016-06-10
Повідомлень: 5

Re: Наладка преобразователя частоты

Сегодня в маткаде построил вот такое:
sines.png
Исключая шум, данное построение полностью повторяет форму тока. Уважаемые знатоки, помогите, пожалуйста, избавиться от пятой гармоники.

Неактивний

#5 2016-06-13 09:28:55

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Наладка преобразователя частоты

привет, расскажите как такая форма тока получается, возможные причины.

Неактивний

#6 2016-06-13 16:00:10

Terraformer
Учасник
Зареєстрований: 2016-06-10
Повідомлень: 5

Re: Наладка преобразователя частоты

Есть у меня предположение, что дедтайм большой. Когда одна фаза в этом режиме, схема из трёхфазной превращается в однофазную и фазные напряжения двух других фаз меняются.

Неактивний

#7 2016-06-13 16:20:17

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Наладка преобразователя частоты

deadtime мне ничего не говорит,
из познаний  3 фазы:
сдвинутый по фазе синус )

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

add
deadtime  - перестали генерить синус?

Остання редакція NoName (2016-06-13 17:47:07)

Неактивний

#8 2016-06-13 18:46:02

Terraformer
Учасник
Зареєстрований: 2016-06-10
Повідомлень: 5

Re: Наладка преобразователя частоты

Одну полуволну выходной синусоиды генерирует верхний транзистор трёхфазного моста (к примеру, 1), подключая ШИМом фазу (к примеру, А) шине с положительным напряжением, другую - нижний, подключая к фазу к нулевой шине. В почти любой момент времени работают 3 ключа (к примеру 1, 3 и 2). В момент перехода синусоиды через ноль один транзистор заканчивает работать и начинает работать другой (к примеру, 1 выключается и включается 4). Так как коммутация происходит не мгновенно, первому транзистору необходимо время чтобы окончательно закрыться. Система управления после закрытия транзистора выжидает некоторое время перед тем как включить его соседа чтобы не закоротить выход выпрямителя через 2 открытых транзистора. Это и есть дедтайм - мёртвое время. В такие моменты в схеме инвертора работают 2 ключа (к примеру, 3 и 2). Теперь о вреде несинусоидальности: Асинхронный двигатель по своей структуре напоминает трансформатор, только электрическую энергию преобразует в механическую, а не электрическую с другими параметрами. Идеальное вращающееся поле статора можно создать тремя идеальными синусоидальными токами со сдвигом в 120 градусов. Частота его вращения будет пропорциональна частоте токов, а частота вращения ротора будет устремлена к частоте вращения поля статора. Чем ближе скорость вращения ротора к скорости поля, тем меньше ток в обоих обмотках. А теперь возьмём мои токи, в которых помимо 1 гармоники - тока с частотой 50 Гц присутствует 5 гармоника - 250 Гц. Результирующее поле будет суммой полей всех гармоник тока (в данном случае 1 и 5). Получается, что в движке помимо основного поля присутствует ещё одно, которое вращается в 5 раз быстрее. Разница скоростей этого поля и поля ротора уже значительна, а потому значителен и ток этой частоты. Получается, что в полезную нагрузку идёт только энергия ё гармоники, а 5-я просто рассеивается, нагревая движок. И как я уже выяснил, нагрев этот весьма значителен.
sx.png

Неактивний

#9 2016-06-13 22:30:05

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Наладка преобразователя частоты

верояно неправильно
  Timer3.start(stepLength);
нужен
Timer3 compare  (old+stepLength);
нужно смещение  а не перезапуск, иначе неравномерность срабатывания

float sinHalph[stepsNum];
float неоднозначеное время расчета

Неактивний

#10 2016-06-14 09:15:37

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Наладка преобразователя частоты

http://playground.arduino.cc/Code/SimpleTimer

int setInterval(long d, timer_callback f)

Call function f every d milliseconds. The callback function must be declared as void f().

void repeatMe() {
    // do something
}

timerId = timer.setInterval(1000, repeatMe);

запустите периодичный таймер,  он по идеи должен сдвигать время  compare при каждом прерывании ( проверьте сами )
дело в том что Вы используете таймер в режиме  ...
в общем странно ) если перегружаете таймер  в ноль после умножение на флоат (IEEE754 - почитайте. появится желание навсегда избавится от плавающей  ) то время между сменой значения  PWM будет нестабильно

пробуйте, но на будущее учтите что хороший синус только DMA

Неактивний

#11 2016-06-14 09:23:15

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Наладка преобразователя частоты

http://playground.arduino.cc/Code/SimpleTimer
http://sphinx.mythic-beasts.com/~markt/ … imers.html
и .т.д.

скорее всего Вам в среде ардуино нужно запустить свободный таймер в режиме count UP, и вызывать Вашу функцию по compare с последующим смещением
времени сравнения CCR1+= 1000;  что то типа такого.  мегу не знаю, ищите как сделать сами

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

дело в том что Вы используете таймер в режиме  ...
в общем странно используете ) если перегружаете таймер после умножение на флоат (IEEE754 - почитайте. появится желание навсегда избавится от плавающей точки в контроллере) то время между сменой значения  PWM будет нестабильно, что может влиять на Ваше ЭМ поле 

пробуйте, но на будущее учтите что хороший синус  - только DMA

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму