čtvrtek 18. února 2016

DTC - Přímé řízení momentu asynchronního motoru

DTC – Direct Torque Control, přímé řízení momentu. Jedná se o hysterezní metodu řízení toku a momentu určenou především pro asynchronní motory s kotvou nakrátko. Verze popsaná zde vychází z U1 – I modelu.
Schema
 Obr. 1: Blokové schema

1) Měření proudu

Prostorový vektor:



Platí:







Složky proudu získáme měřením ve dvou fázích pomocí transformace Clarkové:



 , kde K volíme 2/3, dále pro vinutí bez vyvedeného středu platí




Výsledné výpočty obsažené v bloku transformace potom:





2) Měření napětí

Složky napětí získáme podle aktuální kombinace sepnutí obdobným způsobem jako složky proudu z napětí meziobvodu UM:





3) Výpočet toků:

Bloky realizují integraci napětí v čase.





Velikost toku je potom:



4) Výpočet momentu:

Bloky násobiček a sčítačka dají výsledný moment, který je třeba korigovat konstantou inverzní k té, co byla zanesena v bloku výpočtu složek proudů.
 
, kde pp je počet pólpárů.


5) Přepínací tabulka

Její výstupy přímo řídí konfiguraci sepnutí tranzistorů v třífázovém můstku. Na vstupech má hysterezní regulátory toku a momentu.
 
Obr. 2: Přepínací tabulka

Hysterezní regulátor toku rozhoduje o tom, kdy se má přepnout na následující prostorový vektor.
 



Pro menší žádaný tok se přepíná dříve a prostorový vektor se tedy pohybuje po menším šeštiúhelníku. Pro větší naopak. Cyklickým přepínáním pracovních oblastí je dosaženo točivého magnetického pole. Tokové vektory působí kolmo k cívkám statoru.

Hysterezní regulátor momentu potom rozhoduje o tom, jestli budou tranzistory sepnuté do aktivního stavu 1 až 6 nebo do konfigurace nulového fázového napětí, tedy stavu 0 nebo 7 podle toho, který je dosažen jediným přepnutím. Tímto řízením je v rámci hystereze dosažen konstantní, kruhový průběh momentu.

Výstupem přepínací tabulky jsou potom tři logické signály každý pro jednu fázi rozhodující o tom, jestli je sepnutý horní nebo dolní tranzistor v dané fázi.

6) Třífázový můstek

Tranzistory, nejčastěji IGBT, zajišťují rozstřídání stejnosměrného napětí meziobvodu podle signálů z přepínací tabulky na jednotlivé fáze asynchronního motoru. Uvedené schema je velmi zjednodušené, pouze pro definování polarity řídících signálů, chybí např. generování deadtimu.

Obr. 3: zjednodušené schema třífázového můstku
Závěr:
Z principu je patrné, že tranzistory nejsou řízeny PWM s fixní spínací frekvencí. Jak často dochází k přepínání je dáno především nastavením hystereze regulátoru momentu, který opakovaně spíná a vypíná aktivní a pasivní stav v oblasti, kde se dle přepínací tabulky zrovna nachází prostorový vektor a tím se snaží udržet žádaný moment motoru.

Šestiúhelník je možno zvětšovat až do maximálního omezeného napětím meziobvodu. Dále pak motor při vyšších otáčkách samovolně přechází do režimu odbuzování, tedy klesá moment.

Realizace v MCU
Chtěl jsem ze zvědavosti zkusit realizovat výpočet uvedený výše, který je vlastně přepisem odevzdávaného protokolu, v MCU na prototypové desce s 3f můstkem, který jsem do té doby používal se skalární regulací. Zde je schema, pár fotek a videa, jak to zatím vypadá. V příloze pak kousek upraveného kódu.




S namontovaným chladičem

Úvodní video ze začátků ladění, aneb když to konečně začalo nějak fungovat



Příloha:
Z průbehu vypočteného toku je vidět, že algoritmus nefungoval úplně koretně ještě a vnášel tam jistý offset. (vykresleno přímo z dat přenesených z MCU)

