sunnuntai 16. syyskuuta 2018

AURINKOPANEELIN TESTAUS

Olen useiden vuosien ajan käyttänyt kesämökillä aurinkosähköä. Paneelit aurinkoiseen paikkaan, kaupasta lataussäädin ja akut varastoksi. Niin yksinkertaista se on. Periaatteessa kyllä ja noillakin pärjää pitkälle, mutta aurinkopaneelin toimintaan liittyy kyllä monta muutakin tekijää. Tämän kertaisen blogini tarkoituksena valottaa aurinkopaneelin toimintaa mittaamalla sitä.

Mittausjärjestely. Vasemmalla vakiovirtakuorma.
Paneelin tuottoa eri kulmista.
Olin jokin vuosi sitten ostanut pienen 50 W paneelin testejä varten. Tuolloin testasin lähinnä paneelin tuottoa auringon ollessa eri suunnissa. Toisin sanoen kääntelin paneelia eri kulmissa ja mittasin tuoton.
Yleensä suositellaan paneeli suuntaamaan etelään. Silloin aurinko on korkeimmillaan. En tiedä, mistä tuo suositus tulee, sillä tuoton suuruuteen on monia tekijöitä. Ehkä se on helppo ja selkeä ratkaisu?





Maapallo kääntyy tunnissa 15 astetta. Kun siirrytään kolme (3) tuntia eli 45 astetta siitä, milloin aurinko paistaa paneeliin suoraan, putoaa tuotto noin puoleen. Myös sillä on vaikutusta, onko paneeli pysty- vai vaakasuorassa. Valo on siis jossain määrin polarisoitunutta. Tämän tekijän vaikutus on kuitenkin marginaalisen pieni. Paljon suurempi vaikutus on maapallon kaltevuudella. Juhannuksen tienoilla aurinko paistaa eteläsuomen leveyspiirillä noin 53 asteen korkeudella ja jouluna noin 9 asteen korkeudella. Toinen suositus on asentaa paneeli noin 45 asteen kulmaan. En tiedä tuotakaan, mistä se tulee, mutta pystykulmaa kannatta miettiä sen mukaan, mihin aikaan vuodesta on sen pääasiallinen käyttöaika. Joka tapauksessa vuorokausi rytmillä on paljon suurempi merkitys kuin vuosirytmillä.



Tuosta syystä olen kokeillut erilaisia tapoja kääntää paneeleita päivän edetessä. Jos paneeli seuraa aurinkoa 90 – 120 asteen verran (6 – 8 tuntia), on paneelin tuotto noin kaksinkertainen. Pilvisellä säällä vielä suurempi. Pilvien kulkua on tietysti mahdoton määritellä tai laskea etukäteen, sillä ei voi ennustaa, mihin aikaan päivästä aurinko joutuu pilven taakse, jolloin tuotto tippuu helposti jopa 90 %. Kääntyvä paneeli on silloin kohtisuoraan aurinkoon, kun se suostuu pilkistämään pilven raosta.

Mittaustaulukko. 
Aurinkopaneeli on vähän kuin paristo, minkä jännite on lähes vakio riippumatta valon voimakkuudesta (säteilyn tehosta). Riippuu tietysti paneelista, mutta on tyypillisesti välillä 19 – 23 V. Pimeällä jännite luonnollisesti laskee nollaan. Valo ei suoranaisesti muuta tämän ”pariston” sisäistä vastusta, vaan muuttaa ikään kuin ”vakiovirtalähteen” kuormituskykyä. Kuva simuloi aika hyvin paneelin käyttäytymistä valoisuuden vaihdellessa. Kuvassa PNP-transistorin kannalla on vakiojännitelähde ja transistorin emitterillä valovastus, jonka suuruutta auringosta tuleva fotonivirta muuttaa. Lähdössä oleva kuormituksen vaihtelu ei juurikaan muuta saatavaa virtaa, vaan lähtöjännite muuttuu radikaalisti. Kun on hämärää, aurinko paistaa vinosti tai on pilven takana, saadaan vähän virtaa. Kun paistaa voimakkaasti, saadaan kuormaan paneelin tehosta riippuva maksimivirta. Kuvassa on esitetty taulukko todellisesta mittauksesta. Siinä on aikaskaala tunnin välein, mutta pilven hattaratkin toki vaikuttivat. Kuvassa kolme olen yrittänyt havainnollistaa paneelin käyttäytymistä graafisesti.

