Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

DIY-regenvoorspelling met Arduino, Python en Keras

Componenten en benodigdheden

Kleine plastic doos met afneembare deksels (de mijne heeft schroeven)
× 1
drie AAA-batterijhouder
× 1
drie oplaadbare AAA-batterijen
× 1
6V klein zonnepaneel
× 1
SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
1N4004-diode
× 1
Transistor-NPN voor algemeen gebruik
× 1
een regensensor
× 1
HC-12 seriële communicatiemodule
× 1
HC-12 seriële USB-module
× 1
SparkFun Atmosferische Sensor Breakout - BME280
× 1
BH1750
× 1
PCB, draden, soldeer, KF301-2P plug-in schroefconnector , mannelijke en vrouwelijke pcb-connectoren, lijm
× 1
3.3V-regelaar
× 1

Benodigde gereedschappen en machines

USB naar seriële FTDI-adapter FT232RL
Boor
Soldeerbout (algemeen)
Schroevendraaiers

Over dit project

Eerst een paar woorden over dit project, de motivatie, de betrokken technologieën en het eindproduct dat we gaan bouwen.

Dus het grote doel hier is natuurlijk om de regen in de toekomst te voorspellen (we zullen 6 uur proberen). De voorspelling zal een ja of nee zijn (boolean in programmeertermen). Ik heb gezocht in tutorials over deze kwestie en ik heb er geen gevonden die in alle opzichten compleet is. Dus de mijne zal dit naar een geheel nieuwe benadering brengen en in elk aspect ervan ingaan. Daarvoor gaan we:

  • bouwen het weerstation zelf. Het station moet volledig off-grid zijn met een zonnepaneel en een extreem laag stroomverbruik (enkele tientallen microampère uur)
  • programma het station zodat het gegevens verzamelt en deze elke tien minuten naar een basisstation verzendt
  • verzamelen de gegevens op het basisstation en sla deze op (in een database)
  • met behulp van neurale netwerken (Keras-bibliotheek) en andere Python-bibliotheken zoals panda's filteren, reinigen en verwerken de gegevens en voeren deze vervolgens naar een neuraal netwerk om een ​​"model" te trainen om te voorspellen of het wel of niet zal regenen
  • eindelijk voorspel of het de komende 6 uur wel of niet gaat regenen en stel gebruikers op de hoogte via e-mail

Ik heb dit weerstation persoonlijk gebruikt om gegevens te verzamelen (je kunt de gegevens desgewenst in de volgende stappen downloaden). Met slechts ongeveer 600 dagen aan weergegevens kan het systeem een ​​voorspelling doen of het de komende 6 uur gaat regenen of niet met een nauwkeurigheid van ongeveer 80%, afhankelijk van de parameters, wat niet zo slecht is.

In deze zelfstudie nemen we u door alle noodzakelijke stappen om regenval vanaf het begin te voorspellen. We maken een eindproduct dat praktisch werkt, zonder externe API's voor weer of machine learning te gebruiken. We zullen gaandeweg leren hoe we een praktisch weerstation kunnen bouwen (laag stroomverbruik en off-grid) dat echt gegevens verzamelt over lange perioden zonder onderhoud. Daarna leer je hoe je het programmeert met Arduino IDE. Gegevens verzamelen in een database op een basisstation (server). En hoe de gegevens te verwerken (Panda's) en neurale netwerken toe te passen (Keras) en vervolgens de regenval te voorspellen.

Stap 1:Onderdelen en gereedschappen voor het bouwen van het station

Onderdelen:

1. Kleine plastic doos met afneembare deksels (de mijne heeft schroeven). Het formaat van de doos moet groot genoeg zijn voor de kleine onderdelen en batterijen. Mijn doos heeft een afmeting van 11 x 7 x 5 cm

2. drie AAA-batterijhouders

3. drie oplaadbare AAA-batterijen

4. 6V klein zonnepaneel

5. Arduino Pro Mini 328p

6. een diode, 1N4004 (om tegenstroom van de batterijen naar het paneel te voorkomen)

7. een kleine NPN-transistor en 1k-weerstand (voor het in- en uitschakelen van de voeding naar de componenten)

8. een regensensor

9. HC-12 seriële communicatiemodule

10. HC-12 USB seriële module (voor het basisstation)

11. BME280 bosch sensormodule (voor vochtigheid, temperatuur, druk)

12. BH1750 lichtgevoelige module

13. PCB, draden, soldeer, KF301-2P plug-in schroefconnector, mannelijke en vrouwelijke pcb-connectoren, lijm

14. 3.3V regelaar

15. een basisstation:een pc of een ontwikkelbord dat de hele tijd draait. Het is zijn rol om gegevens te verzamelen, het regenvoorspellingsmodel te trainen en voorspellingen te doen

Hulpprogramma's:

1. USB naar seriële FTDI-adapter FT232RL om de Arduino Pro Mini te programmeren

2. Arduino IDE

3. Boor

4. Fijnzaagblad

5. Schroevendraaiers

6. Soldeerbout

7. Draadknipper

Vaardigheden:

1. Solderen, bekijk deze tutorial