Příloha:
/* Transformace */
        I_alpha = I_a;
        I_beta = (I_a + 2*I_b);
        I_beta = I_beta*57735/100000;
 
/* Stanoveni fazovych napeti */
        switch(vektor)
        {
            case 0:
            {
                U_alpha = 0;
                U_beta = 0;
            }
            break;
            case 1:
            {
                U_alpha = U_m;
                U_beta = 0;
            }
            break;
            case 2:
            {
                U_alpha = U_m/2;
                U_beta = U_m*86603/100000;
            }
            break;
            case 3:
            {
                U_alpha = -U_m/2;
                U_beta = U_m*86603/100000;                
            }
            break;
            case 4:
            {
                U_alpha = -U_m;
                U_beta = 0;
            }
            break;
            case 5:
            {
                U_alpha = -U_m/2;
                U_beta = -U_m*86603/100000;
            }
            break;
            case 6:
            {
                U_alpha = U_m/2;
                U_beta = -U_m*86603/100000;
            }
            break;
            case 7:
            {
                U_alpha = 0;
                U_beta = 0;
            }
            break;
        }
        
    /* Vypocet slozek toku    */    
    psi_alpha = psi_alpha + U_alpha - I_alpha/Gs;
    psi_beta = psi_beta + U_beta - I_beta/Gs;     
    
    /* Vypocet toku    */
    psi_druha = psi_alpha*psi_alpha + psi_beta*psi_beta; //druha mocnina psi
    
    /* Vypocet druhe odmocniny */
    psi_b = 1 << (32-2);
  psi = 0;
  while (psi_b != 0)
    {
    if (psi_druha >= psi + psi_b)
        {
      psi_druha -= psi + psi_b;
      psi += psi_b << 1;
    }
    psi >>= 1;
        psi_b >>= 2;
  }
    
    /* Vypocet momentu */
    moment = (psi_alpha*I_beta/154 - psi_beta*I_alpha/154)*3/2; //130*154=20kHz => mNm
    
    /* Vyber sektoru */
    switch(sektor)
    {
        case 0:
        {
            if(psi_beta*1732 > psi_alpha*1000)
            {
                sektor = 1;
                otacky++;
            }
            if(-psi_beta*1732 > psi_alpha*1000)
            {
                sektor = 5;
                otacky--;
            }
        }
        break;
        case 1:
        {
            if(psi_alpha < 0)
            {
                sektor = 2;
                otacky++;
            }
            if(psi_beta*1732 < psi_alpha*1000)
            {
                sektor = 0;
                otacky--;
            }
        }
        break;
        case 2:
        {
            if(psi_beta*1732 < -psi_alpha*1000)
            {
                sektor = 3;
                otacky++;
            }
            if(psi_alpha > 0)
            {
                sektor = 1;
                otacky--;
            }
        }
        break;
        case 3:
        {
            if(psi_beta*1732 < psi_alpha*1000)
            {
                sektor = 4;
                otacky++;
            }
            if(psi_beta*1732 > -psi_alpha*1000)
            {
                sektor = 2;
                otacky--;
            }
        }
        break;
        case 4:
        {
            if(psi_alpha > 0)
            {
                sektor = 5;
                otacky++;
            }
            if(psi_beta*1732 > psi_alpha*1000)
            {
                sektor = 3;
                otacky--;
            }
        }
        break;
        case 5:
        {
            if(-psi_beta*1732 < psi_alpha*1000)
            {
                sektor = 0;
                otacky++;
            }
            if(psi_alpha < 0)
            {
                sektor = 4;
                otacky--;
            }
        }
        break;
    }
    
    /* Regulator toku */
    psi_delta = psi_zadane - psi;
    if(psi_delta > psi_epsilon)
    {
        psi_hystereze = 1; //tok nahoru
    }
    if(psi_delta < -psi_epsilon)
    {    
        psi_hystereze = 0; //tok dolu
    }
    
    /* Regulator momentu */
    moment_delta = moment_zadany - moment;
    switch(psi_stav)
    {
        case 0:
        {
            if(moment_delta > moment_epsilon)
            {
                psi_stav = 1;
            }
            if(moment_delta < -moment_epsilon)
            {
                psi_stav = 2;
            }
            moment_hystereze = 0;
        }
        break;
        case 1:
        {
            if(moment_delta <= 0)
            {
                psi_stav = 0;
            }
            moment_hystereze = 1; //moment nahoru
        }
        break;
        case 2:
        {
            if(moment_delta >= 0)
            {
                psi_stav = 0;
            }
            moment_hystereze = -1; //moment dolu, nemame kam rekuperovat
        }
        break;
    }
    
    /* Prepinaci tabulka */
    if(psi_hystereze) //tok nahoru
    {
        if(moment_hystereze == 0)
        {
            vektor = 0; //lichy do nul, sudy do jednicek
        }
        if(moment_hystereze == 1)
        {
            vektor = 1 + (6 + sektor + 1)%6; //dopredu ven
        }
        if(moment_hystereze == -1)
        {
            vektor = 1 + (6 + sektor - 1)%6; //zpet ven
        }
    }
    else
    {
        if(moment_hystereze == 0)
        {
            vektor = 0;
        }
        if(moment_hystereze == 1)
        {
            vektor = 1 + (6 + sektor + 2)%6; //dopredu dovnitr
        }
        if(moment_hystereze == -1)
        {
            vektor = 1 + (6 + sektor - 2)%6; //zpet dovnitr
        }
    }
    
    /* Zapis do komparacnich jednotek 3f mustku */
        switch(vektor)
        {
            case 0:
            {
                TIM1->CCR1 = 0;
                TIM1->CCR2 = 0;
                TIM1->CCR3 = 0;
            }
            break;
            case 1:
            {
                TIM1->CCR1 = 4200;
                TIM1->CCR2 = 0;
                TIM1->CCR3 = 0;
            }
            break;
            case 2:
            {
                TIM1->CCR1 = 4200;
                TIM1->CCR2 = 4200;
                TIM1->CCR3 = 0;
            }
            break;
            case 3:
            {
                TIM1->CCR1 = 0;
                TIM1->CCR2 = 4200;
                TIM1->CCR3 = 0;
            }
            break;
            case 4:
            {
                TIM1->CCR1 = 0;
                TIM1->CCR2 = 4200;
                TIM1->CCR3 = 4200;
            }
            break;
            case 5:
            {
                TIM1->CCR1 = 0;
                TIM1->CCR2 = 0;
                TIM1->CCR3 = 4200;
            }
            break;
            case 6:
            {
                TIM1->CCR1 = 4200;
                TIM1->CCR2 = 0;
                TIM1->CCR3 = 4200;
            }
            break;
            case 7:
            {
                TIM1->CCR1 = 4200;
                TIM1->CCR2 = 4200;
                TIM1->CCR3 = 4200;
            }
            break;
        }
    }