Vakiovirtalähdemalli.
Kuvassa on kuormituslaitteen kytkentä. Siinä on kahdella transistorilla (tehotransistori MJE3055 ja ohjaustransistori 2N2904) tehty vakiovirtakuorma. Arduino ohjaa vakiojännitteen ohjaustransistorin kannalle, mikä puolestaan syöttää tehotransistoria. Sen emitterillä on 1 ohmin vastus, mistä Arduino mittaa virran (1 ohmi * jännite = virta). Koska Arduino ei syötä tasajännitettä, vaan analogialähtö on pulssinleveysmoduloitu (PWM), pitää ohjausjännite suodattaa. Jännitemittausta varten on jännitejako kahdella vastuksella. Tuo paneelin noin 20 voltin jännite pitää skaalata Arduinon tuloalueelle 0 – 5 V.

Painikkeita on kolme. Ohjausjännite kasvaa, ohjausjännite pienenee ja arvojen tulostus näytölle. Tulostuksen aikana ohjausjännite nollataan. Tämä johtuu siitä, että tehotransistorin jäähdytyslevy on niin pieni, että pidempiaikaisessa kuormituksessa se olisi kuumentunut liikaa. Testien jälkeen on muutenkin selvää, että tuon ohjausohjelman olisi voinut tehdä fiksumminkin, esim. automaattiseksi, mutta se uhraus on turhaa, koska tälläkin ilmenee kaikki oleellinen paneelin ominaisuuksista. Myöskään tämä tekemäni testilaite ei pysty kuormittamaan tätä 50 W paneelia sen maksimivirtaan saakka.


Painikkeita on kolme. Ohjausjännite kasvaa, ohjausjännite pienenee ja arvojen tulostus näytölle. Tulostuksen aikana ohjausjännite nollataan. Tämä johtuu siitä, että tehotransistorin jäähdytyslevy on niin pieni, että pidempiaikaisessa kuormituksessa se olisi kuumentunut liikaa. Testien jälkeen on muutenkin selvää, että tuon ohjausohjelman olisi voinut tehdä fiksumminkin, esim. automaattiseksi, mutta se uhraus on turhaa, koska tälläkin ilmenee kaikki oleellinen paneelin ominaisuuksista. Myöskään tämä tekemäni testilaite ei pysty kuormittamaan tätä 50 W paneelia sen maksimivirtaan saakka.

Jos paneeli kytketään suoraan akkuun (12 V), ei siihen saada ladattua suurinta mahdollista tehoa. Akku latautuu paneelin antamalla virralla, eli virta kertaa akun sen hetkinen jännite. Loppu paneelin tehosta kuluu paneelin lämmittämiseen, mikä ei ole hyvä juttu. Kuten tuosta taulukosta ilmenee, saadaan maksimiteho paneelista noin 17 – 18 voltin jännitteellä. Jotta tähän päästäisiin, on siinä hyvä pohtimisen aihe ensi kerraksi.

Ohjelma 54
/***************************************
* AuPanTest
* 13.09.2018
* Kuormitetaan pientä aurinkopaneelia ja
* kerätään ominaisuudesta dataa
**************************************/

// MÄÄRITTELYT:
// Muutamia perusmäärityksiä
const int Con_Miinus = 2;
boolean Bol_Miinus = true;
int Seq_Miinus = 1;

const int Con_Tulostus = 3;
boolean Bol_Tulostus = true;
int Seq_Tulostus = 1;
const int Con_LED_2 = 6;
const int Con_Plus = 4;
boolean Bol_Plus = true;
int Seq_Plus = 1;
const int Ain_Voltit = 0;
int Int_Jannite = 0;
float Flo_Jannite = 0;
float Flo_U_Kerroin = 0.0249;
const int Ain_Virta = 1;
int Int_Virta = 0;
float Flo_Virta = 0;
float Flo_I_Jako = 200;
float Flo_Teho = 0;

const int Con_Ohjaus = 5;
const int Con_AnaPohja = 50;
int Int_AnaOut = Con_AnaPohja;
int Int_AnaArvo = 0;
const int Con_AnaMuutos = 10;

