Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Предсказание дождя своими руками с использованием Arduino, Python и Keras

Компоненты и расходные материалы

Маленькая пластиковая коробка со съемными крышками (у меня есть винты)
× 1
держатель для трех батареек AAA
× 1
три аккумуляторные батареи AAA
× 1
Маленькая солнечная панель 6 В
× 1
SparkFun Arduino Pro Mini 328 - 5 В / 16 МГц
× 1
диод 1N4004
× 1
NPN-транзистор общего назначения
× 1
датчик дождя
× 1
Модуль последовательной связи HC-12
× 1
Последовательный USB-модуль HC-12
× 1
Прорыв датчика атмосферы SparkFun - BME280
× 1
BH1750
× 1
Печатная плата, провода, припой, штекер KF301-2P в винтовом соединителе , штекеры и розетки для печатных плат, клей
× 1
регулятор 3,3 В
× 1

Необходимые инструменты и машины

USB-последовательный адаптер FTDI FT232RL
Drill
Паяльник (общий)
Отвертки

Об этом проекте

Сначала несколько слов об этом проекте, мотивации, задействованных технологиях и конечном продукте, который мы собираемся создать.

Таким образом, большая цель здесь, очевидно, состоит в том, чтобы предсказать дождь в будущем (мы попробуем 6 часов). Прогноз будет либо да, либо нет (логическое значение в терминах программирования). Я искал из руководств по этому поводу, и я не нашел ни одного, который был бы полным во всех смыслах. Так что я использую совершенно новый подход и рассматриваю все его аспекты. Для этого мы собираемся:

  • сборка Сама метеостанция. Станция должна быть полностью отключена от сети с солнечной панелью и работать в режиме крайне низкого энергопотребления (несколько десятков микроампер в час).
  • программа станции, чтобы она собирала данные и передавала их каждые десять минут на базовую станцию.
  • собирать данные о базовой станции и сохранить их (в базе данных)
  • с помощью нейронных сетей (Библиотека Keras) и другие библиотеки Python, такие как pandas, фильтруют, очищают и предварительно обрабатывают данные, а затем передают их в нейронную сеть для обучения «модели» прогнозированию того, будет ли дождь или нет.
  • наконец предсказать будет ли дождь в ближайшие 6 часов, и уведомить пользователей по электронной почте.

Я лично использовал эту метеостанцию ​​для сбора данных (при желании вы можете загрузить данные в следующих шагах). Имея данные о погоде всего за 600 дней, система может сделать прогноз, будет ли дождь или нет в следующие 6 часов с точностью около 80% в зависимости от параметров, что не так уж и плохо.

В этом уроке мы проведем вас через все необходимые шаги для прогнозирования осадков с нуля. Мы создадим конечный продукт, который будет выполнять практическую работу без использования внешних API-интерфейсов погоды или машинного обучения. Попутно мы узнаем, как построить практичную метеостанцию ​​(маломощную и автономную), которая действительно собирает данные в течение длительных периодов времени без обслуживания. После этого вы узнаете, как его программировать с помощью Arduino IDE. Как собрать данные в базу данных на базовой станции (сервере). И как обрабатывать данные (Pandas) и применять нейронные сети (Keras), а затем предсказывать количество осадков.

Шаг 1. Детали и инструменты для сборки станции

Детали:

1. Маленькая пластиковая коробочка со съемными крышками (у меня винты). Размер коробки должен быть достаточно большим, чтобы в него поместились мелкие компоненты и батареи. В моей коробке 11 x 7 x 5 см

2. три батарейных отсека AAA

3. три аккумуляторные батареи AAA

4. Маленькая солнечная панель 6 В

5. Arduino Pro Mini 328p

6. диод 1N4004 (для предотвращения обратного тока от батарей к панели)

7. небольшой транзистор NPN и резистор 1 кОм (для включения и выключения питания компонентов)

8. датчик дождя

9. Модуль последовательной связи HC-12

10. Последовательный USB-модуль HC-12 (для базовой станции)

11. Модуль датчика BME280 bosch (для влажности, температуры, давления)

12. Светочувствительный модуль BH1750

13. Печатная плата, провода, припой, вилка KF301-2P с винтовым соединением, вилка и розетка для печатных плат, клей

14. Регулятор 3,3 В

15. Базовая станция:ПК или постоянно работающая плата для разработки. Его роль - сбор данных, обучение модели прогнозирования дождя и построение прогнозов

Инструменты:

1. Переходник с USB на последовательный FTDI FT232RL для программирования Arduino Pro Mini

2. IDE Arduino

3. Дрель

4. Пила с мелким полотном

5. Отвертки

6. Паяльник

7. Кусачки

Навыки:

1. Пайка, проверьте это руководство

2. Основы программирования на Arduino

3. Конфигурация службы Linux, установка пакета

4. Некоторые навыки программирования

Шаг 2. Создание метеостанции

Метеостанция состоит из следующих наборов компонентов:

1. ящик с наклеенной на него солнечной панелью

2 . печатная плата с электроникой внутри

3. батарейный отсек также внутри

4. BME280 и датчики света и дождя снаружи

1. В коробке нужно 4 отверстия, одно для проводов солнечной панели, три других для датчиков, которые будут размещены снаружи. Сначала просверлите отверстия, они должны быть достаточно большими, чтобы провода типа папа-мама выходили и доходили до датчиков. После того, как все отверстия будут просверлены, приклейте панель к одной стороне коробки и пропустите провода через отверстие внутри

2. На печатной плате будут находиться Arduino, HC-12, регулятор 3,3 В, диод, транзистор, резистор и два KF301-2P

  • сначала припаяйте два женских разъема на печатной плате для Arduino, припаяйте штекерные разъемы печатной платы к Arduino и поместите Arduino на печатную плату.
  • светодиод Arduino должен быть удален или хотя бы один из его контактов. это очень важно потому что светодиод потребляет большое количество энергии. Будьте осторожны, чтобы не повредить другие компоненты.
  • припаять транзистор, резистор и стабилизатор 3,3 В.
  • припаиваем два KF301-2P. Один будет для солнечной панели, другой - для держателя батареи.
  • припаяйте три разъема на печатной плате:для датчика освещенности, BME280 и датчика дождя.
  • припаяйте небольшие провода для соединения всех компонентов печатной платы (проверьте изображения и фриттинг schamatic)

3. поместите 3 заряженных никель-металлгидридных аккумулятора AAA внутрь держателя и поместите его в коробку, подключив провода к разъему KF301-2P

4. подключите BME280 и датчики света снаружи коробки к соответствующим штекерным разъемам

Для датчика дождя припаяйте к нему три провода (Gnd, Vcc, сигнал), а на другой стороне припаяйте штыревые контакты, которые войдут внутри коробки, к соответствующим штыревым разъемам

Последнее, что нужно сделать, это поставить станцию ​​на ее конечное положение. Я выбрал место, защищенное от дождя и снега. Я выбрал более длинные провода для датчика дождя и поместил его отдельно под дождем на устойчивой опоре. Для основного ящика я выбрал особый вид клейкой ленты (проверьте изображения), но подойдет все, что удерживает коробку.

sketch.fzz

Шаг 3. Код Arduino

На этом этапе вы узнаете, какие внешние библиотеки необходимы, мы рассмотрим код и то, как он работает, и, конечно же, вы сможете загрузить или скопировать его в Arduino IDE и загрузить на метеостанцию.

Роль метеостанции - каждые 10 минут передавать на базовую станцию ​​данные о своих датчиках.

Сначала опишем, что делает программа метеостанции:

1. считывать данные датчиков (влажность, температура, давление, дождь, свет, напряжение)

2. передает закодированные данные через вторую программную последовательную линию.

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

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

Утверждение сверху будет означать, что:влажность на станции "1" 78 процентов, температура на станции 1 12 градусов, давление 1022 бара, уровень освещенности 500 люкс, дождь 0 и напряжение 4010 милливольт

3. отключите вспомогательные компоненты:датчики и устройство связи

4. переводит Arduino в спящий режим на 10 минут (в результате он потребляет меньше 50 микроампер)

5. включите компоненты и повторите шаги 1–4

Одна небольшая дополнительная настройка:если уровень напряжения выше 4,2 В, Arduino будет использовать обычную функцию сна «задержка (миллисекунды)». Это значительно увеличит потребление энергии и быстро снизит напряжение. Это эффективно предотвращает перезарядку батарей солнечной панелью.

Вы можете получить код из моего репозитория Github здесь:https://github.com/danionescu0/home-automation/tre ...