neděle 7. února 2016

Měnič 48V / 230V

Jedná se o prototypovou konstrukci měniče z akumulátorů 48V na síťové napětí 230V.
Cílem bylo postavit tichý měnič s pasivním chlazením o výkonu 500W až 1kW.
Základní topologie na následujím schematu:

Vyhlazovací tlumivku v napěťovém meziobvodu jsem zatím vypustil kvůli překmitům na diodách. Výstupní tlumivka je pro jednoduchost konstrukce vinutá na jediném jádru. V tom případě je třeba dát pozor na nutnost invertovaného PWM řízení jednoho z koncových polomůstků při takovéto oriantaci vinutí.
Řízení obou můstků obstarává procesor ARM Cortex M3 - STM32F103C8T6
Jako zpětná vazba je bráno napětí z meziobvodu, což se ukázalo jako nedostatečné vzhledem k úbytkům vznikajícím na výstupním můstku a tlumivce. Bylo by lépe měřit přímo výstupní střídavé napětí.
Dále jsou měřeny proudy obou můstků bočníky v sourcech dolních mosfetů a IGBT.
Napájení driverů a procesoru obstarává pomocný zdroj se starým obvodem 5H0365R, dává 5V a 15V.
Schema řízení:

Pár fotek:
 Desky z DirtyPCB's přišly na Vánoce a vypadají velmi nadějně
 První prototyp osazen