// ALIOHJELMAT
void Fun_Tulostus(){
Serial.print("Jännite :"); Serial.print(Flo_Jannite);
Serial.print(" Virta :"); Serial.print(Flo_Virta);
Serial.print(" Teho :"); Serial.println(Flo_Teho);
}

// ASETUKSET:
void setup(){
Serial.begin(9600);
pinMode(Con_Miinus, INPUT_PULLUP);
pinMode(Con_Tulostus, INPUT_PULLUP);
pinMode(Con_Plus, INPUT_PULLUP);
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
Bol_Miinus = !digitalRead(Con_Miinus);
Bol_Tulostus = !digitalRead(Con_Tulostus);
Bol_Plus = !digitalRead(Con_Plus);
Int_Jannite = analogRead(Ain_Voltit);
Flo_Jannite = Int_Jannite * Flo_U_Kerroin;
Int_Virta = analogRead(Ain_Virta);
Flo_Virta = Int_Virta / Flo_I_Jako;
Flo_Teho = Flo_Jannite * Flo_Virta;

switch (Seq_Miinus) {
   case 1:
     if(Bol_Miinus == true){
       delay(5);
       Int_AnaArvo = Int_AnaArvo - Con_AnaMuutos;
       if(Int_AnaArvo < 0){
         Int_AnaArvo = 0;}
         Int_AnaOut = Con_AnaPohja + Int_AnaArvo;
         delay(300);
         Fun_Tulostus();
     Seq_Miinus = 2;}
   break;
   case 2:
     if(Bol_Miinus == false){
       Seq_Miinus = 1;
   }
   break;
   }// Miinus-sekvenssin loppu

switch (Seq_Tulostus) {
   case 1:
     if(Bol_Tulostus == true){
       delay(5);
       Int_AnaOut = Con_AnaPohja;
       Fun_Tulostus();
       Seq_Tulostus = 2;
     }
   break;
   case 2:
      if(Bol_Tulostus == false){
        Seq_Tulostus = 1;
      }
   break;
   }// Tulostus-sekvenssin loppu

switch (Seq_Plus) {
   case 1:
     if(Bol_Plus == true){
       delay(5);
       Int_AnaArvo = Int_AnaArvo + Con_AnaMuutos;
       if(Int_AnaArvo > 204){
         Int_AnaArvo = 204;}
         Int_AnaOut = Con_AnaPohja + Int_AnaArvo;
         delay(300);
        Fun_Tulostus();
     Seq_Plus = 2;}
   break;
   case 2:
     if(Bol_Plus == false){
     Seq_Plus = 1;
   }
   break;
}// Plus-sekvenssin loppu

analogWrite(Con_Ohjaus, Int_AnaOut);
delay(1);
} // Pääohjelma LOPPU

torstai 10. toukokuuta 2018

VILKKU

On toki oikeutettua kysyä, onko tämän pitkän tauon aikana kaikki unohtunut, kun pitää jälleen siirtyä alkeisiin, eli vilkuttamaan LEDiä? Päivät ovat täyttyneet kaikenlaisesta muusta menneen talven aikana.

Nyt kuitenkin tuli jo kiire kehitellä ensi kesäksi uutta aurinkopaneelin kääntäjäprotoa (jokainen edellistä yksinkertaisempi), ja siinä yhteydessä syntyi ajatus: voisiko noiden parin LEDin avulla saada yksinkertaisella ohjelman pätkällä aikaan enemmän informaatiota toiminnan tilasta kuin pelkästään toimii / seis?
    Kun aurinko siirtyy kolme (3) tuntia paneelin suunnasta sivuun, putoaa paneelin tuotto noin puoleen. Toisin sanoen, jos paneeli seuraa aurinkoa klo 9 .. 15, (6h eli 90 astetta), tuottaa paneeli klo 6 – 9 keskim. 75% ja siitä eteenpäin 9 – 15 yli 90% (jos korjataan esim. kerran tunnissa). Sitten taas klo 15 – 18 keskim. 75%. Aurinkoa seuraamalla korvataan käytännössä yhden paneelin tuotto. Pilvet tietysti sotkevat tämän optimismin!
    Minulle on myös sanottu (ja epäilty), että paneelin tuotto kuluu nimenomaan tähän kääntämiseen. Minulla on ollut jo useamman kerran käytössä veneen lasinpyyhkijän moottorit (hiukan modifioituina). Ne toimivat 12 V:n jännitteellä ja niissä on sopiva vaihteisto.
    Tämä on pelkkää laskentoa: jos käännetään kuusi (6) kertaa ja yksi tunnin kääntö kestää yhden (1) minuutin, kuluttaa kääntö 6 Amin aamusta iltaan plus paluu toiset kuusi Ah. Mikrokontrolleri on kuitenkin päällä ja kulutta sähköä koko ajan, joten jos se kuluttaa 5 mA (<Leonardo, UNO noin 150mA, tietysti riippuu ja roikkuu!), kuluu siihen 1440min * 0,005A = 7,2 Amin. Yhteensä siis 13,2 Amin. Jos varaudutaan vaikkapa tuplaan, noin 30 Amin, eli 0,03 Ah:iin, niin 85W panelilta (tuotto noin 4A) kuluu tuotosta kääntäjän pyörittämiseen auringon heloituksessa noin 8 min.
