evo izmenjene i kompletirane mašine.
šema i kod u prilogu ispod.
počinjem sutra svračije gnezdo kako bih potvrdio da stvar radi.
T1 je velika trafojčina od minimalno :) 20kg i motan je sa primarom 9V ko prst debele žice, a sekundarom 220V hmm :) onako žice...
T2 je mali trafo 220V na 12V ... hmm ne ispod 50mA struje na 12V.
C6 je blok kond od najmanje 400V/3uF.
L1 je prigušnica primara motana na velikom torusu feritnom sa podebelom žicom , hmmm empirijski utvrditi. zadatak joj je skinuti visokofrekventni spwm koji primar velikog trafoa ne bi trebao da vidi. invertor može da radi bez nje ali će imati relativno veliku struju lera...
F1 i F2 su skalabilni i nazivna struja zavisi od veličine i snage invertora.
D12 staviti po želji kako bi zahtevana granična struja bila ona koju želite. hall senzor ima rezoluciju 0.1V/A.
P5 konektor prihvata sekundar malog trafoa 220V/12V, opet ne slabijeg sekundara od 50ak mA na 12V i preko njega se derivuje podatak za sync invertora sa mrežom.
P6 ide direktno na utičnicu. VODI RAČUNA O TOME ŠTA JE NULA A ŠTA FAZA U POVEZIVANJU I OBAVEZNO staviti u red žarulju/sijalicu 220V za test. ako svitka ne valja :)
prethodni invertor sam napravio sa egs002 pločicom i proučavao kako radi. u prethodnim postovima ima šta mi je se svidelo a šta ne. ono što sam uvideo da je kinez pametno rešio - to sam preneo na ovu svoju verziju sklopa invertora . toliko o egs002 pločici.
sada priča o shemi ispod:
čitav invertor je lako skalabilan u razne napone baterijskog napajanja i verujem da na 24V/36V/48V verziji mogu lako biti izvodljive snage do 5kW.
ova koja je na shemi i koju ću praviti je na 12V. čisto radi proof of concept situacije...
po teoriji - trebao vi raditi ok. spwm je generisan na D9 i D10 arduino pro min 328p. pro mini u letu generiše dosta preciznu lookup tabelu.
signal ide preko HIP4082 na donje fetove mosta. dosta toga je napravljeno da bude kompatibilno sa egs002 pločicom.
f-ja spwm, rasponi napona feedbacka, itd.....
dodao sam sinhronizaciju sa mrežom. i to sam testirao u low power okruženju i trebalo bi da radi. ne znam kako se ponaša u noisy okruženjima.
sve u svemu , u svakom pokušaju stvar je se sinhronizovala za najviše pola sekunde.
digitalni Bessel low pass filter je u kodu, i koristi se čisto naučni pristup zbog važne karakteristike ovakvog filtriranja za našu upotrebu u feedbacku invertora - a to je malo ili gotovo nikakvo fazno kašnjenje talasnog oblika tokom filtriranja.
kod je pola moj , pola pozajmljen sa raznih strana...
što kaže onaj brkica : šta reći ? koju posluku porati ?
comments ?
Code:
#define ADC_OUT 0 // ulaz feedbacka visokog AC napona
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define NPWM 200
//#define PPWM 665 // 60.062 Hz - izaberi ovaj, ili ovaj ispod. nikako oba.
#define PPWM 799 // 50.002 Hz 799 49.939 Hz za 800
uint8_t uf,oen,v1low, lv_stopped,int_f;
uint16_t pcount;
uint32_t vpwr;
int sst;
uint16_t l[NPWM+1];
float pwr;
uint8_t dbounce;
double Input, Output, Setpoint;
double errSum, lastErr,error,dErr;
double kp, ki, kd;
float xv[5],yv[5];
float ac_output, ac_setpoint;
void init_vars(void);
long pcount_acc;
int pcount_delta, phase_error, old_phase_error;
int pcint,new_delta;
uint8_t init_done;
void setup()
{
int i;
float t,u;
for(t=0.0,i=0; i <= NPWM; i++,t += 3.14159/ (float) (NPWM+1))
{
u = 65535.0 * sin(t); // 1/2 sinusne lookup table, skalirana na (16 bits - 1)
l[i] = (int)u;
}
pinMode(9, OUTPUT); // V1 Spwm
pinMode(10, OUTPUT); // V2 Spwm
pinMode(8,INPUT); // uklj/isklj pin
// u daljem kodu ne smem dozvoliti da arduino poziva pinMode() f-ju.. utvrdio sam da zeza d5 koji mora biti niske impedanse po butovanju...
DDRD = 0xfb; // postavi D2 kao ulaz INT0
pinMode(2,INPUT_PULLUP);
noInterrupts();
TCCR1A = _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(WGM11);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
OCR1A = 10;
ICR1 = PPWM;
TIMSK1 |= (1 << TOIE1);
EICRA = 3; // interrupt na silaznoj ivici signala D2
EIMSK |= bit (INT0); // uključi ga
cbi(PORTD,4); // nema sinh.
cbi(PORTD,5); // isključi izlaze spwm.
oen = 0; // uklj/isklj invertora. = 1 za uklj, = 0 za isklj
init_vars();
init_done = 1;
interrupts(); // omomgući interapte
TIMSK0 = 0; // osim arduino clock-a
sbi(ADCSRA,ADPS2) ; // ADC clock priskejler = 16 sad. štedimo 100us u glavnom loop-u uz sitna odricanja
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
Serial.begin(115200);
}
//
// kod za sync.
// ovo se mora brzo izvršavati
// trebalo bi za manje od 6uS
// kreće na početku poluperiode, gde će PWM duty% uvek biti mali
// otprilike na prolasku kroz nulu. 6uS turbulencije će biti vrlo male, možda neprimetne.
//
ISR (INT0_vect)
{
if (int_f == 0)
{
sbi(PORTD,7);
cbi(PORTD,7);
return; //
}
int_f = 0;
//sbi(PORTD,7);
//cbi(PORTD,7);
pcint = pcount + (v1low == 1?200:0) - 200; // nađi poziciju unutar periode, -200 to 200
phase_error = (pcint - 0);
new_delta = (phase_error/4 + (phase_error - old_phase_error));
if (new_delta > 10)
{
new_delta = 10;
}
if (new_delta < -10)
{
new_delta = -10; // trebalo bi da se usyncuje unutar pola sekunde
}
pcount_delta = pcount_delta - new_delta; // primeni ono što si pronašao na generisani spwm
if(pcount_delta < 200) pcount_delta = 200;
if(pcount_delta > 300) pcount_delta = 300;
old_phase_error = phase_error;
if (phase_error < 3)
sbi(PORTD,4); // upali led ako već misliš da si u sync.
}
//
// 20khz pwm. ovaj kod se mora izvršiti unutar 50 mikrosec. mislim da se izvršava unutar 10mikrosec.
//
ISR(TIMER1_OVF_vect)
{
long c;
c = (l[pcount] * vpwr) >> 16; // reskaliraj vrednosti sinusoide
if (v1low == 1) // svičuj između dva komparatora. generiši obe poluperiode.
OCR1B = c; // 1/2 ovde
else
OCR1A = c; // i još 1/2 ovde.
pcount_acc += pcount_delta; // broji kroz 1/2 snusoide, 200 unosa. Na 20KHz, = 50Hz izlaz
pcount = (pcount_acc >> 8); // dodaj mogućnost variranja +-8Hz.
if(pcount >= NPWM)
{
pcount = 0; // resetuj brojac
pcount_acc = 0;
uf=1;
if (v1low == 1) // ako 1/2 ..
{
v1low = 0; // onda druga polovina half wave-a
TCCR1A = _BV(COM1A1) | _BV(WGM11);
//sbi(PORTD,7); // sync za osciloskop ko voli :)
//cbi(PORTD,7);
if (int_f == 1) // nema ulaznog sync napona ?
{
cbi(PORTD,4); // reci ljudima nema sync-a
pcount_delta = 256; // ako nema synca ili nikad nije ni uspostavljen - vidi jel sve u redu sa f-jom izlaza.
}
int_f = 1; // par stvari da osigura da ovaj kod prvi ide
} // i da ga ne ometaju bilo kakvi interapti
else
{
v1low = 1; // prebaci na prvi half wave
TCCR1A = _BV(COM1B1) | _BV(WGM11); // konf O.C. da paše....
}
}
}
void init_vars()
{
ICR1 = PPWM;
lv_stopped = 0;
sst = 0; // soft start 0 - 251
v1low = 1; // fleg koji pokazuje đe smo, u prvoj ili drugoj poluperiodi, 0 or 1
pcount = 0; // brojač lookup tabele
uf = 0; // nešto oko feedbacka
pwr = 0.0; // PWM duty , 0.0 do 1.0
vpwr= 0; // integer ekvivalent snage, 0 do PPWM
dbounce = 0; //
kp = 0.1; // setup PID za AC izlaz
ki = 0.0;
kd = 0.01;
errSum = 0.0;
lastErr = 0.0;
int_f = 0;
pcount_acc = 0;
pcount_delta = 256;
old_phase_error = 0;
cbi(PORTD,4);
}
void do_pid()
{
double timeChange = 0.01;
error = Setpoint - Input;
errSum += (error * timeChange);
dErr = (error - lastErr) / timeChange;
Output = kp * error + ki * errSum + kd * dErr;
lastErr = error;
}
void loop()
{
float ch0;
ch0 = (float)analogRead(ADC_OUT) / 1024.0; // reskaliraj 0-5V na 0.0-1.0V
// filtriraj AC izlaz , Fc = 10, 4 pole Bessel LP
// pokupio od https://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4];
xv[4] = ch0 / 2.259747797e+05;
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4];
yv[4] = (xv[0] + xv[4]) + 4 * (xv[1] + xv[3]) + 6 * xv[2]
+ ( -0.7428578687 * yv[0]) + ( 3.1954036268 * yv[1])
+ ( -5.1599230905 * yv[2]) + ( 3.7073065280 * yv[3]);
ac_output = yv[4];
if(uf == 1 ) // ovo se izvršava na 100Hz
{ // radi kad prolazi sinusoida kroz nulu
uf=0;
ac_setpoint = 0.56; // pravimo da bude kompatibilno Vfb kao na EG8010.
if (oen == 1) sst++; // slow start.
if (sst > 251)sst = 251;
if (oen == 0) sst--; // ako se gasi invertor, isto sporo gasi
if (sst <= 0)
{
sst = 0;
cbi(PORTD,5); // pull down IR2184 shutdown LOW da bi IC shvatio da nećemo sad spwm
}
else
sbi(PORTD,5); // pull HIGH, kao gore samo obrnuto
if(sst > 0 && sst < 250)
{
if (oen == 1)
{
if(ac_output < ac_setpoint)
pwr += 1.0/250.0;
else
pwr -= 1.0/250.0;
}
else
pwr -= 1.0 /250.0;
}
if (sst == 251)
{
Setpoint = ac_setpoint;
Input = ac_output;
do_pid();
pwr = pwr + Output;
}
if (pwr > 0.99) pwr = 0.99;
if (pwr < 0.01) pwr = 0.01;
vpwr = (int)((float)PPWM * pwr);
check_switch_cont();
Serial.print((pcount_delta-256)*10);
Serial.print(" -150 150 ");
Serial.println(pcint*10);
}
}
void check_switch_cont()
{
if ((PINB & 0x01) == 0x01)
{
if (init_done == 0)
{
init_vars();
init_done = 1;
}
oen = 1; // startuj polako
}
if (((PINB & 0x01) == 0) || ((PIND & 0x40) == 0x40))
{
init_done = 0;
oen = 0; // stopiraj polako
}
}
[Ovu poruku je menjao cukovanny dana 23.06.2019. u 19:13 GMT+1]
[Ovu poruku je menjao cukovanny dana 23.06.2019. u 19:32 GMT+1]