Либо скопируйте и вставьте его снизу, в любом случае просто удалите строку с "transferSenzorData (" V ", sizes.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 sizesCode =1; / ** * уровень напряжения, при котором микроконтроллер переходит в режим глубокого сна вместо обычного сна * / int VoltageDeepSleepThreshold =4200; const byte периферийные PowerPin =6; char buffer [] ={'', '', '', '', '', '', ''}; struct sensorData {байт влажности; внутренняя температура; байтовый дождь; внутреннее давление; длительное напряжение; int light; }; sensorData сенсоры; void setup () {Serial.begin (9600); serialComm.begin (9600); pinMode (периферийные PowerPin, ВЫХОД); digitalWrite (периферийные PowerPin, HIGH); задержка (500); if (! bme.begin ()) {Serial.println («Не удалось найти действующий датчик BME280, проверьте проводку!»); в то время как (1) {customSleep (100); }} Serial.println («Инициализация успешно завершена»); задержка (50); digitalWrite (периферийные PowerPin, HIGH);} недействительный цикл () {updateSenzors (); transferData (); customSleep (75); } void updateSenzors () {bme.begin (); lightMeter.begin (); задержка (300); sensor.temperature =bme.readTemperature (); sensor.pressure =bme.readPressure () / 100.0F; sensor.humidity =bme.readHumidity (); сенсоры.light =lightMeter.readLightLevel (); sensor.voltage =readVcc (); напряжение =readVcc (); sensor.rain =readRain ();} void transferData () {emptyIncommingSerialBuffer (); Serial.print ("Температура:"); Serial.println (датчики.температуры); Serial.print («Влажность:»); Serial.println (датчики. Влажности); Serial.print («Давление:»); Serial.println (датчики. Давления); Serial.print ("Свет:"); Serial.println (датчики.света); Serial.print («Напряжение:»); Serial.println (датчики. Напряжение); Serial.print ("Дождь:"); Serial.println (датчики. Дождь); transferSenzorData («Т», датчики.температура); transferSenzorData («H», сенсоры. влажность); TransmitSenzorData («PS», сенсоры.давления); transferSenzorData («L», сенсоры.свет); transferSenzorData («В», датчики. напряжение); TransmitSenzorData ("R", sizes.rain);} void emptyIncommingSerialBuffer () {while (serialComm.available ()> 0) {serialComm.read (); задержка (5); }} void transferSenzorData (тип String, значение int) {serialComm.print (тип); serialComm.print (сенсоркод); serialComm.print (":"); serialComm.print (значение); serialComm.print ("|"); delay (50);} void customSleep (long 8SecondCycles) {если (датчики.voltage> VoltageDeepSleepThreshold) {задержка (восемьSecondCycles * 8000); возвращение; } digitalWrite (периферийные PowerPin, LOW); для (int я =0; я <восемьSecondCycles; я ++) {LowPower.powerDown (SLEEP_8S, ADC_OFF, BOD_OFF); } digitalWrite (периферийные PowerPin, HIGH); задержка (500);} байт readRain () {байтовый уровень =analogRead (rainPin); вернуть карту (уровень, 0, 1023, 0, 100); } long readVcc () {// Считываем опорное напряжение 1,1 В относительно AVcc // устанавливаем опорное значение на Vcc, а измерение - на внутреннее опорное напряжение 1,1 В, определенное #if (__ AVR_ATmega32U4__) || определено (__ AVR_ATmega1280__) || определено (__ AVR_ATmega2560__) ADMUX =_BV (REFS0) | _BV (MUX4) | _BV (MUX3) | _BV (MUX2) | _BV (MUX1); #elif defined (__AVR_ATtiny24__) || определено (__ AVR_ATtiny44__) || определено (__ AVR_ATtiny84__) ADMUX =_BV (MUX5) | _BV (MUX0); #elif defined (__AVR_ATtiny25__) || определено (__ AVR_ATtiny45__) || определено (__ AVR_ATtiny85__) ADMUX =_BV (MUX3) | _BV (MUX2); #else ADMUX =_BV (REFS0) | _BV (MUX3) | _BV (MUX2) | _BV (MUX1); #endif delay (2); // Ждем, пока Vref установится ADCSRA | =_BV (ADSC); // Запуск преобразования while (bit_is_set (ADCSRA, ADSC)); // измерение uint8_t low =ADCL; // сначала необходимо прочитать ADCL - затем он блокирует ADCH uint8_t high =ADCH; // разблокирует оба long result =(high <<8) | низкий; результат =1125300л / результат; // Вычислить Vcc (в мВ); 1125300 =1,1 * 1023 * 1000 возвращаемый результат; // Vcc в милливольтах}

Перед загрузкой кода загрузите и установите следующие библиотеки arduino:

* Библиотека BH1750:https://github.com/claws/BH1750 * Библиотека LowPower:https://github.com/rocketscream/Low-Power

* Библиотека сенсоров Adafruit:https://github.com/adafruit/Adafruit_Sensor

* Библиотека Adafruit BME280:https://github.com/adafruit/Adafruit_Sensor

Если вы не знаете, как это сделать, ознакомьтесь с этим руководством.

Шаг 4. Подготовка базовой станции

Базовая станция будет состоять из компьютера с Linux . (настольный компьютер, ноутбук или плата для разработки) с разъемом HC-12 USB модуль прилагается. Компьютер должен оставаться включенным, чтобы каждые 10 минут собирать данные со станции.

Я использовал свой ноутбук с Ubuntu 18.

Шаги установки:

1. Установите анаконду. Anaconda - это менеджер пакетов Python, который упростит нам работу с теми же зависимостями. Мы сможем контролировать версию Python и каждую версию пакета

Если вы не знаете, как его установить, посмотрите это:https://www.digitalocean.com/community/tutorials/h ... руководство и выполните шаги 1–8

2. Установите mongoDb. MongoDb будет нашей основной базой данных для этого проекта. В нем будут храниться данные обо всех временных рядах датчиков. Он прост и прост в использовании.

Инструкции по установке см. На их странице:https://docs.mongodb.com/v3.4/tutorial/install-mon ...

Я использовал старую версию mongoDb 3.4.6, если вы последуете приведенному выше руководству, вы получите именно это. В принципе, он должен работать с последней версией.

[Необязательно] добавьте указатель в поле даты:

  mongouse weather db.weather_station.createIndex ({"date":1})  

3. Загрузите проект отсюда:https://github.com/danionescu0/home-automation. Мы будем использовать папку прогнозов погоды

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

4. Создайте и настройте среду анаконды:

  cd weather-predic # создать среду anaconda с именем "weather" с помощью python 3.6.2conda create --name weather python =3.6.2 # активировать средуconda активировать погоду # установить все пакеты pip install -r requirements.txt  

Это создаст новую среду anaconda и установит необходимые пакеты. Вот некоторые из пакетов:

Keras (слой нейронной сети высокого уровня, с помощью этой библиотеки мы будем делать все наши прогнозы нейронной сети)

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

pymongo (драйвер python mongoDb)

sklearn (инструменты интеллектуального анализа и анализа данных)

Настроить проект

Файл конфигурации находится в папке прогноза погоды и называется config.py

1. если вы устанавливаете MongoDb удаленно или на другой порт, измените «хост» или «порт» в

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

2. Теперь нам нужно подключить последовательный USB-адаптер HC-12. Перед тем как запустить:

  ls -l / dev / tty *  

и вы должны получить список подключенных устройств.

Теперь вставьте HC-12 в порт USB и снова выполните ту же команду. Это должна быть одна новая запись в этом списке, наш последовательный адаптер. Теперь при необходимости измените порт адаптера в конфигурации

  serial ={'порт':'/ dev / ttyUSB0', 'скорость_бода':9600}  

Другие записи конфигурации - это пути к некоторым файлам по умолчанию, менять их не нужно.

Шаг 5. Практическое использование метеостанции

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

Если вы хотите узнать больше о том, как это работает, ознакомьтесь со следующим шагом «Как это работает»

Импорт моих уже собранных данных

MongoDb поставляется с командой cli для импорта данных из json:

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

Это позволит импортировать файл из демонстрационных данных в базу данных "погода" и коллекцию "точек данных"

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

Сбор новых данных

Одна из ролей базовой станции - хранить входящие данные от метеостанции в базе данных для последующей обработки. Чтобы запустить процесс, который прослушивает последовательный порт и сохраняет в базе данных, просто запустите:

  conda activate weatherpython serial_listener.py # каждые 10 минут вы должны видеть данные с входящей метеостанции:[Датчик:тип (температура), значение (14.3)] [Датчик:тип (давление), значение ( 1056.0)] ...  

Создание модели прогнозирования

Я предполагаю, что вы импортировали мои данные или «запускали сценарий в течение нескольких лет», чтобы собрать персонализированные данные, поэтому на этом этапе мы обработаем данные, чтобы создать модель, используемую для прогнозирования будущего дождя.

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

* Первый параметр --days_behind означает, сколько данных в прошлое должен обработать скрипт. Измеряется в днях