Montáž na provizorní šasi

 Pohled na transformátor a tlumivku. Diody se na desku rozměru 10x10cm také nevešly, takže jsou vpravo nahoře pospojovány dráty.
Ladění
Výstupní sinusovka na zátěži 100W.

Závěr:
Osazená deska úspěšně funguje na první pokus bez úprav až na drobné změny hodnot součástek. Ovšem s laděním SW to bylo úplně naopak. Velmi nemile mě překvapily mosfety IRFP2907. Oproti IRFP4568 se kterými jsem pracoval předtím a šlapaly naprosto parádně i na 40kHz s minimálním deadtimem 30ns prakticky studené a příčný proud v řádu mA. Tak IRFP2907 ačkoli, to z datasheetu při porovnání s předchozími přímo neplyne, tak jsou velmi, velmi pomalé. Nakonec jsem se musel spokojit s frekvencí 32kHz a deadtimem šílených 300ns a přesto tam teče příčný proud a můstek trochu hřeje i při malé zátěži. Do příští verze už mám opět připraveny IRFP4568.
Obdobný problém byl s výstupními IGBT. Na použitou tlumivku se už prostě nevešlo víc závitů, indukčnost kvůli pevné mezeře nebylo možno ani experimentálně zvětšit, a tak jsem musel zvýšit frekvenci až na 80kHz. IGBT potřebují cca 300ns deadtime, aby byly ztráty naprázdno při tomto napětí rozumné, což je ovšem už 10% periody. Příliš mnoho. Díky tomu jsem musel zvednout napětí meziobvodu na 350V abych dostal aspoň 220V střídavých v zátěži na výstupu. Frekvence je ale příliš vysoká a výstupní můstek docela topí. Celkové ztráty měniče naprázdno jsou 15W. Ale už mám také připraveny lepší polovodiče a navinu větší tlumivku.

MPPT pro 48V 500W systém

V rámci školní zakázky se mi podařilo nechat vyrobit desku pro navržený MPPT pro 48V 500W systém.
Jedná se o synchronní buck - boost topologii s jednou tlumivkou. Měnič tedy umožňuje jak snižování, tak zvyšování napětí z panelů.
Řízení obstarává procesor ARM Cortex M3 - STM32F103C8T6
Byl navržen pro nabíjení akumulátorů, základními vstupy jsou napětí akumulátorů a jejich nabíjecí proud. Obsahuje dva regulátory, regulátor žádaného napětí na panelech a jemu nadřazený regulátor napětí akumulátorů. Pokud napětí akumulátorů dosáhne žádané hodnoty 55,7V, regulátor zvyšuje žádané napětí panelů, které tak díky VA charakteristice dávají menší proud. Regulátor tak udržuje dané napětí akumulátorů.
Pokud akumulátory nejsou nabité, regulátor dosazuje jako žádanou hodnotu napětí na panelech napětí vycházející z MPPT algoritmu.
MPPT algoritmus je klasický typ, který hledá bod maximálního výkonu, zde prostě maximální nabíjecí proud tak, že zkouší zvyšovat nebo snižovat žádané napětí panelů a podle změny nabíjecího proudu pokračuje ve snižování resp. zvyšování, nebo obrátí směr, pokud je naměřený proud již menší, než předchozí.
Klíčová je zde především frekvence výpočtu. Při snižování napětí se vybíjí vstupní kapacity měniče a ten tak vždy naměří větší proud, při zvyšování naopak. Je tedy třeba výpočet zpomalit, aby měřil skutečnou změnu danou VA char. panelů. Naopak příliš pomalý výpočet není schopen reagovat na reálné změny jasno/mrak a ustalování by trvalo například až několik minut.
Zvolil jsem synchronní topologii kvůli minimalizaci ztrát. Ovšem její nevýhodou se ukázala absence výstupní diody, která by přirozeně zabránila toku energie z akumulátorů do panelů. Správná funkce je tak závislá právě na SW. Měnič je symetrický z obou stran posazený mezi dva relativně výkonné zdroje resp. spotřebiče a při nevhodném řízení je schopen např. posílat energii z akumulátorů do panelů místo opačně a nebo zkratovat natvrdo jeden nebo druhý vstup.
Zapojení obsahuje jedinou HW ochranu a to proti přebíjení. Při vzrůstu napětí akumulátorů přes 59V se klopným obvodem vypnou oba drivery a měnič bez zásahu procesoru vypne všechny výkonové tranzistory v můstku. Opětovný start je možný jedině restartem napájení z panelů. Buď vypínačem ručmo, nebo automaticky "druhý den ráno".
Napájení driverů a procesoru je řešeno pomocným spínaným zdrojem se starým obvodem 5H0365R, jehož předností je velká úspora součástek, velký vstupní rozsah napětí a velmi malá klidová spotřeba. Přestože se jedná o síťový zdroj, bezproblému pracuje od 15V. Pomocný zdroj dává 5V a 15V.