2. Basis Arduino-programmering

3. Linux-serviceconfiguratie, pakketinstallatie

4. Enkele programmeervaardigheden

Stap 2:Het weerstation bouwen

Het weerstation is samengesteld uit de volgende sets componenten:

1. de doos met het zonnepaneel erop geplakt

2 . de print met de elektronica erin

3. de batterijhouder ook binnen

4. de BME280 en licht- en regensensoren aan de buitenkant

1. De doos heeft 4 gaten nodig, een voor de draden van het zonnepaneel, de andere drie voor de sensoren die aan de buitenkant worden geplaatst. Boor eerst de gaten, ze moeten groot genoeg zijn om de mannelijke-vrouwelijke draden uit te steken en naar de sensoren te gaan. Nadat de gaten zijn geboord, lijmt u het paneel aan een kant van de doos en haalt u de draden door een gat naar binnen

2. De PCB bevat de arduino, HC-12, 3.3V-regelaar, diode, transistor, weerstand en twee KF301-2P

  • Soldeer eerst de twee vrouwelijke printconnectoren op de printplaat voor de arduino, soldeer de mannelijke printconnectoren op de arduino en plaats de arduino op de print
  • de arduino-led moet worden verwijderd of op zijn minst een van zijn pinnen. dit is erg belangrijk omdat de led veel stroom trekt. Pas op dat u geen andere onderdelen beschadigt
  • soldeer de transistor, weerstand en 3.3V regelaar
  • soldeer de twee KF301-2P. De ene is voor het zonnepaneel, de andere voor de batterijhouder
  • soldeer drie vrouwelijke printconnectoren:voor de lichtsensor, BME280 en regensensor
  • soldeer kleine draden om alle PCB-componenten aan te sluiten (bekijk de foto's en de fritzing schamatic)

3. plaats 3 opgeladen AAA NiMH-batterijen in de houder en plaats deze in de doos, waarbij u de draden aansluit op de KF301-2P-connector

4. sluit de BME280 en lichtsensoren van buiten de doos aan op hun corresponderende mannelijke connectoren

Voor de regensensor, soldeer er drie draden (Gnd, Vcc, signaal) aan, en aan de andere kant soldeer mannelijke pinnen die in de doos naar de overeenkomstige mannelijke connectoren gaan

Het laatste zou zijn om het station op zijn definitieve positie te plaatsen. Ik heb een positie gekozen die beschut is tegen regen en sneeuw. Ik heb voor de regensensor langere draden gekozen en apart in de regen op een stevige steun geplaatst. Voor de hoofddoos heb ik een speciaal soort tape met lijm gekozen (zie de foto's), maar alles wat de doos vasthoudt, is voldoende.

schets.fzz

Stap 3:Arduino-code

In deze stap leer je welke externe bibliotheken nodig zijn, we geven een overzicht van de code en hoe het werkt en natuurlijk kun je het downloaden of kopiëren en plakken in Arduino IDE en uploaden naar het weerstation.

De rol van het weerstation is om elke 10 minuten gegevens over zijn sensoren naar een basisstation te verzenden.

Laten we eerst beschrijven wat het programma van het weerstation doet:

1. sensorgegevens uitlezen (vochtigheid, temperatuur, druk, regen, licht, spanning)

2. verzendt de gecodeerde gegevens via een tweede seriële softwarelijn.

De gecodeerde gegevens zien er als volgt uit:

H1:78|T1:12|PS1:1022|L1:500|R1:0|V1:4010|  

De bovenstaande verklaring betekent dat:vochtigheid vanaf station "1" 78 procent is, temperatuur vanaf station 1 12 graden is, druk 1022 bar is, lichtniveau 500 lux, regen 0 en spanning 4010 millivolt

3. schakel de hulpcomponenten uit:sensoren en communicatieapparaat

4. zet de arduino 10 minuten in de slaapstand (hierdoor verbruikt hij minder 50 microampère)

5. schakel de componenten in en herhaal stap 1 - 4

Een kleine extra aanpassing hier, als het spanningsniveau hoger is dan 4,2 V, gebruikt de arduino de normale slaapfunctie "vertraging (milliseconden)". Dit zal het stroomverbruik aanzienlijk verhogen en de spanning snel verlagen. Dit voorkomt effectief dat het zonnepaneel de batterijen overlaadt.

Je kunt de code hier uit mijn Github-repository halen:https://github.com/danionescu0/home-automation/tre...

Of kopieer en plak het van onderaf, hoe dan ook verwijder de regel met "transmitSenzorData("V", sensors.voltage);"

#include "LowPower.h"
#include "SoftwareSerial.h"#include "Wire.h"#include "Adafruit_Sensor.h"#include "Adafruit_BME280.h"#include "BH1750.h "SoftwareSerial serialComm(4, 5); // RX, TXAdafruit_BME280 bme; BH1750 lightMeter;const byte rainPin =A0;byte sensorsCode =1;/** * spanningsniveau dat de microcontroller in diepe slaap brengt in plaats van in normale slaap */int voltageDeepSleepThreshold =4200; const byte randapparatuurPowerPin =6;char buffer[] ={' ',' ',' ',' ',' ',' ',' '};struct sensorData {byte vochtigheid; int temperatuur; byte regen; int. druk; lange spanning; int licht; };sensorData-sensoren;void setup() {Serial.begin(9600); serialComm.begin (9600); pinMode (randapparatuurPowerPin, OUTPUT); digitalWrite (randapparatuurPowerPin, HIGH); vertraging (500); if (!bme.begin()) { Serial.println("Kon geen geldige BME280-sensor vinden, controleer de bedrading!"); terwijl (1) { customSleep(100); } } Serial.println("Initialisatie is voltooid"); vertraging (50); digitalWrite(randapparatuurPowerPin, HIGH);}void loop() { updateSenzors(); verzendgegevens(); customSleep(75); }nietig updateSenzors() { bme.begin(); lichtmeter.begin(); vertraging (300); sensoren.temperatuur =bme.readTemperature(); sensoren.druk =bme.readPressure() / 100.0F; sensors.humidity =bme.readHumidity(); sensoren.light =lightMeter.readLightLevel(); sensoren.voltage =readVcc(); sensors.rain =readRain();}void transmitterData(){ emptyIncommingSerialBuffer(); Serial.print("Temp:");Serial.println(sensoren.temperatuur); Serial.print("Vochtig:");Serial.println(sensoren.vochtigheid); Serial.print("Druk:");Serial.println(sensoren.druk); Serial.print("Light:");Serial.println(sensors.light); Serial.print("Spanning:");Serial.println(sensoren.voltage); Serial.print("Regen:");Serial.println(sensoren.regen); transmitterSenzorData("T", sensoren.temperatuur); transmitterSenzorData("H", sensoren.vochtigheid); transmitterSenzorData("PS", sensoren.druk); transmitterSenzorData("L", sensors.light); transmitterSenzorData ("V", sensoren.voltage); transmitterSenzorData("R", sensors.rain);}void emptyIncommingSerialBuffer(){ while (serialComm.available()> 0) { serialComm.read(); vertraging (5); }}void transmitterSenzorData(String type, int value){ serialComm.print(type); serialComm.print(sensorsCode); serialComm.print(":"); serialComm.print(waarde); serialComm.print("|"); vertraging (50);} ongeldig customSleep (lange eightSecondCycles){ if (sensors.voltage> voltageDeepSleepThreshold) {delay (eightSecondCycles * 8000); opbrengst; } digitalWrite (randapparatuurPowerPin, LOW); for (int i =0; i

Download en installeer de volgende Arduino-bibliotheken voordat u de code uploadt:

* BH1750-bibliotheek:https://github.com/claws/BH1750 * LowPower-bibliotheek:https://github.com/rocketscream/Low-Power

* Adafruit Sensor-bibliotheek:https://github.com/adafruit/Adafruit_Sensor

* Adafruit BME280-bibliotheek:https://github.com/adafruit/Adafruit_Sensor

Als je niet weet hoe je dat moet doen, bekijk dan deze tutorial.

Stap 4:Het basisstation voorbereiden

Het basisstation zal bestaan ​​uit een linux-computer (desktop, laptop of ontwikkelbord) met de HC-12 USB module aangesloten. De computer moet altijd aan staan ​​om elke 10 minuten gegevens van het station te verzamelen.

Ik heb mijn laptop met Ubuntu 18 gebruikt.

De installatiestappen:

1. Installeer anaconda. Anaconda is een Python-pakketbeheerder en het maakt het voor ons gemakkelijk om met dezelfde afhankelijkheden te werken. We zullen de Python-versie kunnen controleren, en elke pakketversie

Als je niet weet hoe je het moet installeren, kijk dan hier:https://www.digitalocean.com/community/tutorials/h... tutorial en volg de stappen 1 - 8

2. Installeer mongoDb. MongoDb zal onze belangrijkste database voor dit project zijn. Het zal gegevens opslaan over alle tijdreeksen van de sensoren. Het is schemaloos en voor ons doel gemakkelijk te gebruiken.

Ga voor installatiestappen naar hun pagina:https://docs.mongodb.com/v3.4/tutorial/install-mon...

Ik heb een oudere versie van mongoDb 3.4.6 gebruikt, als je de bovenstaande tutorial volgt, krijg je precies dat. In principe zou het moeten werken met de laatste versie.

[Optioneel] voeg een index toe aan het datumveld:

Mongoolse weer db.weather_station.createIndex({"date" :1}) 

3. Download het project hier:https://github.com/danionescu0/home-automation. We gebruiken de weersvoorspellingsmap

sudo apt-get install gitgit clone https://github.com/danionescu0/home-automation.gi... 

4. Anaconda-omgeving maken en configureren:

cd weather-predict # maak een anaconda-omgeving met de naam "weather" met python 3.6.2conda create --name weather python=3.6.2 # activeer environmentconda activeer weer# installeer alle pakketten pip install -r requirements.txt  

Dit zal een nieuwe anaconda-omgeving creëren en de benodigde pakketten installeren. Sommige van de pakketten zijn:

Keras (neurale netwerklaag op hoog niveau, met deze bibliotheek maken we al onze neurale netwerkvoorspellingen)

panda's (handige tool die gegevens manipuleert, we zullen er veel gebruik van maken)

pymongo (python mongoDb-stuurprogramma)

sklearn (tools voor datamining en data-analyse)

Configureer het project

Het configuratiebestand bevindt zich in de weersvoorspellingsmap en heet config.py

1. als u MongoDb op afstand of op een andere poort installeert, wijzigt u de "host" of "poort" in de

mongodb ={ 'host':'localhost', 'poort':27017}... 

2. Nu moeten we de HC-12 USB seriële adapter aansluiten. Voor dan rennen:

ls -l /dev/tty* 

en je zou een lijst met gekoppelde apparaten moeten krijgen.

Steek nu de HC-12 in een USB-poort en voer dezelfde opdracht opnieuw uit. Het zou een nieuwe vermelding in die lijst moeten zijn, onze seriële adapter. Wijzig nu indien nodig de adapterpoort in de configuratie

serial ={ 'port':'/dev/ttyUSB0', 'baud_rate':9600} 

De andere configuratie-items zijn enkele standaardpaden voor bestanden, daar hoeft u niets te wijzigen.

Stap 5:Gebruik het weerstation in de praktijk

Hier bespreken we basisdingen over het importeren van mijn testgegevens, het uitvoeren van enkele tests, het opzetten van uw eigen gegevens, het weergeven van enkele grafieken en het opzetten van een e-mail met voorspelling voor de komende uren.

Als je meer wilt weten over hoe het werkt, bekijk dan de volgende stap "Hoe werkt het"

Mijn reeds verzamelde gegevens importeren

MongoDb wordt geleverd met een cli-opdracht voor het importeren van gegevens uit json:

mongoimport -d weather -c weather_station --file sample_data/weather_station.json 

Dit importeert het bestand van voorbeeldgegevens naar de "weer"-database en de verzameling "datapunten"

Een waarschuwing hier, als je mijn verzamelde gegevens gebruikt en deze combineert met je nieuwe lokale gegevens, kan de nauwkeurigheid afnemen vanwege de kleine verschillen in hardware (sensoren) en lokale weerpatronen.

Nieuwe gegevens verzamelen

Een van de functies van het basisstation is het opslaan van binnenkomende gegevens van het weerstation in de database voor latere verwerking. Om het proces te starten dat naar de seriële poort luistert en in de database opslaat, voert u het volgende uit:

conda activeer weatherpython serial_listener.py# elke 10 minuten zou je gegevens van het weerstation moeten zien binnenkomen :[Sensor:type(temperature), value(14.3)][Sensor:type(pressure), value( 1056.0)]... 

Het voorspellingsmodel genereren

Ik neem aan dat je mijn gegevens hebt geïmporteerd of "het script een paar jaar hebt uitgevoerd" om je gepersonaliseerde gegevens te verzamelen, dus in deze stap verwerken we de gegevens om een ​​model te maken dat wordt gebruikt om toekomstige regen te voorspellen.

conda activeert weatherpython train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 8 --hour-granularity 6 

* De eerste parameter --days_behind betekent hoeveel data in het verleden het script moet verwerken. Het wordt gemeten in dagen

* --test-file-percent betekent hoeveel van de gegevens in aanmerking moeten worden genomen voor testdoeleinden, dit is een normale stap in een machine learning-algoritme

* --hour-granularity betekent in feite hoeveel uur in de toekomst we de voorspelling willen hebben

* --datapoints-behind deze parameter wordt verder besproken in de volgende sectie

Bekijk enkele gegevenskaarten met alle sensoren van het weerstation

Laten we zeggen voor de afgelopen 10 dagen:

conda activeert weerpython-grafieken --days-behind 10 

Voorspel of het de komende periode gaat regenen

We voorspellen of het gaat regenen en sturen een e-mailmelding

conda activeert weerpython predict.py --datapoints-behind 8 --hour-granularity 6 --from-addr a_gmail_address --from-password gmail_password --to-addr a_email_destination 

Voer een batchvoorspelling uit op de testgegevens:

python predict_batch.py ​​-f sample_data/test_data.csv 

Het is belangrijk om dezelfde parameters te gebruiken als in het bovenstaande treinscript.

Om de e-mailmelding te laten werken, logt u in op uw Gmail-account en schakelt u Minder veilige apps toestaan ​​in op AAN. Houd er rekening mee dat dit het voor anderen gemakkelijker maakt om toegang te krijgen tot uw account.

Je hebt twee e-mailadressen nodig, een Gmail-adres waarop bovenstaande optie is geactiveerd en een ander adres waarop je je melding ontvangt.

Als je elk uur meldingen wilt ontvangen, zet je het script in crontab

Bekijk de volgende stap om te zien hoe dit allemaal mogelijk is

Stap 6:Hoe werkt het

In deze laatste stap zullen we verschillende aspecten van de architectuur van dit project bespreken:

1. Projectoverzicht, we bespreken de algemene architectuur en betrokken technologieën

2. Basisconcepten van machine learning

3. Hoe de gegevens worden voorbereid (de belangrijkste stap)

4. Hoe de eigenlijke neurale netwerkwrapper-API werkt (Keras)

5. Toekomstige verbeteringen

Ik zal proberen hier een codevoorbeeld te geven, maar houd er rekening mee dat het niet 100% de code van het project is. In het project is het zelf de code, het is een beetje ingewikkelder met klassen en een structuur

1. Projectoverzicht, we bespreken de algemene architectuur en betrokken technologieën

Zoals we eerder hebben besproken, bestaat het project uit twee afzonderlijke delen. Het weerstation zelf heeft als enige functie het verzamelen en verzenden van gegevens. En het basisstation waar alle verzamelingstrainingen en -voorspellingen zullen plaatsvinden.

Voordelen van de scheiding van het weerstation en het basisstation:

  • stroomvereisten, als het weerstation de gegevens ook zou kunnen verwerken, zou het veel stroom nodig hebben, misschien grote zonnepanelen of een permanente stroombron
  • draagbaarheid, vanwege het kleine formaat kan het weerstation gegevens van een paar honderd meter afstand verzamelen en u kunt indien nodig gemakkelijk van plaats veranderen
  • schaalbaarheid, u kunt de voorspellingsnauwkeurigheid vergroten door meer dan één weerstation te bouwen en deze over een paar honderd meter te verspreiden
  • lage kosten, omdat het een goedkoop apparaat is dat u gemakkelijk kunt bouwen voor het geval er een verloren of gestolen is

De databasekeuze . Ik heb mongoDb gekozen omdat het leuke functies heeft:schemaloze, gratis en gebruiksvriendelijke API

Elke keer dat sensorgegevens worden ontvangen, worden de gegevens opgeslagen in de database, en de gegevensinvoer ziet er ongeveer zo uit:

{ "_id" :"04_27_2017_06_17", "vochtigheid" :65, "date" :ISODate("2017-04-27T06:17:18Z"), "druk" :1007, "temperatuur" :9, "regen":0, "licht":15} 

De database slaat gegevens op in BSON-formaat (vergelijkbaar met JSON), dus het is gemakkelijk te lezen en gemakkelijk om mee te werken. Ik heb de gegevens samengevoegd onder een ID die de datum bevat die is opgemaakt als tekenreeks voor de minuten, dus de kleinste groepering hier is een minuut.

Het weerstation zendt (mits goed werkend) elke 10 minuten een datapunt uit. Een datapunt is een verzameling van waarden voor "datum", "vochtigheid", "druk", "temperatuur", "regen" en "licht".

De gegevensverwerking en het neurale netwerk technologie keuze

Ik heb Python gekozen voor de backend omdat veel grote innovaties in neurale netwerken in Python te vinden zijn. Een groeiende community met veel Github-repositories, tutorials, blogs en boeken zijn hier om te helpen.

* Voor het gegevensverwerkingsgedeelte heb ik Panda's gebruikt (https://pandas.pydata.org/ ) . Panda's maken het werken met gegevens gemakkelijk. U kunt tabellen laden vanuit CSV-, Excel-, Python-gegevensstructuren en ze opnieuw ordenen, kolommen neerzetten, kolommen toevoegen, per kolom indexeren en vele andere transformaties.

* Voor het werken met neurale netwerken heb ik gekozen voor Keras (https://keras.io/). Keras is een neuraal netwerk-wrapper op hoog niveau over meer API's op een lager niveau, zoals Tensorflow, en men kan een neuraal netwerk met meerdere lagen bouwen met een tiental regels code of zo. Dit is een groot voordeel omdat we iets nuttigs kunnen bouwen op het geweldige werk van andere mensen. Welnu, dit zijn de basisdingen van programmeren, bouwen op andere kleinere bouwstenen.

2. Basisconcepten van machine learning

Het doel van deze tutorial is niet om machine learning te leren, maar alleen om een ​​van de mogelijke use-cases te schetsen en hoe we deze praktisch kunnen toepassen op deze use-case.

Neurale netwerken zijn gegevensstructuren die lijken op hersencellen die neuronen worden genoemd. De wetenschap ontdekte dat een brein speciale cellen heeft, neuronen genaamd, die met andere neuronen communiceren door elektrische impulsen via "lijnen" die axonen worden genoemd. Indien voldoende gestimuleerd (van vele andere neuronen) zullen de neuronen een elektrische impuls veroorzaken verder weg in dit "netwerk" dat andere neuronen stimuleert. Dit is natuurlijk een te grote vereenvoudiging van het proces, maar in feite proberen computeralgoritmen dit biologische proces te repliceren.

In neurale netwerken van computers heeft elk neuron een "triggerpunt" waar het, als het over dat punt wordt gestimuleerd, de stimulatie naar voren zal voortplanten, zo niet, dan zal het dat niet doen. Hiervoor heeft elk gesimuleerd neuron een vooroordeel en elk axon een gewicht. Na een willekeurige initialisatie van deze waarden start een proces genaamd "leren", dit betekent dat in een lus een algoritme deze stappen zal uitvoeren:

  • stimuleer de input-neuronen
  • verspreiden de signalen door de netwerklagen tot de outputneuronen
  • lees de output neuronen en vergelijk de resultaten met de gewenste resultaten
  • Tweak de gewichten van de axonen voor een beter resultaat de volgende keer
  • begin opnieuw totdat het aantal lussen is bereikt

Als je meer details over dit proces wilt weten, kun je dit artikel lezen:https://mattmazur.com/2015/03/17/a-step-by-step-ba.... Er zijn ook talloze boeken en tutorials die er zijn.

Nog een ding, hier zullen we een begeleide leermethode gebruiken. Dat betekent dat we het algoritme ook de inputs en outputs leren, zodat het, gegeven een nieuwe set inputs, de output kan voorspellen.

3. Hoe de gegevens worden voorbereid (de belangrijkste stap)

Bij veel problemen met machine learning en neurale netwerken is gegevensvoorbereiding een zeer belangrijk onderdeel en omvat het:

  • haal de onbewerkte gegevens
  • gegevensopschoning:dit betekent het verwijderen van weeswaarden, afwijkingen of andere anomalieën
  • gegevensgroepering:veel datapunten nemen en omzetten in een geaggregeerd datapunt
  • gegevensversterking:andere aspecten van de gegevens toevoegen die zijn afgeleid van eigen gegevens of van externe bronnen
  • de gegevens splitsen in trein- en testgegevens
  • splits elk van de trein- en testgegevens in in- en uitgangen. Meestal heeft een probleem veel ingangen en een paar uitgangen
  • schaal de gegevens opnieuw zodat ze tussen 0 en 1 liggen (dit zal het netwerk helpen om vooroordelen met een hoge/lage waarde te verwijderen)

De onbewerkte gegevens ophalen

In ons geval is het heel eenvoudig om gegevens voor MongoDb in python te krijgen. Gezien onze verzameling van datapunten zijn alleen deze coderegels voldoende

client =MongoClient(host, poort).weather.datapoints cursor =client.find( {'$and':[ {'date':{'$gte':start_date}}, {'date' :{'$lte' :end_date}} ]} )data =lijst(cursor).. 

Gegevens opschonen

De lege waarden in het dataframe worden verwijderd

dataframe =dataframe.dropna() 

Gegevensgroepering en gegevensverbetering

This is a very important step, the many small datapoins will be grouped into intervals of 6 hours. For each group several metrics will be calculated on each of the sensors (humidity, rain, temperature, light, pressure)

  • min value
  • max value
  • mean
  • 70, 90, 30, 10 percentiles
  • nr of times there has been a rise in a sensor
  • nr of times there has been a fall in a sensor
  • nr of times there has been steady values in a sensor

All of these things will give the network information for a datapoint, so for each of the 6 hours intervals these things will be known.

From a dataframe that looks like this:

_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0  

And the transformation will be:"

_id date humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile humidity_avg ... temperature_avg temperature_fall temperature_max temperature_min temperature_rise temperature_steady ... 04_27_2017_0 2017-04-27 03:08:36 59.6 60.8 63.2 66.0 62.294118 ... 10.058824 2 11.0 9.0 1 1404_27_2017_1 2017-04-27 06:06:50 40.3 42.0 60.0 62.0 50.735294 ... 14.647059 3 26.0 9.0 11 2004_27_2017_2 2017-04-27 12:00:59 36.0 37.0 39.8 42.0 38.314286 ... 22.114286 1 24.0 20.0 5 29  

After this a new column named "has_rain" will be added. This will be the output (our predicted variable). Has rain will be 0 or 1 depending if the rain average is above a threshold (0.1). With pandas it's as simple as:

dataframe.insert(loc=1, column='has_rain', value=numpy.where(dataframe['rain_avg']> 0.1, 1, 0)) 

Data cleanup (again)

- we'll drop the date column because it's no use to us, and also remove datapoints where the minimum temperature is below 0 because our weather station it doesn't have a snow sensor, so we won't be able to measure if it snowed

dataframe =dataframe.drop(['date'], axis=1)dataframe =dataframe[dataframe['temperature_min']>=0] 

Data enhancing

Because data in the past might influence our prediction of the rain, we need for each of the dataframe rows to add columns reference to the past rows. This is because each of the row will serve as a training point, and if we want the prediction of the rain to take into account previous datapoints that's exactly what we should do:add more columns for datapoints in the past ex:

_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0  

So you see that for every sensor let's say temperature the following rows will be added:"temperature_1", "temperature_2".. meaning temperature on the previous datapoint, temperature on the previous two datapoints etc. I've experimented with this and I found that a optimum number for our 6 hour groupings in 8. That means 8 datapoints in the past (48 hours). So our network learned the best from datapoins spanning 48 hours in the past.

Data cleanup (again)

As you see, the first few columns has "NaN" values because there is nothing in front of them so they should be removed because they are incomplete.

Also data about current datapoint should be dropped, the only exception is "has_rain". the idea is that the system should be able to predict "has_rain" without knowing anything but previous data.

Splitting the data in train and test data

This is very easy due to Sklearn package:

from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ... 

This will split the data randomly into two different sets

Split each of the train and test data into inputs and outputs

Presuming that our "has_rain" interest column is located first

X =main_data.iloc[:, 1:].valuesy =main_data.iloc[:, 0].values  

Rescale the data so it's between 0 and 1

Again fairly easy because of sklearn

from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save')  

4. How the actual neural network wrapper API works (Keras)

Building a multi layer neural network with Keras is very easy:

from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name') 

So what does this code mean? Here we're building a sequential model, that means sequentially all the layers will be evaluated.

a) we declare the input layer (Dense), here all the inputs from our dataset will be initializedm so the "input_dim" parameter must be equal to the row length

b) a Dropout layer is added. To understand the Dropout first we must understand what "overfitting" means:it's a state in which the network has learned too much particularities for a specific dataset and will perform badly when confronted to a new dataset. The dropout layer will disconnect randomly neurons at each iteration so the network won't overfit.

c) another layer of Dense is added