Päässä pyörii jo ensi talven proto. Siinä ei lasin pyyhkijään tarvitse tehdä muutoksia, ja sen tulisi kääntää useampia rinnan olevia paneeleja yhdessä. Saa nähdä toteutuuko??

Päädyin miettimisen jälkeen aliohjelmaan, minkä avulla yksi kaksivärinen LEDi tarjoaa kuusi (6) eri tilatietoa (sen lisäksi, että kumpikaan LEDi ei valaise). Ajattelin laittaa sen tänne blogiin ajatuksella, että sillä saattaisi olla käyttöä muillekin. Minulle ainakin myös jatkossa myös muissa sovelluksissa.
    Tässä ohjelmaesimerkissä on kuusi (6) painiketta. Käytännössä informaatio tulee tietysti prosessin tilatietoina. Aliohjelmassa ( void Fun_LEDit(int led, int toiminto){) on kolme toiminnallista askelta ja oletusaskeleena (default:) LEDien sammutus ja aikalaskurin palautus, jotta uusi ohjaus alkaisi aina LEDin syttymisellä
    Askeleet ovat: 1. LED palaa niin kauan kun tuloinformaatio on TOSI. 2. LEDin lyhyt välähdys ja loppu kokonaisajasta sammuneena ja 3. Kokonaisaika puolitetaan, jolloin LED on puolet ajasta valo päällä ja puolet ajasta pimeänä.
    Tämä valittavana kutsussa (esim. {Fun_LEDit(Con_LEDvih, 1), jolloin vihreä valo palaa niin kauan kuin tulo on aktiivinen. Eli pääohjelman kutsussa määritellään kahdella parametrilla, kumpi LEDi aktivoituu ja millä tavalla.
    Jos mikään ohjaus ei ole aktiivinen, kutsutaan oletusaskelta (}else{Fun_LEDit(0, 0);}), missä molemmat LEDit ohjataan nollaan ja aika palautetaan alkuun, jotta seuraava ohjaus alkaa LEDin syttymisellä.

Koska tulot (tässä tapauksessa) on määritelty sisäisesti ylös (pinMode(Con_Pain1, INPUT_PULLUP );), muuttuu prosessorin tulo alas ( 1 → 0 ), käännetään tulon tilaa luettaessa huutomerkillä (!) (Bol_Pain1 = !digitalRead(Con_Pain1);). Tämä on kyllä vain ihmisen aivoja varten.

Tässäkin aliohjelmassa on tietysti rajoituksensa. Tämä edellyttää, että sille syötetään ainoastaan yksi tieto kerrallaan. Jos halutaan vilkuttaa useampaa lamppua samaan aikaan ja eri tahtiin, pitää aliohjelmalle välittää myös yksilöllinen aikainformaatio. Samoin pitää myös valojen sammutus valvoa yksilöllisesti. Tässä sen toteuttaa oletusaskel (default:), mikä edellyttää, että aliohjelmaa ei kutsuta lainkaan.
    Jos nuo ajat (919 ja 43) ihmetyttävät, niin niiden lukuarvoilla ei sinänsä ole merkitystä. Noilla ajoilla (monien muiden lähellä olevien lisäksi) vilkutus tuntui sopivalta. Mutta miksi juuri noin oudot luvut? Molemmat ovat alkulukuja ja niiden valinnan taustalla on viimeaikainen toisen ohjelmointikielen (python) harjoitteleminen. Sen harjoituksissa on ollut hauskoja ”numeromurskausjuttuja”, mm. alkulukujen (jaollinen vain yhdellä(1) ja itsellään) laskeminen. Toinen kiva harjoitus purki tietoa, että kaikki luonnolliset luvut ovat alkulukujen tuloja. Esim. kertolasku 2*3*3*5*3607*3803 antaa tulokseksi luvun : 1234567890. Numerot ovat hauskoja!
 
OHJELMA 53
 
/***************************************
* Vilkku_v1
* 10.05.2018
* Laajempaa LEDi-informaatiota
**************************************/

// MÄÄRITTELYT:
// Ledit
const int Con_LEDpun = 2; // Ohjaukset seis
const int  Con_LEDvih = 3; // Automaatilla

// Tulot
const int  Con_Pain1 = 4;
boolean Bol_Pain1 = false;
const int  Con_Pain2 = 5;
boolean Bol_Pain2 = false;
const int  Con_Pain3 = 6;
boolean Bol_Pain3 = false;
const int  Con_Pain4 = 7;
boolean Bol_Pain4 = false;
const int  Con_Pain5 = 8;
boolean Bol_Pain5 = false;
const int  Con_Pain6 = 9;
boolean Bol_Pain6 = false;

// Muutamia perusmäärityksiä
const int Con_Kierros = 919; // Kokonaiskesto
const int Con_Ero = 43; // Pilkahdusaika
int Int_Kierros = Con_Kierros;// Keston välimuisti

// ALIOHJELMAT
// LEDien ohjaus
void Fun_LEDit(int led, int toiminto){
   switch (toiminto) {
     case 1: // Jatkuva
     digitalWrite(led, HIGH);
   break;
   case 2: // Pilkahdus
     if (Int_Kierros > (Con_Kierros - Con_Ero))
       {digitalWrite(led, HIGH);
    }else{digitalWrite(led, LOW);}
       Int_Kierros = Int_Kierros - 1;
     if (Int_Kierros == 0){Int_Kierros = Con_Kierros;}
   break;
   case 3: // Vilkku
     if (Int_Kierros > (Con_Kierros / 2))
       {digitalWrite(led, HIGH);
     }else{digitalWrite(led, LOW);}
       Int_Kierros = Int_Kierros - 1;
    if (Int_Kierros == 0){Int_Kierros = Con_Kierros;}
   break;
   default: // LEDien sammutus ja ajan palautus
     digitalWrite(Con_LEDvih, LOW);
     digitalWrite(Con_LEDpun, LOW);
     Int_Kierros = Con_Kierros;
   }// sekvenssi loppu
}// LEDien funktion loppu

// ASETUKSET:
void setup(){
Serial.begin(9600);
pinMode(Con_LEDpun, OUTPUT);
pinMode(Con_LEDvih, OUTPUT);
pinMode(Con_Pain1, INPUT_PULLUP );
pinMode(Con_Pain2, INPUT_PULLUP);
pinMode(Con_Pain3, INPUT_PULLUP);
pinMode(Con_Pain4, INPUT_PULLUP);
pinMode(Con_Pain5, INPUT_PULLUP);
pinMode(Con_Pain6, INPUT_PULLUP);
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
Bol_Pain1 = !digitalRead(Con_Pain1);
Bol_Pain2 = !digitalRead(Con_Pain2);
Bol_Pain3 = !digitalRead(Con_Pain3);
Bol_Pain4 = !digitalRead(Con_Pain4);
Bol_Pain5 = !digitalRead(Con_Pain5);
Bol_Pain6 = !digitalRead(Con_Pain6);

if (Bol_Pain1 == true){Fun_LEDit(Con_LEDvih, 1); // jatkuva
}else if(Bol_Pain2 == true){Fun_LEDit(Con_LEDpun, 1);
}else if(Bol_Pain3 == true){Fun_LEDit(Con_LEDvih, 2); // pilkahdus
}else if(Bol_Pain4 == true){Fun_LEDit(Con_LEDpun, 2);
}else if(Bol_Pain5 == true){Fun_LEDit(Con_LEDvih, 3); // tasavilkku
}else if(Bol_Pain6 == true){Fun_LEDit(Con_LEDpun, 3);
}else {Fun_LEDit(0, 0);} // LEDien sammutus (default)
delay(1);
} // Pääohjelma LOPPU