Schema:

Pár fotek:
 Osazená deska

 Zimní den. Při malém proudu přepne a drží nulový rozdíl napětí, protože algoritmus by již kvůli nedostatečnému rozlišení při malých proudech nemohl fungovat. Při nulovém rozdílu jsou navíc nejmenší ztráty.

 Start s částečně zasněženými panely, které dávaly jen poloviční napětí přes bypass diody, algoritmus naskočil úspěšně za 15 vteřin.

 Pokud hodinu měří nulový proud, vypne můstek a tím i napájení procesoru. Nastartuje znovu další den ráno. (A nebo bohužel hned za pár vteřin pokud ještě není dostatečná tma)

Závěr:
Uvedl jsem zde jedno z mnoha možných řešení MPPT nabíjecího měniče. Článek slouží spíš pro inspiraci nemá být návodem. Můstek je možno řídit mnoha typy procesorů, stejnětak jako SW v něm je čistě na fantazii každého.

Příloha:
/* MPPT algoritmus */
        if(mppt)
//flag
        {
            if(I_aku_avg < I_aku_predchozi)
            {
                add = ~add + 1;
            }
            I_aku_predchozi = I_aku_avg;
            panely_mppt = panely_mppt + add*200;
//0,4V za vterinu
            if(panely_mppt < 32000)
            {
                panely_mppt = 32000;
//dolni limit 32V
                add = ~add + 1;
            }
            if(panely_mppt > 65000)
            {
                panely_mppt = 65000;
//horni limit 65V
                add = ~add + 1;
            }
            mppt = 0;
        }

/* Regulator napeti na akumulatorech */
            Err_aku = U_aku - 55650;
//Max napeti akumulatoru pri nabijeni
            Out_aku = Sum_aku + Err_aku/10;
      
          
 /* Omezovac zadaneho napeti na panelech */
            if(Out_aku > 80000)
            {
                panely_ref = 80000;
            }
            else
            {
                if(Out_aku < panely_min)
                {
                    panely_ref = panely_min;
                }
                else
                {
                    panely_ref = Out_aku;
                }
            }
            Exc_aku = panely_ref - Out_aku;
            Sum_aku = Sum_aku + Err_aku/20 + Exc_aku/20;
      
          
 /* Regulator napeti na panelech */
            Err = U_panely - panely_ref;
            Out = Sum + Err/5;
      
            /* Omezovac stridy */
            if(Out > 30000)
//abychom netopili zelezoprachem tlumivky
            {
                strida = 30000;
//boost
            }
            else
            {
                if(Out < -30000)
                {
                    strida = -30000;
//buck
                }
                else
                {
                    strida = Out;
                }
            }
            Exc = strida - Out;
            Sum = Sum + Err/10 + Exc/10;
          
            
/* Vlozeni stridy do komparacnich jednotek */
            if(strida >= 0)
            {
                TIM1->CCR1 = 775 - strida/100;
//boost menic
                TIM1->CCR2 = 775;
//97,4%
            }
            else
            {
                TIM1->CCR1 = 775;
                TIM1->CCR2 = 775 - ~(strida/100) + 1;
//buck menic
            }