d) another Dropout

e) the last layer is added with one output dimension (it will predict only yes/no)

f) the model is "fitted" that means the learning process will begin, and the model will learn

Other parameters here:

  • activation functions (sigmoid, relu). This are functions that dictate when the neuron will transmit it's impulse further in the network. There are many, but sigmoid and relu are the most common. Check out this link for more details:https://towardsdatascience.com/activation-function...
  • kernel_initializer function (uniform). This means that all the weights are initialized with random uniform values
  • loss function (mean_absolute_error). This function measures the error comparing the network predicted result versus the ground truth. There are many alternatives:https://keras.io/losses/
  • metrics function (accuracy). It measures the performance of the model
  • optimiser functions (rmsprop). It optimizes how the model learn through backpropagation.
  • batch_size. Number of datapoints to take once by Keras before applying optimizer function
  • epochs:how many times the process it's started from 0 (to learn better)

There is no best configuration for any network or dataset, all these parameters can an should be tuned for optimal performance and will make a big difference in prediction success.

5. Future improvements

Let's start from the weather station , I can see a lot of improving work to be done here:

  • add a wind speed / direction sensor. This could be a very important sensor that i'm missing in my model
  • experiment with UV rays, gas and particle sensors
  • add at least two stations in the zone for better data (make some better averages)
  • collect a few more years of data, i've experimented with just a year and a half

