Разработка и исследование модели нейросетевого регулятора на микроконтроллере STM32F407VG
Разработка алгоритма и программы на персональном компьютере двухслойной нейросети, аналогичной программы на микроконтроллере STM32F407VG. Этапы реализации обучения нейросети и передачи весовых коэффициентов на микроконтроллер по интерфейсу связи UART.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 21.02.2016 |
Размер файла | 1,4 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://allbest.ru
- Разработка и исследование модели нейросетевого регулятора на микроконтроллере STM32F407VG
Техническое задание
Разработать и исследовать модель нейросетевого регулятора на микроконтроллере STM32F407VG.
Введение
алгоритм программа нейросеть
В данной курсовой работе необходимо разработать алгоритм и программу на ПК двухслойной нейросети, а также аналогичную программу на микроконтроллере STM32F407VG. В программе на ПК реализовано обучение нейросети и передача весовых коэффициентов на микроконтроллер по интерфейсу связи UART.
В наши дни возрастает необходимость в системах, которые способны не только выполнять однажды запрограммированную последовательность действий над заранее определенными данными, но и способны сами анализировать вновь поступающую информацию, находить в ней закономерности, производить прогнозирование и т.д. В этой области приложений самым лучшим образом зарекомендовали себя так называемые нейронные сети - самообучающиеся системы, имитирующие деятельность человеческого мозга.
Целью данной работы является разработка модели нейросети на микроконтроллере, а так же закрепление практических навыков программирования микроконтроллеров на языке С и программирования ПК на С#. Процесс подготовки предусматривает самостоятельное изучение нового материала и закрепление его с помощью практического задания.
1. Разработка алгоритма
Для дальнейшей работы необходимо построить следующие алгоритмы: алгоритм работы программы в целом, алгоритм обучения нейросети.
1.1 Математический алгоритм
1.1.1 Искусственные нейронные сети
Несмотря на большое разнообразие вариантов нейронных сетей, все они имеют общие черты. Так, все они, так же, как и мозг человека, состоят из большого числа связанных между собой однотипных элементов - нейронов, которые имитируют нейроны головного мозга. На рис. 1 показана схема нейрона.
Из рисунка видно, что искусственный нейрон, так же, как и живой, состоит из синапсов, связывающих входы нейрона с ядром; ядра нейрона, которое осуществляет обработку входных сигналов и аксона, который связывает нейрон с нейронами следующего слоя. Каждый синапс имеет вес, который определяет, насколько соответствующий вход нейрона влияет на его состояние.
Состояние нейрона определяется по формуле
(1)
где :
n - число входов нейрона
xi - значение i-го входа нейрона
wi - вес i-го синапса
Затем определяется значение аксона нейрона по формуле
Y = f(S) (2)
Где f - некоторая функция, которая называется активационной. Наиболее часто в качестве активационной функции используется сигмоид, который имеет следующий вид:
(3)
Основное достоинство этой функции в том, что она дифференцируема на всей оси абсцисс и имеет очень простую производную:
(4)
При уменьшении параметра a сигмоид, становится более пологим, вырождаясь в горизонтальную линию на уровне 0,5 при a=0. При увеличении a, сигмоид приближается к функции единичного скачка.
Список других наиболее употребляемых функций активации приведен в таблице 1.
Таблица 1- Основные функций активации.
№ |
Название |
Математическая запись |
|
1 |
Линейная |
||
2 |
Пороговая бинарная |
||
3 |
Пороговая биполярная |
||
4 |
Линейная ограниченная |
||
5 |
Гиперболический тангенс |
||
6 |
Логарифмическая |
||
7 |
Радиально-базисная |
||
8 |
Сигмоидная (y [-1,1]) |
Обучение нейронной сети
Самым важным свойством нейронных сетей является их способность обучаться на основе данных окружающей среды и в результате обучения повышать свою производительность. Обучение нейронной сети происходит посредством интерактивного процесса корректировки синаптических весов и порогов.
Существуют два концептуальных подхода к обучению нейронных сетей: обучение с учителем и обучение без учителя. В данной курсовой работе используется метод обучения с учителем.
Обучение нейронной сети с учителем предполагает, что для каждого входного вектора из обучающего множества существует требуемое значение выходного вектора, называемого целевым. Эти вектора образуют обучающую пару. Веса сети изменяют до тех пор, пока для каждого входного вектора не будет получен приемлемый уровень отклонения выходного вектора от целевого.
Алгоритм обратного распространения ошибки:
1. Инициализировать синаптические веса маленькими случайными значениями.
2. Выбрать очередную обучающую пару из обучающего множества; подать входной вектор на вход сети.
3. Вычислить выход сети.
4. Вычислить разность между выходом сети и требуемым выходом (целевым вектором обучающей пары).
5. Подкорректировать веса сети для минимизации ошибки (как см. ниже).
Повторять шаги с 2 по 5 для каждого вектора обучающего множества до тех пор, пока ошибка на всем множестве не достигнет приемлемого уровня.
Рассмотрим подробней 5 шаг - корректировка весов сети. Здесь следует выделить два нижеописанных случая.
Случай 1. Корректировка синаптических весов выходного слоя
Определимся, что индексом p будем обозначать нейрон, из которого выходит синаптический вес, а q - нейрон в который входит.
Введем величину д, которая равна разности между требуемым и реальным выходами, умноженной на производную функции активации:
(5)
Тогда, веса выходного слоя после коррекции будут равны:
(6)
где:
i - номер текущей итерации обучения;
- величина синаптического веса, соединяющего нейрон p с нейроном q;
- коэффициент «скорости обучения», позволяет управлять средней величиной изменения весов;
- выход нейрона .
Случай 2. Корректировка синаптических весов скрытого слоя.
(7)
где:
- сумма от 1 по N, N - количество нейронов выходного слоя.
Тогда, веса скрытого слоя после коррекции будут равны:
(8)
В этом алгоритме происходит распространение ошибки от выходов НС ко входам, то есть в направлении обратном распространению сигналов обычном режиме работы. Согласно методу наименьших квадратов, минимизируемой целевой функцией ошибки НС является величина:
(9)
где реальное выходное состояние нейрона выходного слоя N нейронной сети при подаче на ее входы - го образа; - желаемое (идеальное) выходное состояние этого нейрона. Суммирование происходит по всем нейронам выходного слоя и по всем обрабатываемым сетью образам.
1.2 Разработка схем алгоритмов
Для дальнейшей работы необходимо построить следующие алгоритмы: алгоритм работы программы в целом, и алгоритм обучения нейросети. Обобщенная схема алгоритма программы, распознающей 2 класса чисел с помощью искусственной нейросети на микроконтроллере, представлена на рисунке 2.
Рисунок 2 - Обобщенная схема алгоритма программы
Алгоритм обучения нейросети представлен на рисунке 3.
Рисунок 4 - Схема алгоритма обучения нейросети
2. Разработка программы
Для запуска этой программы предварительно была записана прошивка в микроконтроллер, которая разрабатывалась в среде Keyl 4. Затем соединяются выводы PC10 и РС11 микроконтроллера с выводами Rx и Tx соответственно любого преобразователя компьютерных интерфейсов в UART, на плате с соответствующими элементами. После этого подключается USB-кабель к отладочной плате, тем самым подавая питание на микроконтроллер.
Следующим шагом является запуск программы на ПК. Для этого нужно иметь установленную версию Windows XP/Vista/7. Данная программа разрабатывалась в среде MSVisualC# 2010(Microsoft .NET Framework 4.0).
2.1 Разработка программы на ПК
Для работы использовались следующие пространства имен:
System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Text;
System.Windows.Forms;
System.Threading;
System.IO;
System.IO.Ports;
Для создания программы на ПК были использованы:
class Neyro - класс работающий с нейросетью.
class Form1 : Form - класс диалогового окна, наследуемый от стандартного класса Form.
public int[] Vihod(int kol, int kl) - метод, формирующий целевой вектор.
public void Korekt() - метод, коректирующий синапсы.
public void Rez() - метод вычисления результата нейросети.
public void CreateNS() - метод, создающий нейросеть.
public void Obuchenie(string file, StreamWriter sw1) - метод, обучающий нейросеть определенному классу чисел.
private void grafic() - метод, рисующий график.
Текст программы представлен в приложении А.
2.2 Разработка программы на микроконтроллер
Для создания программы на микроконтроллере STM32F407VG были использованы:
Функции:
void delay(int n) - функция задержки.
void InitUart4(void) - инициализация UART.
void InitPorts() - инициализация портов.
void InitNeyro() - инициализация и создание модели нейросети.
void CreateNeyro(Neyro* nr) - функция заполнения матриц весовых коэффициентов малыми случайными значениями.
void Res(Neyro* nr) - функция расчета выходных значений нейросети.
void Write_koef(Neyro* nr, const double *buf) - функция записи весовых коэффициентов в матрицы принятых с ПК.
void Write_vvod(Neyro* nr, const double *buf) - функция формирования входных значений нейросети принятых данных с ПК.
void Klass(Neyro* nr) - функция определения класса чисел по выходным значениям нейросети.
Прерывания:
void UART4_IRQHandler() - перывание по приему данных через UART интерфейс.
void SysTick_Handler() - прерывание по переполнению таймера SysTick.
Текст программы представлен в приложении Б.
3. Вычислительный эксперимент
3.1 Программа разработанная на языке С#
При запуске вызываем Windows окно. Ознакомившись, вводим данные с клавиатуры, требуемые программой. Вычислительный эксперимент представлен на рисунке 5.
Рисунок 5 - Результат работы программы, представленный в Windows окне
При неправильном использовании возникают ошибки, представленные на рисунках 6, 7.
Рисунок 6 - Ошибки при вводе данных
Рисунок 7 - Ошибки при вводе данных
3.2 Программа, разработанная на микроконтроллер
На микроконтроллер, с заранее установленной прошивкой, требуется только лишь подать питание, подключив USB-кабель к отладочной плате, и наблюдать за результатом, так как основное управление происходит с ПК.
Вычислительный эксперимент представлен на рисунках 8, 9.
Рисунок 8 - Результат вычислительного эксперимента.
Рисунок 9 - Результат вычислительного эксперимента.
4. Руководство программиста
4.1 Назначение и условия применения программы
Программа предназначена для распознавания двух классов чисел.
Для запуска этой программы необходимо иметь на компьютере установленную версию Windows XP/Vista/7. Данная программа разрабатывалась в среде MSVisualC# 2010(Microsoft .NET Framework 4.0).
4.2 Характеристика программы
4.2.1 Программа для ПК
Для написания программы нам понадобились следующие команды:
Получение числовых значений из текстовых полей:
neyr1 = Convert.ToInt32(textBox1.Text); (cм. Приложение А)
Вывод окошка:
MessageBox.Show("Введите количество нейронов первого слоя");
(cм. Приложение А)
Чтение содержимого файла:
text = File.ReadAllLines("1-1.txt"); (cм. Приложение А)
Сброс текстбокса:
textBox1.Clear(); (cм. Приложение А)
В данной программе был создан класс - class Neyro, с помощью которого создается нейросеть, и затем ведется работа с ней.
Класс содержит следующие переменные:
public double[] prom, vvod;
public double[,] w1, w2;
public double[] rez;
public int count1=0, count2=0;
public int neyr1, neyr2;
public int[] ogid;
public bool[] ogid1, ogid2;
public double k, skor;
public double[] err_m = new double[100]; (cм. Приложение А)
Значениям переменных neyr1, neyr2 присваивается значение количества нейронов в первом и втором слоях нейросети соответственно.
Массив vvod заполняется из файла с входными данными. Далее вычисляются значения массивов prom и rez. Массив prom - это результаты выходов нейронов первого слоя. А массив rez - результаты выходов нейросети.
Также в классе используются методы:
public int[] Vihod(int kol, int kl) - метод, формирующий целевой вектор.
public void Korekt() - метод, коректирующий синапсы.
public void Rez() - метод вычисления результата нейросети.
public void CreateNS() - метод, создающий нейросеть.
public void Obuchenie(string file, StreamWriter sw1) - метод, обучающий нейросеть определенному классу чисел.
Для установки соединения по интерфейсу RS-232 использовался класс SerialPort и в частности следующие методы:
Open() - установление соединения.
Close() - завершение соединения.
ReadLine() - чтение данных, пришедших по интерфейсу RS-232.
WriteLine(string ) - отправка данных по интерфейсу RS-232.
Текст программы класса представлен в Приложении А.
Правильность работы класса и программы в целом подтверждена вычислительным экспериментом. (см. рисунки 5-9).
4.2.2 Программа для микроконтроллера
Программа для микроконтроллера написана на языке С. В этом языке программирования нет классов, поэтому для создания модели нейросети использовалась структура:
typedef struct
{
double vvod[Amount_Vvod];
double prom[Neyr1];
double rez[Neyr2];
double w1[Amount_Vvod][Neyr1];
double w2[Neyr1][Neyr2];
double k;
int ogid1[Neyr2];
int ogid2[Neyr2];
}Neyro;
vvod - массив входных значений нейросети.
prom - массив выходных значений первого слоя нейросети.
rez - массив выходных значений нейросети.
w1 - матрица весовых коэффициентов первого слоя.
w2 - матрица весовых коэффициентов второго слоя.
k - коэффициент активационной функции (сигмоид).
ogid1 - массив значений, ожидаемых на выходе, при подаче на вход чисел первого класса.
ogid2 - массив значений, ожидаемых на выходе, при подаче на вход чисел второго класса.
4.3 Обращение к программе
Для запуска программы необходимо открыть в папке «курсовой ЭВМиВС» файл «курсовой ЭВМиВС.sln» с помощью MS Visual Studio С# 2010 и нажать кнопку «Начать отладку». В результате должно появиться окно программы.
4.4 Входные и выходные данные
В предыдущей работе были подобраны оптимальные значения коэффициентов нейросети:
Количество шагов обучения - 100;
Коэффициент скорости обучения - 0,7;
Коэффициент сигмоида - 1,3;
Эффективность работы нейросети с этими параметрами так же была проверена при работе с другими классами чисел. Поэтому для данной нейросети лучше использовать именно эти значения.
В пункты: «Количество нейронов», нужно вводить целые значения. Значения коэффицентов k (коэффицент сигмоидной функции) и skor (скорость обучения) могут быть дробными.
В пункте «Обучающая выборка» нужно выбрать файлы для обучения нейросети соответствующим классам. В пунктах «Файл» выбираются файлы для экзаменационной и тестовой выборки.
В файлах экзаменационной выборки представлены 20 выборок соответствующего класса. После нажатия кнопки «Старт» будет выведен процент распознавания чисел данного класса. Если он низок и не удовлетворяет условиям, то следует вернуться к шагу обучения. Далее можно переходить к тестированию программы.
5. Руководство пользователя
Программа предназначена для распознавания двух классов чисел.
Для запуска программы необходимо открыть в папке «курсовой ИТПЗ 2010» файл «курсовой титп2.sln» с помощью MS Visual Studio С# 2010 и нажать кнопку «Начать отладку». В результате должно появиться окно программы.
После появления рабочего окна (рисунок 9) можно поступать к работе.
Рисунок 9 - Окно для ввода данных
В пункты: «Количество нейронов», нужно вводить целые значения. Модель нейросети на ПК может иметь любое количество нейронов как первого, так и второго слоя. Но так как в программе микроконтроллера нейросеть имеет 4 нейрона на первом слое и 2 на втором, следует вводить именно эти значения.
Значения коэффицентов k (коэффицент сигмоиды) и skor (скорость обучения) могут быть дробными.
После ввода этих значений нужно нажать кнопку «Создать сеть».
Далее в пункте «Обучающая выборка» нужно выбрать файлы для обучения нейросети и нажать на кнопку «Обучить».
После того как сеть будет обучена, появится график функции ошибки нейросети зависящий от шага обучения, а так же таблица значений ошибок при каждом шаге.
Затем следует проверить нейросеть на правильность распознавания образов. В пункте «Экзаменационная выборка» выбираются файлы первого или второго класса, в которых содержатся по 20 выборок. После нажатия кнопки «Старт» в строке «Процент» появится процент распознавания нейросетью образов выбранного класса. Если процент распознавания низкий, то следует вернуться к обучению нейросети. Если же процент удовлетворяет требованиям, то следует передать значения весовых коэффициентов на микроконтроллер. Для этого следует выбрать доступный COM-порт в выпадающем меню PortName и нажать кнопку Connect. После удачного соединения нужно нажать кнопку «Отправить коэффициенты» и дождаться полной отправки. Во время приема весовых коэффициентов на отладочной плате микроконтроллера синий светодиод будет загораться с частотой 5 Гц (в режиме ожидания - 1 Гц).
Тестовая выборка служит для того, чтобы самому убедиться в правильности работы программы. В тестовых файлах представлена одна выборка определенного класса чисел. После выбора файла можно проверить работу программы как на ПК, нажав кнопку «Результат», так и на микроконтроллере, передав числа, находящиеся в файле по RS-232. Для этого следует установить соединение с COM-портом, если это не сделано ранее, и нажать кнопку «Send to MC». Во время приема чисел, так же как и во время приема весовых коэффициентов, синий светодиод отладочной платы будет загораться с частотой 5 Гц. После обработки результатов загорается либо зеленый, либо красный светодиод. Зеленый - если удалось распознать первый класс чисел, красный - если второй. При неудачном распознавании оба светодиода будут выключены.
Заключение
Разработанная программа соответствует заданным на этапе проектирования требованиям. Во время работы над программой были улучшены навыки программирования на языке С#, а также навыки программирования микроконтроллеров. Была исследована модель нейросети созданная на микроконтроллере, которая показала хорошие результаты.
В качестве перспектив развития данной темы можно отметить такие нереализованные возможности как обучение непосредственно на микроконтроллере, подключение датчиков для формирования входных значений и непосредственное применение в какой-либо области робототехники.
Список литературы
1. Павловская Т.А. C#. Программирование на языке высокого уровня. СПб. : Питер, 2010.
2. Фролов А. В., Фролов Г. В. Язык С#. Самоучитель. М: ДИАЛОГ-МИФИ, 2009.- 560с.
3. STM32F405xx, STM32F407xx, STM32F415xx and STM32F417xx advanced ARM-based 32-bit MCUs - Datasheet.
4. ГОСТ 2.105-95 Единая система конструкторской документации. Общие требования к текстовым документам.
5. ГОСТ 19.504-79 (СТ СЭВ 2095-80). Руководство программиста. Требования к содержанию и оформлению.
6. ГОСТ 19.701-90 (ИСО 5807-85). ЕСПД. Схемы алгоритмов, программ, данных и систем.
Приложение
Текст программы на ПК.
Текст программы файла Form1.cs представлен на рисунке А.1.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.IO.Ports;
namespace курсовой_титп_2
{
public partial class Form1 : Form
{
public double[] x1, x2, r;
Random number = new Random();
Neyro nr;
public bool flag = false; //флаг создания нейросети
public bool fl_pot = false; //флаг работы потоков
public Thread pp;
public Thread pp1;
public DateTime dd;
public int mx = 5, my = 100; //Масштаб
public System.Drawing.Graphics graphicsObj;
public Pen myPen1 = new Pen(System.Drawing.Color.Red, 1);
public Pen myPen2 = new Pen(System.Drawing.Color.Black, 1);
public static SerialPort sp = new SerialPort(); // com port
public bool flag_connect = false; //флаг соединения по ком порту
public Thread readThread; //поток чтения ком портаъ
public Form1()
{
this.x1 = new double[200]; //числа первого класса
this.x2 = new double[200]; //числа второго класса
this.r = new double[6]; //рандомные числа
double sum_r = 0;
for(int i=0; i<200;i++)
{
for (int j = 0; j < 6; j++)
{
r[j] = number.NextDouble();
sum_r += r[j];
}
x1[i] = (sum_r - 3) / Math.Sqrt(0.5);
x1[i] = Math.Round(x1[i],3)+2.5;
x2[i] = x1[i] + 7.5;
sum_r = 0;
}
InitializeComponent();
//обновление списка доступных ком портов
comboBox2.Items.AddRange(SerialPort.GetPortNames());
//установка первого доступного ком порта в список
if (SerialPort.GetPortNames().Length != 0)
{
comboBox2.Text = SerialPort.GetPortNames()[0];
}
//int aaa = sizeof(double);
}
// ///////////////////////////////////////////
// кнопка создать сеть
private void button1_Click(object sender, EventArgs e)
{
int neyr1, neyr2;
double k, skor;
flag = true;
if (textBox1.TextLength != 0)
{
neyr1 = Convert.ToInt32(textBox1.Text); //количество нейронов первого слоя
}
else
{
MessageBox.Show("Введите количество нейронов первого слоя");
return;
}
if (textBox2.TextLength != 0)
{
neyr2 = Convert.ToInt32(textBox2.Text); //количество нейронов второго слоя
}
else
{
MessageBox.Show("Введите количество нейронов второго слоя");
return;
}
if (textBox9.TextLength != 0)
{
k = Convert.ToDouble(textBox9.Text); //коэффицент сигмоида k
}
else
{
MessageBox.Show("Введите k");
return;
}
if (textBox11.TextLength != 0)
{
skor = Convert.ToDouble(textBox9.Text); //коэффицент скорости обучения
}
else
{
MessageBox.Show("Введите skor");
return;
}
nr = new Neyro(neyr1, neyr2, k, skor); //вызываем конструктор класса
nr.CreateNS();
//выводим резульат нейросети
textBox3.Clear();
for(int i=0; i<neyr2;i++)
{
textBox3.AppendText(Convert.ToString(Math.Round(nr.rez[i],3)) +" ");
}
}
////////////////////////////////////////////////////////////
//кнопка сброс
private void button2_Click(object sender, EventArgs e)
{
textBox1.Clear();
textBox2.Clear();
textBox3.Clear();
textBox4.Clear();
textBox6.Clear();
textBox7.Clear();
comboBox1.Text = "";
comboBox2.Text = "";
comboBox3.Text = "";
comboBox4.Text = "";
}
// //////////////////////////////////////
// кнопка обучить 1 класс
private void button3_Click(object sender, EventArgs e)
{
string file;
//int kl = 1;
string file_osibka = "oshibka.txt";
if (flag == false)
{
MessageBox.Show("Создайте сеть");
return;
}
if (comboBox1.Text != "")
{
file = comboBox1.Text; //выбранный файл для обучения первого класса
}
else
{
MessageBox.Show("Выберите файл");
return;
}
//создаем файл для вывода ошибки
FileStream fo = new FileStream(file_osibka, FileMode.Create, FileAccess.Write, FileShare.Write);
fo.Close();
StreamWriter sw1 = new StreamWriter(file_osibka, true, Encoding.Unicode);
nr.Obuchenie(file,sw1);
///////////////////////////////////////////////
//выводим результат
textBox3.Clear();
for (int i = 0; i < nr.neyr2; i++)
{
textBox3.AppendText(Convert.ToString(Math.Round(nr.rez[i],3)) + " ");
}
sw1.Close();
grafic();
}
// ////////////////////////////////////////////////
//кнопка результат
private void button4_Click(object sender, EventArgs e)
{
double err = 0;
string file;
bool[] znach = new bool[nr.neyr2];
int kl=0;
if (flag == false)
{
MessageBox.Show("Создайте сеть");
return;
}
for (int i = 0; i < nr.neyr2; i++)
{
znach[i] = false;
}
if (comboBox3.Text != "")
{
file = comboBox3.Text;
}
else
{
MessageBox.Show("Выберите файл тестовой выборки");
return;
}
Рисунок А.1 - Продолжение.
Продолжение приложения А
string[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text
for (int i = 0; i < 10; i++)
{
nr.vvod[i] = Convert.ToDouble(text[i])/10;
}
//пересчитываем результат
nr.Rez();
for (int i = 0; i < nr.neyr2; i++)
{
if (nr.rez[i] < 0.5)
znach[i] = false;
if (nr.rez[i] > 0.5)
znach[i] = true;
}
for (int i = 0; i < nr.neyr2; i++)
{
if (znach[i] == nr.ogid1[i])
{}
else goto m;
}
kl = 1;
m:
for (int i = 0; i < nr.neyr2; i++)
{
if (znach[i] == nr.ogid2[i])
{}
else goto m1;
}
kl = 2;
m1:
textBox3.Clear();
for (int i = 0; i < nr.neyr2; i++)
{
textBox3.AppendText(Convert.ToString(Math.Round(nr.rez[i],3)) + " ");
}
for (int i = 0; i < nr.neyr2; i++)
{
err = err + (nr.rez[i] - nr.ogid[i]) * (nr.rez[i] - nr.ogid[i]);
}
err = err / 2;
textBox7.Clear();
textBox7.AppendText(Convert.ToString(Math.Round(err,3)));
if (kl == 0)
{
MessageBox.Show("Класс не определен");
}
if (kl == 1)
{
MessageBox.Show("Выборка относится к первому классу");
}
Рисунок А.1 - Продолжение.
Продолжение приложения А
if (kl == 2)
{
MessageBox.Show("Выборка относится ко второму классу");
}
}
// ////////////////////////////////////////////////////////
// Кнопка Старт для экзамена
private void button7_Click(object sender, EventArgs e)
{
string file;
bool[] znach = new bool[nr.neyr2];
int kl = 0;
int kl_opr = 0;
double procent = 0;
double kol = 0;
if (flag == false)
{
MessageBox.Show("Создайте сеть");
return;
}
for (int i = 0; i < nr.neyr2; i++)
{
znach[i] = false;
}
if (comboBox4.Text != "")
{
file = comboBox4.Text;
}
else
{
MessageBox.Show("Выберите файл экзаменационной выборки");
return;
}
if (file[0] == '1' || file[0] == '4')
{
kl = 1;
}
if (file[0] == '2' || file[0] == '3')
{
kl = 2;
}
string[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text
double[,] chisla = new double[text.Length / 10, 10];
//вносим в матрицу chisla данные из файла
for (int i = 0; i < text.Length / 10; i++)
for (int j = 0; j < 10; j++)
{
chisla[i, j] = Convert.ToDouble(text[10 * i + j]);
}
for (int qq = 0; qq < (text.Length / 10); qq++)
{
//вносим в массив vvod данные из файла
for (int i = 0; i < 10; i++)
{
nr.vvod[i] = chisla[qq, i]/10;
}
//пересчитываем результат
nr.Rez();
for (int i = 0; i < nr.neyr2; i++)
{
if (nr.rez[i] < 0.5)
znach[i] = false;
if (nr.rez[i] > 0.5)
znach[i] = true;
}
for (int i = 0; i < nr.neyr2; i++)
{
if (znach[i] == nr.ogid1[i])
{ }
else goto m;
}
kl_opr = 1;
m:
for (int i = 0; i < nr.neyr2; i++)
{
if (znach[i] == nr.ogid2[i])
{ }
else goto m1;
}
kl_opr = 2;
m1: ;
if (kl == kl_opr)
{
kol++;
}
procent = kol / 20;
procent = procent * 100;
textBox4.Clear();
textBox4.AppendText(Convert.ToString(procent));
}
}
////////////////////////////////////////
//кнопка выход
private void button8_Click(object sender, EventArgs e)
{
if (fl_pot)
{
pp1.Abort();
pp.Abort();
}
if (sp.IsOpen)
{
flag_connect = false;
Рисунок А.1 - Продолжение.
Продолжение приложения А
readThread.Join();
sp.Close();
}
Application.Exit();
}
/////////////////////////////////////////////////////
//кнопка для вывода ошибок
// ///////////////////////////////////////////////////
private void button9_Click(object sender, EventArgs e)
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
pp = new Thread(pot);
pp1=new Thread(pot1);
fl_pot = true;
pp.Start();
pp1.Start();
}
// ///////////////////////////////
public void pot()
{
int neyr1 = 15, neyr2 = 4;
string[] file_osibka = new string[2000];
double k, skor=0.7;
for (int i = 0; i < 2000; i++)
{
file_osibka[i] = "err/err" + Convert.ToString(i) + ".txt";
}
//создаем файл для вывода ошибки
int ii = 0;
FileStream fo = new FileStream(file_osibka[ii], FileMode.Create, FileAccess.Write, FileShare.Write);
fo.Close();
StreamWriter sw1 = new StreamWriter(file_osibka[ii], true, Encoding.Unicode);
//for (skor = 0.1; skor < 3; skor+=0.1)
//{
for (k = 0.1; k < 5; k+=0.1)
{
nr = new Neyro(neyr1, neyr2, k,skor);
textBox5.Clear();
textBox5.AppendText("k=" + Convert.ToString(k) + ";skor=" + Convert.ToString(skor));
//создаем сеть
nr.CreateNS();
//обучение
nr.Obuchenie("1-100.txt", sw1);
//sw1.Close();
//ii++;
grafic();
}
//}
sw1.Close();
//sw1.WriteLine();
//sw1.WriteLine("Время - " + dd.ToLongTimeString());
//sw1.Close();
fl_pot = false;
textBox5.Text = "Все";
MessageBox.Show("Поток завершен", "Все", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
public void pot1()
{
dd = new DateTime(1, 1, 1, 0, 0, 0);
//time = 0;
while (fl_pot)
{
textBox8.Clear();
textBox8.AppendText(dd.ToLongTimeString());
Thread.Sleep(1000);
dd = dd.AddSeconds(1);
}
}
// /////////////////////////////////////////////////
// Функция рисующая график
// ///////////////////////////////
private void grafic()
{
int i = 0;
graphicsObj = this.CreateGraphics();
graphicsObj.Clear(System.Drawing.SystemColors.Control);
textBox10.Clear();
graphicsObj.DrawLine(myPen2, 480, 250, 1000, 250);
graphicsObj.DrawLine(myPen2, 500, 30, 500, 270);
for (int xx = 1; xx < 20; xx++)
{
delenie(xx, xx, 0.2, -0.2, (mx*5));
}
for (double yy = -2; yy <= 0; yy++)
{
delenie(0.05, -0.05, yy, yy, my);
}
for (i = 0; i < 99; i++)
{
graphicsObj.DrawLine(myPen1, m_x(i), m_y(nr.err_m[i]), m_x((i) + 1), m_y(nr.err_m[i + 1]));
textBox10.AppendText(Convert.ToString(i) + " " + Convert.ToString(Math.Round(nr.err_m[i],5)));
textBox10.AppendText("\r\n");
Рисунок А.1 - Продолжение.
Продолжение приложения А
}
textBox10.AppendText(Convert.ToString(99) + " " + Convert.ToString(Math.Round(nr.err_m[99], 5)));
}
private float m_x(double a)
{
float b;
b = Convert.ToInt32(a * mx + 500);
return b;
}
private float m_y(double a)
{
float b;
b = Convert.ToInt32(a * (-1) * my + 250);
return b;
}
private void delenie(double x1, double x2, double y1, double y2, int m)
{
x1 = x1 * m + 500;
x2 = x2 * m + 500;
y1 = y1 * m + 250;
y2 = y2 * m + 250;
graphicsObj.DrawLine(myPen2, Convert.ToInt32(x1), Convert.ToInt32(y1), Convert.ToInt32(x2), Convert.ToInt32(y2));
}
//////////////////////////////////////////////////////////////////
// Кнопка соединения через ком порт Connect/Disconnect
//////////////////////////////////////////////////////////////////
private void button10_Click(object sender, EventArgs e)
{
if (!flag_connect)
{
sp.PortName = comboBox2.Text;
sp.BaudRate = 9600;
sp.Parity = Parity.None;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
// Set the read/write timeouts
sp.ReadTimeout = 500;
sp.WriteTimeout = 500;
sp.Open();
label19.Text = sp.PortName;
textBox12.Clear();
button10.Text = "Disconnect";
flag_connect = true;
readThread = new Thread(Read);
readThread.Start();
return;
}
if (flag_connect)
{
flag_connect = false;
Рисунок А.1 - Продолжение.
Продолжение приложения А
readThread.Join();
sp.Close();
label19.Text = "--";
button10.Text = "Connect";
return;
}
}
//////////////////////////////////////////////////////////////////
// Поток для чтения
//////////////////////////////////////////////////////////////////
public void Read()
{
while (flag_connect)
{
try
{
string message = sp.ReadLine();
textBox12.AppendText(message);
}
catch (TimeoutException) { }
}
}
//////////////////////////////////////////////////////////////////
// Кнопка Refresh
//////////////////////////////////////////////////////////////////
private void button11_Click(object sender, EventArgs e)
{
comboBox2.Items.Clear();
comboBox2.Items.AddRange(SerialPort.GetPortNames());
}
//////////////////////////////////////////////////////////////////
// Кнопка Передать коэффициенты
//////////////////////////////////////////////////////////////////
private void button6_Click(object sender, EventArgs e)
{
int count_ves_k = 0; //кол-во весовых коэффициентов
if (flag == false)
{
MessageBox.Show("Создайте сеть");
return;
}
count_ves_k = 10 * nr.neyr1 + nr.neyr1 * nr.neyr2;
string[] mas = new string[count_ves_k];
int i = 0;
//Заполнение массива из матрицы w1
for (int q = 0; q < 10; q++)
{
for (int p = 0; p < nr.neyr1; p++)
{
mas[i] = Convert.ToString(Math.Round(nr.w1[q, p],10));
i++;
Рисунок А.1 - Продолжение.
Продолжение приложения А
}
}
//Заполнение массива из матрицы w2
for (int q = 0; q < nr.neyr1; q++)
{
for (int p = 0; p < nr.neyr2; p++)
{
mas[i] = Convert.ToString(Math.Round(nr.w2[q, p], 10));
i++;
}
}
if (sp.IsOpen)
{
sp.WriteLine("w"); //для передачи коэффициентов
for (i = 0; i < count_ves_k; i++)
{
sp.WriteLine(mas[i]);
Thread.Sleep(100);
}
}
else
{
textBox12.Text = "Порт не подключен";
}
}
//////////////////////////////////////////////////////////////////
// Событие при закрытии формы
//////////////////////////////////////////////////////////////////
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (flag_connect)
{
flag_connect = false;
readThread.Join();
sp.Close();
}
}
//////////////////////////////////////////////////////////////////
// Кнопка Sendto MC
//////////////////////////////////////////////////////////////////
private void button12_Click(object sender, EventArgs e)
{
string file;
if (flag == false)
{
MessageBox.Show("Создайте сеть");
return;
}
if (comboBox3.Text != "")
{
file = comboBox3.Text;
}
else
{
MessageBox.Show("Выберите файл тестовой выборки");
return;
}
string[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text
if (sp.IsOpen)
{
sp.WriteLine("c"); //для передачи чисел
for (int i = 0; i < 10; i++)
{
sp.WriteLine(text[i]);
Thread.Sleep(100);
}
}
else
{
textBox12.Text = "Порт не подключен";
}
}
}
//////////////////////////////////////////////////////////////////
// Класс, который работает с нейросетью
//////////////////////////////////////////////////////////////////
public class Neyro : Form1
{
public double[] prom, vvod;
public double[,] w1, w2;
public double[] rez;
public int count1=0, count2=0;
public int neyr1, neyr2;
public int[] ogid;
public bool[] ogid1, ogid2;
public double k, skor;
public double[] err_m = new double[100];
//конструктор. при создании объекта класса задаем параметры матриц
public Neyro(int neyr1, int neyr2, double k, double skor)
{
this.neyr1 = neyr1;
this.neyr2 = neyr2;
this.k = k;
this.skor = skor;
this.ogid = new int[neyr2];
this.ogid1 = new bool[neyr2];
this.ogid2 = new bool[neyr2];
this.w1 = new double[10, neyr1];
this.w2 = new double[neyr1, neyr2];
this.prom = new double[neyr1];
this.vvod = new double[10];
this.rez = new double[neyr2];
Random number = new Random();
//Заполнение матрицы весовых коэффицентов w1
for (int q = 0; q < 10; q++)
{
for (int p = 0; p < neyr1; p++)
{
w1[q, p] = number.NextDouble()-0.5;
}
}
//Заполнение матрицы весовых коэффицентов w2
for (int q = 0; q < neyr1; q++)
{
for (int p = 0; p < neyr2; p++)
{
w2[q, p] = number.NextDouble()-0.5;
}
}
ogid1[0] = false;
for (int i = 1; i < neyr2; i++)
{
if (ogid1[i - 1] == false)
ogid1[i] = true;
else ogid1[i] = false;
}
ogid2[0] = true;
for (int i = 1; i < neyr2; i++)
{
if (ogid2[i - 1] == false)
ogid2[i] = true;
else ogid2[i] = false;
}
}
//код, который будет выполняться в потоке
public void Potok1(object _Data)
{
double sum1 = 0;
for (int n = 0; n < (neyr1 / 2); n++)
{
for (int i = 0; i < 10; i++)
{
sum1 = sum1 + (vvod[i] * w1[i, n]);
}
prom[n] = Math.Round(1 / (1 + Math.Exp((-sum1)*k)), 3);
sum1 = 0;
}
count1++;
}
public void Potok2(object _Data)
{
double sum2 = 0;
for (int n = (neyr1 / 2); n < neyr1; n++)
{
for (int i = 0; i < 10; i++)
{
sum2 = sum2 + (vvod[i] * w1[i, n]);
}
prom[n] = 1 / (1 + Math.Exp((-sum2)*k));
sum2 = 0;
}
count1++;
}
public void Potok3(object _Data)
{
double sum1 = 0;
for (int n = 0; n < (neyr2 / 2); n++)
{
for (int i = 0; i < neyr1; i++)
{
sum1 = sum1 + (prom[i] * w2[i, n]);
}
rez[n] = 1 / (1 + Math.Exp((-sum1)*k));
sum1 = 0;
}
count2++;
}
public void Potok4(object _Data)
{
double sum2 = 0;
for (int n = (neyr2 / 2); n < neyr2; n++)
{
for (int i = 0; i < neyr1; i++)
{
sum2 = sum2 + (prom[i] * w2[i, n]);
}
rez[n] = 1 / (1 + Math.Exp((-sum2)*k));
sum2 = 0;
}
count2++;
}
public int[] Vihod(int kol, int kl) //функция формирует ожидаемые значения
{
int a=0;
if (kl == 2 || kl==3)
a = 1;
int[]mas=new int[kol];
for (int i = 0; i < kol; i++)
{
mas[i] = a;
if (a == 0)
a = 1;
else a = 0;
}
return mas;
public void Korekt() //коректировка весов матриц
{
double[] beta2 = new double[neyr2];
double[] beta1 = new double[neyr1];
//double skor = 0.5;
double summa = 0;
//ощибка выходного слоя
for (int q = 0; q < neyr2; q++)
{
beta2[q] = (ogid[q] - rez[q]) * (1 - rez[q]) * rez[q];
}
//коректировка весов матрицы w2
for (int p = 0; p < neyr1; p++)
{
for (int q = 0; q < neyr2; q++)
{
w2[p, q] = (w2[p, q] + skor * beta2[q] * prom[p]);
if (w2[p, q] == 0)
{
w2[p, q] = 0.1;
}
}
}
//ошибка промежуточного слоя
summa = 0;
for (int q = 0; q < neyr1; q++)
{
for (int k = 0; k < neyr2; k++)
{
summa = summa + beta2[k] * w2[q, k];
}
beta1[q] = (1 - prom[q]) * prom[q] * summa;
summa = 0;
}
//коректировка весов матрицы w1
for (int p = 0; p < 10; p++)
{
for (int q = 0; q < neyr1; q++)
{
w1[p, q] = (w1[p, q] + skor * beta1[q] * vvod[p]);
if (w1[p, q] == 0)
{
w1[p, q] = 0.1;
}
}
}
}
public void Rez()
{
//пересчитываем результат
Thread th_11 = new Thread(Potok1);
Thread th_22 = new Thread(Potok2);
th_11.Start("11");
th_22.Start("22");
while (count1 != 2) { }
count1 = 0;
Thread th_33 = new Thread(Potok3);
Thread th_44 = new Thread(Potok4);
th_33.Start("33");
th_44.Start("44");
while (count2 != 2) { }
count2 = 0;
}
public void CreateNS()
{
string[] text = File.ReadAllLines("1-1.txt"); //читаем содержимое файла в переменную text
for (int i = 0; i < 10; i++)
{
vvod[i] = Convert.ToDouble(text[i])/10; //создаем массив входных значений
}
//считаем результат
Rez();
}
public void Obuchenie(string file, StreamWriter sw1)
{
double err = 0;
int klass = 0;
int ee = 0;
string[] text = File.ReadAllLines(file); //читаем содержимое файла в переменную text
for (int qq = 0; qq < 1100; )
{
klass = Convert.ToInt32(text[qq]);
qq++;
ogid = Vihod(neyr2, klass); //создаем функцию которая должна получится
for (int i = 0; i < 10; i++)
{
vvod[i] = Convert.ToDouble(text[qq])/10;
qq++;
}
Rez(); //пересчитываем результат
Korekt(); //коректируем веса
Rez(); //еще раз пересчитываем результат
//считаем ошибку
err = 0;
for (int i = 0; i < neyr2; i++)
{
err = err + (rez[i] - ogid[i]) * (rez[i] - ogid[i]);
}
err = err / 2;
err_m[ee] = err; //записываем все ошибки в массив
ee++;
//выводим ошибку
textBox7.Clear();
textBox7.AppendText(Convert.ToString(Math.Round(err, 5)));
//выводим ошибку в файл
sw1.Write(Convert.ToString(Math.Round(err, 5)) + " ");
}
sw1.WriteLine();
}
}
}
Рисунок А.1 - Текст программы файла Form1.cs.
Текст программы на микроконтоллер.
Текст программы файла Neyro.h представлен на рисунке Б.1.
#include "stm32f4xx.h"
#define Amount_Vvod 10 //количество входных значений
#define Neyr1 4 //количество нейронов первого слоя
#define Neyr2 2 //количество нейронов второго слоя
typedef struct
{
double vvod[Amount_Vvod]; //массив входных значений
double prom[Neyr1]; //массив выходов первого слоя
double rez[Neyr2];//массив выходов второго слоя
double w1[Amount_Vvod][Neyr1];//веса нейронов первого слоя
double w2[Neyr1][Neyr2];//веса нейронов второго слоя
double k;//коэфициент сигмоиды
double skor;//коэффициент скорости обучения
int ogid1[Neyr2];//функция ожидания для 1 класса
int ogid2[Neyr2];//функция ожидания для 2 класса
}Neyro;
void Res(Neyro* nr);
void CreateNeyro(Neyro* nr);
Рисунок Б.1 - Текст программы файла Neyro.h.
Текст программы файла Neyro.с представлен на рисунке Б.2.
#include "Neyro.h"
#include <stdlib.h>
#include <math.h>
#include <time.h>
void CreateNeyro(Neyro* nr)
{
char i=0, j=0;
//srand(time(NULL));
//Заполнение матрицы весовых коэффициентов w1
for (i = 0; i < Amount_Vvod; i++)
{
for (j = 0; j < Neyr1; j++)
{
nr->w1[i][j] = (double)(rand()%3)-0.5;
}
}
//Заполнение матрицы весовых коэффициентов w2
for (i = 0; i < Neyr1; i++)
{
for (j = 0; j < Neyr2; j++)
{
nr->w2[i][j] = (double)(rand()%3)-0.5;
}
}
nr->ogid1[0] = 0;
for (i = 1; i < Neyr2; i++)
{
if (nr->ogid1[i - 1] == 0)
nr->ogid1[i] = 1;
else nr->ogid1[i] = 0;
}
nr->ogid2[0] = 1;
for (i = 1; i < Neyr2; i++)
{
if (nr->ogid2[i - 1] == 0)
nr->ogid2[i] = 1;
else nr->ogid2[i] = 0;
}
}
void Res(Neyro* nr)
{
double sum = 0;
char n=0,i=0;
for (n = 0; n < Neyr1; n++)
{
for (i = 0; i < Amount_Vvod; i++)
{
sum = sum + (nr->vvod[i] * nr->w1[i][n]);
}
nr->prom[n] = 1 / (1 + exp((-sum)*nr->k));
sum=0;
}
sum=0;
for (n = 0; n < Neyr2; n++)
{
for (i = 0; i < Neyr1; i++)
{
sum = sum + (nr->prom[i] * nr->w2[i][n]);
}
nr->rez[n] = 1 / (1 + exp((-sum)*nr->k));
sum=0;
}
}
Текст программы файла main.с представлен на рисунке Б.3.
#include "stm32f4xx.h"
#include "stm32f4_discovery.h"
#include "Neyro.h"
#include <stdlib.h>
#define NOM 15//количество принимаемых байт через UART
char bufer[NOM];//буфер для приема через COM
volatile char flag_uart=0;//флаг для уарт, если 1 то принята инфа
volatile uint64_t timeout=0;//таймаут для уарт
volatile int count_bufer=0;//счетчик элементов буфера уарт
volatile int flag_koef=0;//когда =1 принимаем коэффициенты матриц
volatile int flag_chisla=0;//когда =1 принимаем числа
double buf_koef[(10*Neyr1)+(Neyr1*Neyr2)]; //преобразованные коэффициенты
double buf_chisla[Amount_Vvod]; //преобразованные числа
Neyro nr;
volatile int delay_time=0;//переменная для задержки
//////////////////////////////////////////////////////////////////////////
//задержка в милисекундах, работает через таймер SysTick
void delay(int n)
{
delay_time=n;
while(delay_time != 0);
}
/////////////////////////////////////////////////////////////////////.....
// Инициализация УАРТа
//////////////////////////////////////////////////////////////////////////
void InitUart4(void)
{
GPIO_InitTypeDef GPIO_uart;
USART_InitTypeDef USART_InitStructure;
//USART_ClockInitTypeDef USART_ClockInitStructure;
//enable bus clocks
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
//Set UART4 Tx (PC.10) as AF push-pull
GPIO_uart.GPIO_Pin = GPIO_Pin_10;
GPIO_uart.GPIO_Mode = GPIO_Mode_AF;
GPIO_uart.GPIO_OType = GPIO_OType_PP;
GPIO_uart.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_uart);
//Set UART4 Rx (PC.11) as input floating
GPIO_uart.GPIO_Pin = GPIO_Pin_11;
GPIO_uart.GPIO_Mode = GPIO_Mode_AF;
GPIO_uart.GPIO_OType = GPIO_OType_PP;
GPIO_uart.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_uart.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_uart);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);
//USART_ClockStructInit(&USART_ClockInitStructure);
//USART_ClockInit(UART4, &USART_ClockInitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
//Write UART4 parameters
USART_Init(UART4, &USART_InitStructure);
//разрешение прерывания по приему данных
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
NVIC_EnableIRQ(UART4_IRQn); //вкл прерывание
//USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
//Enable USART4
USART_Cmd(UART4, ENABLE);
}
//////////////////////////////////////////////////////////////////////
// Инициализация портов
//////////////////////////////////////////////////////////////////////////
void InitPorts()
{
GPIO_InitTypeDef gpiod;
GPIO_InitTypeDef gpioa;
//тактирование порта D, A
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//настройка порта D на выход
gpiod.GPIO_Mode = GPIO_Mode_OUT;
gpiod.GPIO_OType = GPIO_OType_PP;
gpiod.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
gpiod.GPIO_Speed = GPIO_Speed_50MHz;
// Инициализируем GPIO на порту D
//GPIO_DeInit(GPIOD);
GPIO_Init(GPIOD, &gpiod);
//настройка порта А на вход, используется кнопка подключенная к земле и к контроллеру
gpioa.GPIO_Mode = GPIO_Mode_IN;
gpioa.GPIO_OType = GPIO_OType_PP;
gpioa.GPIO_Pin = GPIO_Pin_0;
gpioa.GPIO_Speed = GPIO_Speed_50MHz;
// Инициализируем GPIO на порту A
//GPIO_DeInit(GPIOA);
GPIO_Init(GPIOA, &gpioa);
}
///////////////////////////////////////////////////////////////////////////
// Прерывание УАРТа
//////////////////////////////////////////////////////////////////////////
void UART4_IRQHandler()
{
timeout=0;
if(flag_uart==1)
{
return;//если буфер не обработан, то выходим
}
//записываем принятое значение в буфер
bufer[count_bufer] = USART_ReceiveData(UART4);
// если приняли w, значит идете передача весовых коэф-ов
if(bufer[count_bufer] == 'w')
{
flag_koef=1;
return;
}
// если приняли c, значит идете передача чисел на распознавание
if(bufer[count_bufer] == 'c')
{
flag_chisla=1;
return;
}
if(bufer[count_bufer] == ',')
{
bufer[count_bufer] = '.';
}
//максимум NOM байт, если счетчик равен NOM, значит приняли все полностью
count_bufer++;
if(count_bufer==NOM)
{
count_bufer=0;
flag_uart=1;
}
}
//////////////////////////////////////////////////////////////////////////
// Обработчик прерывания по переполнению таймера SysTick
//////////////////////////////////////////////////////////////////////////
void SysTick_Handler()
{
static int i=0;
int srav=500;
i++;
if(flag_koef==1 || flag_chisla==1)
{
srav=100;
if(i>100)
{
i=0;
}
}
if(flag_koef==0 && flag_chisla==0)
{
srav=500;
}
if(i==srav)
{
// Мигание светодиодом
GPIO_ToggleBits(GPIOD, GPIO_Pin_15);
i=0;
}
//если задана задержка delay
if(delay_time != 0)
{
delay_time--;
}
//если что то приняли, ждем таймаут
if(count_bufer != 0)
{
timeout++;
//если таймаут вышел, значит больше ничего не придет
if(timeout>30)
{
count_bufer=0;
flag_uart=1;
timeout=0;
}
}
}
//////////////////////////////////////////////////////////////////////////
void InitNeyro()
{
nr.k=1.3;
nr.skor=0.7;
CreateNeyro(&nr);
}
//////////////////////////////////////////////////////////////////////////
// Функция записы коэффициентов в матрицы
//////////////////////////////////////////////////////////////////////////
void Write_koef(Neyro* nr, const double *buf)
{
int i,j;
//Заполнение матрицы весовых коэффициентов w1
for (i = 0; i < Amount_Vvod; i++)
{
for (j = 0; j < Neyr1; j++)
{
nr->w1[i][j] = *buf++;
}
}
//Заполнение матрицы весовых коэффициентов w2
for (i = 0; i < Neyr1; i++)
{
for (j = 0; j < Neyr2; j++)
{
nr->w2[i][j] = *buf++;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Функция записы коэффициентов в матрицы
//////////////////////////////////////////////////////////////////////////
void Write_vvod(Neyro* nr, const double *buf)
{
int i;
//заполнение массива входных значений
for(i = 0; i < Amount_Vvod; i++)
{
nr->vvod[i]=*buf/10;
buf++;
}
}
void Klass(Neyro* nr)
{
int i;
int znach[Neyr2];
int kl=0;
for (i = 0; i < Neyr2; i++)
{
if (nr->rez[i] < 0.5)
{
znach[i] = 0;
}
if (nr->rez[i] > 0.5)
{
znach[i] = 1;
}
}
for (i = 0; i < Neyr2; i++)
{
if (znach[i] == nr->ogid1[i])
{}
else goto m;
}
kl = 1;
m:
for (i = 0; i < Neyr2; i++)
{
if (znach[i] == nr->ogid2[i])
{}
else goto m1;
}
kl = 2;
m1:
if (kl == 0)
{
//вкл-выкл светодиодами
GPIO_SetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
delay(100);
GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
if (kl == 1)
{
GPIO_SetBits(GPIOD, GPIO_Pin_12);
}
if (kl == 2)
{
GPIO_SetBits(GPIOD, GPIO_Pin_14);
}
}
//////////////////////////////////////////////////////////////////////////
int main(void)
{
int i=0;
int cnt=0;
i=sizeof(double);
InitPorts();
InitUart4();
InitNeyro();
// Конфигурируем таймер SysTick на срабатывание 1000 раз в секунду
SysTick_Config(SystemCoreClock / 1000);
while(1)
{
//если приняты данные через уарт
if(flag_uart==1)
{
//если принимаем коэффициенты
if(flag_koef==1)
{
buf_koef[cnt]=atof(bufer);
cnt++;
//если приняли все коэффициенты
if(cnt == (10*Neyr1)+(Neyr1*Neyr2) )
{
cnt=0;
flag_koef=0;
//записываем в матрицы
Write_koef(&nr,&buf_koef[0]);
//вкл-выкл светодиодами
GPIO_SetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
delay(200);
GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}
}
//если принимаем числа
if(flag_chisla==1)
{
buf_chisla[cnt]=atof(bufer);
cnt++;
//если приняли все числа
if(cnt==Amount_Vvod)
{
cnt=0;
flag_chisla=0;
GPIO_ResetBits(GPIOD, GPIO_Pin_12 | GPIO_Pin_14);
delay(200);
//записываем в массив входных значений
Write_vvod(&nr,&buf_chisla[0]);
Res(&nr);
Klass(&nr);
}
}
//обнуление буфера
for(i=0;i<NOM;i++)
{
bufer[i]=0;
}
flag_uart=0;//снимаем флаг уарта
}
}
}
Рисунок Б.3
Размещено на Allbest.ru
Подобные документы
Понятие и направления анализа акций. Изучение принципов работы нейросети с использованием программы "Нейросимулятор". Создание оптимально работающей нейросети для прогнозирования котировок акций, этапы данного процесса и оценка полученных результатов.
презентация [42,3 K], добавлен 19.08.2013Выбор программ CodeVisionAVR и Altium Designer для быстрой реализации бегущей строки на микроконтроллере с применением программного симулятора. Реализация передачи данных, отображение текста на экране LCD. Составление эксплуатационной документации.
курсовая работа [723,5 K], добавлен 17.11.2014Этапы процедуры принятия решений. Разработка математического алгоритма. Блок-схема алгоритма работы программы. Разработка программы на языке программирования С++ в среде разработки MFC. Текст программы определения технического состояния станка с ЧПУ.
курсовая работа [823,0 K], добавлен 18.12.2011Классификация генераторов пилообразного напряжения со стабилизаторами тока, их применение. Разработка алгоритма и программы функционирования устройства. Результаты эмуляции программы в пакете VMLAB, анализ временных соотношений и оценка погрешностей.
курсовая работа [903,7 K], добавлен 25.12.2010Функциональная схема микроконтроллера. Схема подключения ADS7841. Блок-схема и интерфейс программы АЦП. Реализация Hart-протокола, пример транзакции. Результат моделирования передачи по Uart. Индикация, текст программы. Сторожевой таймер, печатная плата.
курсовая работа [2,3 M], добавлен 17.02.2013Анализ нейронных сетей и выбор их разновидностей. Модель многослойного персептрона с обучением по методу обратного распространения ошибки. Проектирование библиотеки классов для реализации нейросети и тестовой программы, описание тестирующей программы.
курсовая работа [515,4 K], добавлен 19.06.2010Разработка модели лифта, алгоритма и программы на языке JavaScript. Возможность использования модели при проектировании промышленных лифтов и отладки управляющих программ. Основные принципы построения модели лифта, выполнение вычислительного эксперимента.
курсовая работа [495,8 K], добавлен 09.06.2013Описание работы элементов программы в виде блок-схем. Анализ структурной схемы модели домофона. Блок-схема работы открытия двери ключом. Моделирование в Proteus: принцип динамического опроса и индикации, внешний вид жидкокристаллического дисплея.
курсовая работа [1,4 M], добавлен 12.04.2019Разработка алгоритма и программы управления поворотной платформой лифта при помощи языка программирования Java Script. Проектирование приложения к браузеру в среде Adobe Dreamweaver CS5. Схема алгоритма, текст программы для двухмерной модели лифта.
курсовая работа [353,1 K], добавлен 18.05.2013Сущность метода неопределённых коэффициентов, использование интерполяционных многочленов и разностных соотношений для аппроксимации производных. Алгоритм программы и обоснование языка программирования. Экспериментальное исследование и решение задачи.
курсовая работа [227,4 K], добавлен 30.04.2009