* --test-file-percent означает, сколько данных следует рассматривать для целей тестирования, это обычный шаг в алгоритме машинного обучения

* --hour-granularity в основном означает, на сколько часов в будущем нам понадобится прогноз

* --datapoints - этот параметр будет рассмотрен далее в следующем разделе

Просмотр графиков данных со всех датчиков метеостанции

Допустим, за последние 10 дней:

  conda активировать погодные графики python - days-behind 10  

Предскажите, пойдет ли дождь в следующий период

Мы предскажем, будет ли дождь, и отправим уведомление по электронной почте

  conda активировать погоду python pred.py --datapoints-behind 8 --hour-granularity 6 --from-addr a_gmail_address --from-password gmail_password --to-addr a_email_destination  

Выполните пакетное прогнозирование на основе тестовых данных:

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

Важно использовать те же параметры, что и в приведенном выше сценарии поезда.

Чтобы уведомление по электронной почте работало, войдите в свою учетную запись Gmail и установите для параметра Разрешить менее безопасные приложения значение ВКЛ. Имейте в виду, что это облегчает другим доступ к вашей учетной записи.

Вам понадобятся два адреса электронной почты, адрес Gmail с включенной опцией выше и другой адрес, на который вы получите уведомление.

Если вы хотите получать уведомления каждый час, поместите скрипт в crontab

Чтобы увидеть, как все это возможно, перейдите к следующему шагу

Шаг 6. Как это работает

На этом последнем шаге мы обсудим несколько аспектов архитектуры этого проекта:

1. Обзор проекта, мы обсудим общую архитектуру и задействованные технологии

2. Основные концепции машинного обучения

3. Как подготавливаются данные (самый важный шаг)

4. Как работает реальный API оболочки нейронной сети (Keras)

5. Будущие улучшения

Я попытаюсь привести здесь пример кода, но имейте в виду, что это не 100% код из проекта. В проекте это собственный код, это немного сложнее с классами и структурой

1. Обзор проекта, мы обсудим общую архитектуру и задействованные технологии

Как мы уже говорили ранее, проект состоит из двух отдельных частей. Сама метеостанция, единственная функция которой - собирать и передавать данные. И базовая станция, где будут происходить все сборы, обучение и прогнозирование.

Преимущества разделения метеостанции и базовой станции:

  • Требования к питанию:если бы метеостанция могла обрабатывать данные, ей потребовалась бы значительная мощность, возможно, большие солнечные батареи или постоянный источник питания.
  • портативность, благодаря небольшому размеру метеостанция может собирать данные с расстояния в несколько сотен метров, и вы можете легко изменить ее место, если это необходимо.
  • масштабируемость:вы можете повысить точность прогнозов, построив более одной метеостанции и разместив их на расстоянии нескольких сотен метров.
  • низкая стоимость, потому что это дешевое устройство, вы можете легко построить другое, если оно будет потеряно или украдено.

Выбор базы данных . Я выбрал mongoDb, потому что это приятные особенности:без схемы, бесплатный и простой в использовании API

Каждый раз при получении данных датчика данные сохраняются в базе данных, запись данных выглядит примерно так:

  {"_id":"04_27_2017_06_17", "влажность":65, "дата":ISODate ("2017-04-27T06:17:18Z"), "давление":1007, "температура":9, «дождь»:0, «свет»:15}  

База данных хранит данные в формате BSON (похожем на JSON), поэтому их легко читать и с ними легко работать. Я собрал данные по идентификатору, который содержит дату, отформатированную в виде строки с точностью до минут, поэтому наименьшая группировка здесь - минуты.

Метеостанция (при правильной работе) будет передавать точку данных каждые 10 минут. Точка данных - это набор значений «дата», «влажность», «давление», «температура», «дождь» и «свет».

Обработка данных и нейронная сеть выбор технологии

Я выбрал Python для бэкэнда, потому что многие важные нововведения в нейронных сетях можно найти в Python. Растущее сообщество с множеством репозиториев Github, учебными блогами и книгами здесь, чтобы помочь.