Some processing improvements:

  • try to incorporate data from other sources into the model. You can start to import wind speed data and combine with the local station data for a better model. This website offers historical data:https://www.wunderground.com/history/
  • optimize the Keras model better by adjusting:layers, nr of neurons in layers, dropout percents, metrics functions, optimiser functions, loss functions, batch size, learning epochs
  • try other model architectures, for example i've experimented with LSTM (long short term memory) but it gived slightly poorer results)

To try different parameters on the learning model you can use

python train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 6 --hour-granularity 6 --grid-search 

This will search through different "batch_size", "epoch", "optimizer" and "dropout" values, evaluate all and print out the best combination for your data.

If you have some feedback on my work please share it, thanks for staying till the end of the tutorial!

Step 7:Bonus:Using an Official Weather Dataset

I was wondering if I can get better results with a more reliable weather station, so i've searched a bit, and i've came across "Darksky AP I" (https://darksky.net/dev), this is a great tool that provides current and historical weather data with many more sensor data:

  • temperature
  • humidity
  • pressure
  • wind speed
  • wind gust
  • ub index
  • visibilitySo this beeing data from an official weather station, and having more parameters I thought it should perform better so i've gave it a try. To replicate my findings:

1.Download the data from darsky or import my MongoDb collection:

a) Download

  • to download your self, first create an account in darsky and get the API key
  • replace the API key in download_import/config.py
  • also in the config replace the geographic coordonates for the location you want to predict the rain
  • in a console activate "weather" anaconda environment and run:
python download_import/darksky.py -d 1000 

- the free version of the API is limited to 1000 requests per day so if you want more data you need to wait for a longer time

b) Import my downloaded data for Bucharest city

- in a console run

mongoimport -d weather -c darksky --file sample_data/darksky.json  

2. When you train the model specify that it should run on "darksy" dataset

python train.py -d 2000 -p 20 -dp 4 -hg 6 --data-source darksky 

3. To see the results run predict batch script as before

python predict_batch.py -f sample_data/test_data.csv 

You'll see that the overall prediction percent has gone from about 80% to 90%. Also the prediction accuracy when accounting only rainy days has gone up.

So yes, the dataset really matters.

Code

  • Codefragment #2
  • Codefragment #5
  • Code snippet #6
  • Code snippet #10
  • Code snippet #15
  • Code snippet #16
  • Code snippet #18
  • Code snippet #22
  • Code snippet #23
  • Code snippet #25
  • Code snippet #26
Codefragment #2Platte tekst
#include "LowPower.h"
#include "SoftwareSerial.h"#include "Wire.h"#include "Adafruit_Sensor.h"#include "Adafruit_BME280.h"#include "BH1750.h"SoftwareSerial serialComm(4, 5); // RX, TXAdafruit_BME280 bme; BH1750 lightMeter;const byte rainPin =A0;byte sensorsCode =1;/** * voltage level that will pun the microcontroller in deep sleep instead of regular sleep */int voltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6;char buffer[] ={' ',' ',' ',' ',' ',' ',' '};struct sensorData { byte humidity; int temperature; byte rain; int pressure; long voltage; int light; };sensorData sensors;void setup() { Serial.begin(9600); serialComm.begin(9600); pinMode(peripherialsPowerPin, OUTPUT); digitalWrite(peripherialsPowerPin, HIGH); vertraging (500); if (!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1) { customSleep(100); } } Serial.println("Initialization finished succesfully"); vertraging (50); digitalWrite(peripherialsPowerPin, HIGH);}void loop() { updateSenzors(); transmitData(); customSleep(75); }void updateSenzors() { bme.begin(); lightMeter.begin(); vertraging (300); sensors.temperature =bme.readTemperature(); sensors.pressure =bme.readPressure() / 100.0F; sensors.humidity =bme.readHumidity(); sensors.light =lightMeter.readLightLevel(); sensors.voltage =readVcc(); sensors.rain =readRain();}void transmitData(){ emptyIncommingSerialBuffer(); Serial.print("Temp:");Serial.println(sensors.temperature); Serial.print("Humid:");Serial.println(sensors.humidity); Serial.print("Pressure:");Serial.println(sensors.pressure); Serial.print("Light:");Serial.println(sensors.light); Serial.print("Voltage:");Serial.println(sensors.voltage); Serial.print("Rain:");Serial.println(sensors.rain); transmitSenzorData("T", sensors.temperature); transmitSenzorData("H", sensors.humidity); transmitSenzorData("PS", sensors.pressure); transmitSenzorData("L", sensors.light); transmitSenzorData("V", sensors.voltage); transmitSenzorData("R", sensors.rain);}void emptyIncommingSerialBuffer(){ while (serialComm.available()> 0) { serialComm.read(); delay(5); }}void transmitSenzorData(String type, int value){ serialComm.print(type); serialComm.print(sensorsCode); serialComm.print(":"); serialComm.print(value); serialComm.print("|"); delay(50);}void customSleep(long eightSecondCycles){ if (sensors.voltage> voltageDeepSleepThreshold) { delay(eightSecondCycles * 8000); opbrengst; } digitalWrite(peripherialsPowerPin, LOW); for (int i =0; i
Codefragment #5Platte tekst
cd weather-predict # create anaconda environment named "weather" with python 3.6.2conda create --name weather python=3.6.2 # activate environmentconda activate weather# install all packages pip install -r requirements.txt 
Code snippet #6Plain text
mongodb ={ 'host':'localhost', 'port':27017}...
Code snippet #10Plain text
conda activate weatherpython serial_listener.py# every 10 minutes you should see data from the weather station coming in :[Sensor:type(temperature), value(14.3)][Sensor:type(pressure), value(1056.0)]...
Code snippet #15Plain text
{ "_id" :"04_27_2017_06_17", "humidity" :65, "date" :ISODate("2017-04-27T06:17:18Z"), "pressure" :1007, "temperature" :9, "rain" :0, "light" :15}
Code snippet #16Plain text
client =MongoClient(host, port).weather.datapoints cursor =client.find( {'$and' :[ {'date' :{'$gte' :start_date}}, {'date' :{'$lte' :end_date}} ]} )data =list(cursor)..
Code snippet #18Plain text
_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0 
Code snippet #22Plain text
_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0 
Code snippet #23Plain text
from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ...
Code snippet #25Plain text
from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save') 
Code snippet #26Plain text
from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name')
Github
https://github.com/claws/BH1750https://github.com/claws/BH1750
Github
https://github.com/rocketscream/Low-Powerhttps://github.com/rocketscream/Low-Power
Github
https://github.com/adafruit/Adafruit_Sensorhttps://github.com/adafruit/Adafruit_Sensor
Github
https://github.com/adafruit/Adafruit_BME280_Libraryhttps://github.com/adafruit/Adafruit_BME280_Library
Github
https://github.com/danionescu0/home-automationhttps://github.com/danionescu0/home-automation

Schema's

sketch_KAtDa2VReF.fzz
Weather station arduino sketch
https://github.com/danionescu0/home-automation/tree/master/arduino-sketches/weatherStation

Productieproces

  1. Python- en Raspberry Pi-temperatuursensor
  2. DIY Photoshop-bewerkingsconsole met Arduino Nano RP 2040
  3. Python Bestand en Directory hernoemen met os.rename()
  4. Aanwezigheidssysteem met Arduino en RFID met Python
  5. Universele afstandsbediening met Arduino, 1Sheeld en Android
  6. DIY voltmeter met Arduino en smartphone
  7. DIY infrarood hartslagsensor met Arduino
  8. Frequentie- en werkcyclusmeting met Arduino
  9. DIY voltmeter met Arduino en een Nokia 5110-display
  10. Sonar met arduino en weergave op verwerkings-IDE
  11. LED-helderheid regelen met Bolt en Arduino