* Для обработки данных я использовал Pandas ( https://pandas.pydata.org/ ) . Pandas упрощает работу с данными. Вы можете загружать таблицы из структур данных CSV, Excel, Python и переупорядочивать их, удалять столбцы, добавлять столбцы, индексировать по столбцу и выполнять многие другие преобразования.

* Для работы с нейронными сетями я выбрал Keras (https://keras.io/). Keras - это оболочка нейронной сети высокого уровня над более низкоуровневыми API, такими как Tensorflow, и можно построить многослойную нейронную сеть с дюжиной строк кода или около того. Это большое преимущество, потому что мы можем построить что-то полезное на основе великой работы других людей. Это основная составляющая программирования, основанная на других более мелких строительных блоках.

2. Основные концепции машинного обучения

Задача этого руководства - не обучить машинному обучению, а просто обрисовать один из возможных вариантов использования и то, как мы можем практически применить его к этому варианту использования.

Нейронные сети - это структуры данных, которые напоминают клетки мозга, называемые нейронами. Наука обнаружила, что в мозгу есть особые клетки, называемые нейронами, которые общаются с другими нейронами с помощью электрических импульсов через «линии», называемые аксонами. При достаточной стимуляции (со стороны многих других нейронов) нейроны вызовут электрический импульс дальше в этой «сети», стимулируя другие нейроны. Это, конечно, чрезмерное упрощение процесса, но в основном компьютерные алгоритмы пытаются воспроизвести этот биологический процесс.

В компьютерных нейронных сетях каждый нейрон имеет «триггерную точку», где, если стимулировать через эту точку, он будет распространять стимуляцию вперед, в противном случае - нет. Для этого каждый моделируемый нейрон будет иметь смещение, а каждый аксон - вес. После случайной инициализации этих значений начинается процесс, называемый "обучением", это означает, что в цикле алгоритм будет выполнять следующие шаги:

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

Если вы хотите узнать больше об этом процессе, вы можете прочитать эту статью:https://mattmazur.com/2015/03/17/a-step-by-step-ba .... Также есть множество книг и учебные пособия.

Еще одна вещь, здесь мы будем использовать метод обучения с учителем. Это означает, что мы также обучим алгоритм входам и выходам, чтобы при новом наборе входных данных он мог предсказать выход.

3. Как подготавливаются данные (самый важный шаг)

Во многих задачах машинного обучения и нейронных сетей подготовка данных является очень важной частью, и она охватывает:

  • получить необработанные данные
  • очистка данных:это будет означать удаление потерянных значений, аберраций или других аномалий.
  • группировка данных:получение множества точек данных и преобразование в агрегированные точки данных.
  • улучшение данных:добавление других аспектов данных, полученных из собственных данных или из внешних источников.
  • разделение данных на обучающие и тестовые.
  • разделите данные поезда и тестирования на входы и выходы. Обычно проблема будет иметь много входов и несколько выходов.
  • изменить масштаб данных так, чтобы они находились между 0 и 1 (это поможет сети устранить смещения высоких / низких значений)

Получение необработанных данных

В нашем случае получить данные для MongoDb в python очень просто. Учитывая нашу коллекцию точек данных, подойдут только эти строки кода

  client =MongoClient (хост, порт) .weather.datapoints cursor =client.find ({'$ and':[{'date':{'$ gte':start_date}}, {'date' :{'$ lte':end_date}}]}) data =list (курсор) ..  

Очистка данных

Пустые значения в фрейме данных удаляются

dataframe =dataframe.dropna() 

Data grouping &data enhancing

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.

Код

  • Фрагмент кода №2
  • Фрагмент кода № 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
Фрагмент кода 2 Обычный текст
#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); задержка (500); if (!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1) { customSleep(100); } } Serial.println("Initialization finished succesfully"); задержка (50); digitalWrite(peripherialsPowerPin, HIGH);}void loop() { updateSenzors(); transmitData(); customSleep(75); }void updateSenzors() { bme.begin(); lightMeter.begin(); delay(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(); задержка (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); возвращение; } digitalWrite(peripherialsPowerPin, LOW); for (int i =0; i
Фрагмент кода № 5 Обычный текст
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

Схема

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

Производственный процесс

  1. Датчик температуры Python и Raspberry Pi
  2. Консоль редактирования DIY Photoshop с использованием Arduino Nano RP 2040
  3. Python переименовывает файл и каталог, используя os.rename()
  4. Система посещаемости с использованием Arduino и RFID с Python
  5. Универсальный пульт дистанционного управления с использованием Arduino, 1Sheeld и Android
  6. Вольтметр своими руками с использованием Arduino и смартфона
  7. Инфракрасный датчик сердцебиения своими руками с использованием Arduino
  8. Измерение частоты и рабочего цикла с использованием Arduino
  9. DIY вольтметр с Arduino и дисплеем Nokia 5110
  10. Сонар с использованием Arduino и отображение при обработке IDE