Neurocell code

Hello, dear community GeekTimes! Not so long ago a series of articles devoted to the work on the creation of a model of the nervous system was published here. And the best way to understand the logic of the model is the possibility of studying the program code of its implementation. I not only want to convey my ideas in more detail, but also ask for help from the community. I know that among GT readers there are a lot of professionals in writing software code and your experience, knowledge can help the development of the project. Sometimes there is enough competent advice or recommendation so that the solution of such an unusual task becomes elegant and easy.
Content of a series of articles
1. Симулятор нервной системы. Часть 1. Простой сумматор
2. Симулятор нервной системы. Часть 2. Модулируемый нейроэлемент
3. Симулятор нервной системы. Часть 3. Ассоциативный нейроэлемент
4. Память, консолидация памяти и бабушкины нейроны
5. Моделирование эмоций или электронное чувство новизны
6. Удивительный мозжечок
7. Структура и стартовые настройки мозга
2. Симулятор нервной системы. Часть 2. Модулируемый нейроэлемент
3. Симулятор нервной системы. Часть 3. Ассоциативный нейроэлемент
4. Память, консолидация памяти и бабушкины нейроны
5. Моделирование эмоций или электронное чувство новизны
6. Удивительный мозжечок
7. Структура и стартовые настройки мозга
Development environment - Unity3D, a very popular game engine. This medium turned out to be very convenient and accessible both in the work with the editor and in the presence of a large number of references, explanations and comments in Russian. Therefore, my modest programming skills were enough to implement my ideas using Unity3D.
There are no plans to change the development environment, as the game engine makes it easy to solve visualization tasks, which is very important at this stage.
I want to apologize to those who want to refer to the code for its negligence, the possible neglect of the syntax of the language and possible errors. When I started this work, there was no demonstration of code in the plans. I wanted to test some of my hypotheses.
The code reflects the creative search. In the process of work, I faced another problem, the model did not want to act as I imagined it. And during the day, an idea of how to fix this could come to me. In these moments, I can be inspired by some insight. Returning from work, I eagerly amended, ignoring all norms in the code, there was no time for that. And as often happens, these insights did not bring results, or did not bring quite the desired result. This was how the project worked, and thanks for the patience of my wife, which allowed me to carry out this work. It is difficult to find time between family, work, your own procrastination and laziness for the routine work of standardizing code. Although it will still have to do sometime.
In my work, I adhered to a somewhat non-typical model of the work of a neuron. A neuron model like a biological neuron could act asynchronously from the work of other neurons. Signals from receptor keys such as, for example, skin receptors may not be synchronized. Therefore, in the first models, under the influence of stereotypical thinking, I singled out in the work of a neuron some phases of the state lasting a certain number of steps (cycles) of the entire system, and the steps of the system were performed synchronously in all neurons. It did not work properly, and it was also terribly uncomfortable. But it was necessary to somehow synchronize the incoming and outgoing signals, and properly evaluate them.
At a certain point, an idea came that one Internet user subsequently dubbed the “cistern”. The “flush tank” model was surprisingly accurate and applicable to a biological neuron, it explained summation mechanisms very visually, and was more convenient to implement. Now emulated neurons could be completely independent, just like real objects.

This adder model is the most accurate model of the biological neuron I know of. To model in detail the stomach cell will require incredibly large computational power, but all that this cell does is that it produces the appropriate enzyme or hormone if necessary. The attribution of incredible computational properties to a neuron is very popular among modern cyberneticists.
Subsequently, some mechanisms from the reflex theory and the idea of directional orientation of the settings of the outgoing synapses were added to the summation model. The resulting model allowed us to create a theoretical basis that rather simply explained many processes and phenomena occurring in the nervous system. Reflex mechanisms, memory and memory consolidation, self-organization and specialization of neurons, the work of the cerebellum, emotional mechanisms and thinking all in one bottle.
I will not tire. Link to the GitHub repository .
For example, the script code which contains the main logic of the NeironScript.cs neuroelement (sorry for my French):
Lot of code
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
publicclassNeironScript : MonoBehaviour {
public GameObject prefabNeiron; //Префаб нейронаpublic GameObject prefabSinaps; //Префаб синапсаpublicint IndexNeiron = 0; //Индекс нейронаprivateint _TypeIndexNeiron = 0; //Индекс типа нейронаpublicint TypeIndexNeiron //Индекс типа нейрона
{
get { return _TypeIndexNeiron; }
set {
if (value == 0)
{ _TypeIndexNeiron = value;
gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 0, 255);//Жёлтый, сумматор
}
if (value == 1)
{ _TypeIndexNeiron = value;
gameObject.GetComponent<SpriteRenderer>().color = new Color32( 0, 255, 0, 255); //Зелёный, модулирующий //
}
if (value == 2)
{ _TypeIndexNeiron = value;
gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 255, 255, 255);//Голубой, асоциативный тип
}
if (value == 3)
{ _TypeIndexNeiron = value;
gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 255, 255);//Белый, тормозящие нейроны
}
}
}
// Настройки нейрона 0publicfloat Adder = 0.0f; //Сумматорpublicfloat MaxAdder = 30f; //Максимальное значение сумматораpublicfloat DampferAdder = 1.0f; //Регулятор сумматораpublicfloat thresholdTop = 1.0f; //Верхний баховый порогpublicfloat AnswerTime = 0.1f; //Время ответаpublicfloat TimeRepose = 0f; //Время отдыха publicbool IgnoreInput = false; //Игнорируется ли входыpublic List<GameObject> hitSinaps = new List<GameObject>(); //Список синапсовpublic GameObject Area; //Областьprivatebool _ActionN; //Активен ли нейронpublicbool ActionN //Активен ли нейрон
{
get { return _ActionN; }
set
{
_ActionN = value;
if (Area != null)
{
gameObject.GetComponent<LineRenderer>().enabled = value; //Показать вектор направления..bool existAction = Area.GetComponent<AreaScript>().NeironActionList.Contains(gameObject); //existAction = true - если нейрон в списке активных нейронов областиif (_ActionN && (!existAction)) Area.GetComponent<AreaScript>().NeironActionList.Add(gameObject); //добавить в список активных областиelse Area.GetComponent<AreaScript>().NeironActionList.Remove(gameObject); //удалить из списка активных области
}
}
}
// Настройки нейрона 1 publicfloat thresholdDown = -5.0f; //Нижний порог publicfloat timeIgnore = 5.0f; //Время усиленной реполяризации при значении сумматора ниже нижнего порогаpublicfloat bonusThreshold = 0f; //Надбавка на верхний порогpublicfloat DempferBonusThreshold = 1.0f; //Регулятор фактического значения порогаpublicfloat TimeEvaluation = 5.0f; //Время оценкиpublicint LimitRecurrence = 5; //Лимит повторенийpublicfloat thresholdTopUp = 1.0f; //На сколько повысить порогpublicbool TimeEvaluationBool = false; //Время оценкиpublicint LimitEvaluationInt = 0; //Счётчик повторений в период оценкиpublicfloat AdaptationTime = 0; //Время адаптацииpublicfloat thresholdAdapt = 1f; //Минимум при адаптации// Настройка нейрона 2publicfloat MaxForceSinaps = 100f;
private Vector3 VectorPattern; //Вектор патернаpublic Vector3 VectorTrend; //Вектор путиpublicfloat Charge = 0.0f; //Зарядpublicfloat TimeCharge = 0.01f; //Время такта смены зарядаprivatefloat changeAngle = 0f; //Изменение угла вектораpublicfloat FocusNeiron = 90f; //Фокус нейронаpublicbool FocusDinamic = true; //Изменять фокус динамическиpublicfloat StepFocus = 1f; //Шаг изменения фокусаpublicfloat MaxFocus = 90f; //Максимальное значение фокусаpublicfloat Plasticity = 1.0f; //Нейропластичностьpublicbool PlasticityDinamic = true; //Изменяется ли пластичность publicfloat StepPlasticity = 0.01f; //Шаг пластичностиpublicfloat BasicPlasticity = 1.0f; //Базовая пластичность (пластичность новых нейронов)publicbool NewNeironDinamic = true; //Создовать ли нейрон динамическиprivatefloat angleMin = 0f;
privatebool CorunPlasticRun = false;
// END VARprivate Vector3 noveltyVector = Vector3.zero;
privatefloat noveltyFactor = 0.1f;
IEnumerator StartSummator (){
IgnoreInput = true; //Включаем игнорирование внешних сигналов
gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); //Подсветка красным
ActionN = true; //Активное состояние для идикаторов выходаyield return new WaitForSeconds(AnswerTime); //Время ответа
ActionN = false;
ExcitationTransfer (); //передача возбужденияyield return new WaitForSeconds(TimeRepose);//время отдыха
IgnoreInput = false; // отключаем игнорирование внешних сигналов
TypeIndexNeiron = _TypeIndexNeiron; //Возращаем цвет нейроэлементы
}
IEnumerator repolarizationTime (){
IgnoreInput = true; //включаем игнорирование внешних сигналов
gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255);//устанавливаем синий цветyield return new WaitForSeconds(timeIgnore);//время игнора
IgnoreInput = false;
TypeIndexNeiron = _TypeIndexNeiron;//включаем свой цвет
}
IEnumerator StartModule (){
IgnoreInput = true; //включаем игнорирование внешних сигналов
ActionN = true; //Состояние активности, это значение считывают индикаторы выходов
gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255);//крачный цветyield return new WaitForSeconds(AnswerTime);//время ответа
ExcitationTransfer ();//передача по всем исходящим синапсам
ActionN = false;//выключаем активность yield return new WaitForSeconds(TimeRepose);//время отдыха
IgnoreInput = false;//перестаем игнорировать внешние сигналы
TypeIndexNeiron = _TypeIndexNeiron;//возращаем цвет
StartCoroutine ("EvaluationTime");//запуск времени оценкиif ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");//запуск адаптации, при значении настроект адаптации =0 адаптация не работает//и нет смысла запускать корунтину если порог на нижнем пределе
}
IEnumerator EvaluationTime(){
TimeEvaluationBool = true;//Сейчас пойдет время оценкиyield return new WaitForSeconds(TimeEvaluation);
TimeEvaluationBool = false;//Время оценки кончилось
}
IEnumerator AdaptationVoid(){
yield return new WaitForSeconds(AdaptationTime);//временной итервал if (thresholdTop > thresholdAdapt) thresholdTop--;//снижаем порог, но не ниже базовогоif ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");//снова запускаем адаптацию
}
IEnumerator NegativeRepolarization(){
IgnoreInput = true; //влючаем игнорирование внешних сигналов
ActionN = true; //Активностьfor (int i = 0; i < 16; i++)
{ //перебираем занчения заряда
Charge = Area.GetComponent<AreaScript>().Spike2[i];
if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); //красныйelse gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); //синийyield return new WaitForSeconds(TimeCharge); //с заданной частотой/скоростью
}
Charge = 0f;//заряд обнуляем
TypeIndexNeiron = _TypeIndexNeiron;//свой цыет
ActionN = false;//активность
IgnoreInput = false;//больше не игнорируем внешние сигналы
}
IEnumerator StartAssociative(){
IgnoreInput = true;//Игнорирование внешних сигналов
ActionN = true;//Активность
StartCoroutine("PositiveRepolarization"); //параллельно начинаем изменять зарядyield return new WaitForSeconds(AnswerTime); //Время ответа
Compass ();//отдельный блок кода
}
IEnumerator StartWhite() {
IgnoreInput = true;//Игнорирование внешних сигналов
ActionN = true;//Активность
StartCoroutine("PositiveRepolarization");//параллельно начинаем изменять зарядyield return new WaitForSeconds(AnswerTime); //Время ответа
ExcitationTransfer ();//ответ по всем исходящим синапсам
}
IEnumerator PositiveRepolarization(){
for (int i = 0; i < 16; i++) {
//перебор значений заряда
Charge = Area.GetComponent<AreaScript>().Spike1[i];
if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); //красныйelse gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); //синийyield return new WaitForSeconds(TimeCharge); //с установленной частотой
}
Charge = 0f; //обнуляем заряд
TypeIndexNeiron = _TypeIndexNeiron;//возращаем цвет
ActionN = false;//активность отключаемyield return new WaitForSeconds(TimeRepose);//время отдыха
IgnoreInput = false;//отключаем игнорирование
StartCoroutine ("EvaluationTime");//Время оценкиif ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");//Адаптация
}
IEnumerator PlasticTimeCoruntine (Vector2 PT){//Временное изменение пластичности
CorunPlasticRun = true;//Изменение временной пластичности началосьfloat PlasticBuffer = Plasticity;//Сохраням текущюю пластичность
Plasticity = PT.x;//Устанавливаем временнуюyield return new WaitForSeconds(PT.y);//Ждем необходимое время
Plasticity = PlasticBuffer;//Возращаем прежнюю пластичность
CorunPlasticRun = false;//Время изменения пластичности кончилось
}
publicvoidActiveNeiron (){ //В засисимости от типа нейрона запускаем соотвествующюю программу активацииif (!IgnoreInput)
{
if (TypeIndexNeiron == 0) StartCoroutine ("StartSummator");//Синапс прямого действияif (TypeIndexNeiron == 1) StartCoroutine ("StartModule");//Модулирующий синапсif (TypeIndexNeiron == 2) StartCoroutine ("StartAssociative");//Изменяемый синапса, прямого действия ассоциативного нейроэлементаif (TypeIndexNeiron == 3) StartCoroutine ("StartWhite");//Синапс прямого действия
}
}
privatevoidCompass (){
if (Area != null){ //Если нейрон не принадлежит области, то невозможно получить информацию о других обьектах системы
VectorPattern = Vector3.zero; //Обнуляем точку паттерна//Подсчёт точки паттернаfor (int i = 0; i < Area.GetComponent<AreaScript>().NeironActionList.Count; i++) { //Список всех активных нейроновif (gameObject == Area.GetComponent<AreaScript> ().NeironActionList [i]) continue; //Исключаем данный нейрон из расчётов
Vector3 R = Area.GetComponent<AreaScript> ().NeironActionList [i].transform.position - transform.position;//получаем относительные кординаты, относительно данного нейрона//Формула определения заряд нейрона на единичный вектор
VectorPattern += (Area.GetComponent<AreaScript> ().NeironActionList [i].GetComponent<NeironScript> ().Charge * R.normalized);//R.sqrMagnitude; .normalized //sqrMagnitude;!!!!!!!!!(Без квадрата лучше)
}
if (VectorPattern.sqrMagnitude < 3f) VectorPattern = VectorTrend; //незначительное влияние не учитываем, принимаем предыдущее значение вектораif (VectorPattern.sqrMagnitude == 0) VectorPattern = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f));
//Нет предыдущих значений (новый нейрон), нет других активных нейронов, то берём случайное значение, возбуждение должно передаться куда-нибудь
VectorPattern.Normalize(); //Получаем единичный вектор направленияif (noveltyVector == Vector3.zero) noveltyVector = -VectorPattern; //новый нейрон (новизна ранее не определялась) устанавливаем максимальное значения - противоположное установленному вектору направления
changeAngle = Vector3.Angle(VectorPattern, noveltyVector);// определяем угол между направлением и предыдущем значением вектора новизныif (Area != null) Area.SendMessage("MessageOriginality", changeAngle/180);//сообщаем области об уровне новизны для нейрона
VectorTrend = VectorPattern; //промежуточное начение
noveltyVector = Vector3.Slerp(noveltyVector, VectorPattern, noveltyFactor);//изменям вектор новизны//вектор новизны постепенно приближается к векторы направления//это имитация постепенного угасания получения удовольстия от нового опыта//если сразу присвоить noveltyVector = VectorPattern, то новизна будет оцениваться более реактивно (в ранних версиях так и было)//новое действие вызывает интерес даже при нескольких повторениях, а не угасает сразу после однократного повторения
gameObject.GetComponent<LineRenderer>().SetPosition(0, transform.position);//визуализация вектора предпочитаемого направления
gameObject.GetComponent<LineRenderer>().SetPosition(1, transform.position + VectorTrend * 6);
if (PlasticityDinamic) {
if (changeAngle < 10) Plasticity -= StepPlasticity; else Plasticity += StepPlasticity; //изменение пластичностиif (Plasticity > 1) Plasticity = 1f;
if (Plasticity < 0) Plasticity = 0f;
//Идея с таким динамическим изменением пластичности сейчас считаю не перспективной//Пластичность характеризуется областью в мозге, а также имет большую роль играет в эмоциональных механизмах. //Т.е. большее внимание стоит уделить внешним условиям изменения пластичности, чем изменять пластичность под влиянием внутренних состояний
}
if (FocusDinamic){
if (changeAngle < 10) FocusNeiron -= StepFocus; else FocusNeiron = MaxFocus;
if (FocusNeiron < 0) FocusNeiron = 0;
//На данный моммент не получилось продемонстрировать эффективность динамически изменяемого фокуса.//Но перспектива для него есть в более маштабных моделях.//Динамическое изменение фопуса поможет имулировать иррадиацию и концентрацию.//Иррадиацию и концентрацию - наблюдаемые явления в нервной системе, модель нервной системы должна их имитировать
}
//динамическое создание нейроновif (NewNeironDinamic){
if (!Physics.CheckSphere(transform.position + VectorTrend * 5, 3f))
{ //Есть ли что-то в сферической области радиусом 3,//центор которой расположен на растоянии 5 от данного нейрона//в направлении вектора направленияif (Area.GetComponent<AreaScript>().Global) NewNeiron(); //Глобальная область не имеет границelse
{
if (Area.GetComponent<Collider>().bounds.Contains(transform.position + VectorTrend * 5)) NewNeiron(); //проверка выходит ли будующий нейрон за границы своей области
}
}
//Динамическое создание синапсов
Collider[] hitColliders = Physics.OverlapSphere(transform.position + VectorTrend * 5, 3f); //Список всех обьектов в сферической области по направлению foreach (Collider valuein hitColliders) //перебор всех из этого списка
{
if (value.tag == "Neiron") //нужны только нейроны
{
bool EnableSinaps = false; //синапса с этим обьектом нетforeach (GameObject sinapsValue in hitSinaps) //смотрим все свои синапсы
{
if (sinapsValue.GetComponent<SinapsScript>().NeironTarget == value.gameObject) {
EnableSinaps = true; //синапс такой есть break; //дальше не перебираем
}
}
if (!EnableSinaps) { //Если такого синапса нет
GameObject cSinaps = Instantiate(prefabSinaps, transform.position, transform.rotation) as GameObject;//мы его создаём
cSinaps.transform.parent = transform;
cSinaps.GetComponent<SinapsScript>().NeironTarget = value.gameObject;
cSinaps.GetComponent<SinapsScript>().Force = 0f;
hitSinaps.Add(cSinaps);
}
}
}
}
//Нахождение минимального угла между векторами синапсов и вектором направления
angleMin = 180f;
if (hitSinaps.Count != 0) angleMin = Vector3.Angle(hitSinaps[0].GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
foreach(GameObject ShershSinaps in hitSinaps)
{
float angleShersh = Vector3.Angle(ShershSinaps.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
if (angleShersh < angleMin) angleMin = angleShersh;
}
if (FocusNeiron < angleMin) FocusNeiron = angleMin;
//Фокус не должен уменьшаться ниже того значения, которое приведёт к угасанию всех его синапсов.//В конус фокуса должен входить хотябы одни вектор синапса, //иначе после укрепления рефлекса далее произойдет его необоснованное угнетение.//Подсчет весов foreach(GameObject SinapsCoeff in hitSinaps){
if (SinapsCoeff.GetComponent<SinapsScript>().TypeSinaps == 0){
float angleSinaps = Vector3.Angle(SinapsCoeff.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
if (angleSinaps <= FocusNeiron) SinapsCoeff.GetComponent<SinapsScript>().Force += MaxForceSinaps * Plasticity;
else SinapsCoeff.GetComponent<SinapsScript>().Force -= MaxForceSinaps * Plasticity;
SinapsCoeff.GetComponent<SinapsScript>().Force = Mathf.Clamp(SinapsCoeff.GetComponent<SinapsScript>().Force, 0, MaxForceSinaps);
}
}
}
ExcitationTransfer ();//передача по всем исходящим синапсам
}
privatevoidNewNeiron (){
GameObject clone = Instantiate(prefabNeiron, transform.position + VectorTrend * 6, transform.rotation) as GameObject;
/* Интересная фича: если производить самокопирование из обьекта на сцене (как это происходит здесь),
* то происходит копирование значений переменных родителя, а не беруться исходные значения настроенного префаба
* поэтому требуется это учитывать и устанавливать начальные настройки, значения переменных в новом экземпляре.
* Не знание этого нюанса создало множество проблем....
* */if (Area != null) Area.GetComponent<AreaScript>().amount++;//подсчёт нейронов в области принадлежащей нейрону
clone.GetComponent<NeironScript>().Plasticity = BasicPlasticity;//стартовые настройки нейроэлемента
clone.GetComponent<NeironScript>().ActionN = false;
clone.GetComponent<NeironScript>().IgnoreInput = false;
clone.GetComponent<NeironScript>().Adder = 0f;
clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero;
clone.GetComponent<NeironScript>().Area = Area;
clone.GetComponent<NeironScript>().TimeEvaluationBool = false;
clone.GetComponent<NeironScript>().LimitEvaluationInt = 0;
clone.GetComponent<NeironScript>().Charge = 0.0f;
clone.GetComponent<NeironScript>().FocusNeiron = MaxFocus;
clone.GetComponent<NeironScript>().Plasticity = BasicPlasticity;
clone.GetComponent<NeironScript>().TypeIndexNeiron = 2;
clone.GetComponent<NeironScript>().noveltyVector = Vector3.zero;
clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero;
clone.GetComponent<LineRenderer>().SetPosition(0, clone.transform.position);
clone.GetComponent<LineRenderer>().SetPosition(1, clone.transform.position);
clone.SendMessage("StopNeiron"); //в новом обьекте даже корунтины находятся в той же фазе работы, что и родителе
GameObject ManagerObj = GameObject.Find("Manager"); //...нужно исправить, Find перегружает
ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron++;//подсчитываем нейроны
clone.GetComponent<NeironScript>().IndexNeiron = ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron;//определяем номер для нового нейрона
clone.name = "Neiron" + clone.GetComponent<NeironScript>().IndexNeiron;//отмечаем идекс нейрона в имени обьектаforeach (GameObject sd in clone.GetComponent<NeironScript>().hitSinaps) Destroy(sd); //префаб размещенный в сцене из подобного себе обьекта, копирует и дочерниие обьеты родителя
clone.GetComponent<NeironScript>().hitSinaps.Clear(); //приходится очищать новый обьект. Это странно..
}
voidFixedUpdate(){ //Главная функция для нейрона срабатывает каждые 0.01сif (!IgnoreInput) //Если внешние сигналы не игнорируется
{
if (TypeIndexNeiron == 0) // Это простой сумматор
{
if (Adder > thresholdTop) //Пороговая функция
{
StartCoroutine ("StartSummator");
}
}
if (TypeIndexNeiron == 1) //Это модулируемый нейроэлемент
{
if (Adder > thresholdTop + bonusThreshold) //Пороговая функция
{
if (TimeEvaluationBool) //Сейчас время оценки?
{
LimitEvaluationInt++; //Счётчик повторов
StopCoroutine("EvaluationTime"); //Остановка корунтины отстивающей время оценки
TimeEvaluationBool = false; //выключение фазы оценки
}
else LimitEvaluationInt = 0; //иначе сбрасываем счётчик повторовif ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; //лимит повторов превышен и небыло модуляции значит повышаем порого - превыкание
StopCoroutine ("AdaptationVoid"); //остановка адаптации, она выполняется только при протое нейрона
StartCoroutine ("StartModule"); // Запуск модулируемого нейроэлемента
}
if (Adder < thresholdDown) //пороговая функция на нижний порог
{
if (Area != null) StartCoroutine ("repolarizationTime"); //при достаточном тормозящем воздействии, биологический нейрон усиленно поляризуется
}
}
if (TypeIndexNeiron == 2) //модулируемый нейроэлемент
{
if (Adder > thresholdTop + bonusThreshold) //порог сладывается из двух частей: обычной и модулируемой
{
if (TimeEvaluationBool) //если активация произошла во время оценки
{
LimitEvaluationInt++; //считаем лимит повторов
StopCoroutine("EvaluationTime");//останавливаем подсчёт времени
TimeEvaluationBool = false;
}
else LimitEvaluationInt = 0; //иначе время оценки прошло, сбрасываем счётчикif ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; //лемит превышен и дело не в модуляции, то повышам порог
StopCoroutine ("AdaptationVoid");//активация призошла, приостанавливаем адаптацию (адаптация - снижеине порога при простое)
StartCoroutine ("StartAssociative"); //Старт активации модулируемого нейроэлемента
}
if (Adder < thresholdDown) //сумматор ниже нижнего порога
{
StartCoroutine ("NegativeRepolarization"); //усиленная реполяризация (торможение)
}
}
if (TypeIndexNeiron == 3) //Ассоциативный нейроэлемент
{
if (Adder > thresholdTop + bonusThreshold)//Порог из двух состовляющих
{
if (TimeEvaluationBool)//Время оценки...
{
LimitEvaluationInt++;
StopCoroutine("EvaluationTime");
TimeEvaluationBool = false;
}
else LimitEvaluationInt = 0;
if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp;
StopCoroutine ("AdaptationVoid");
StartCoroutine ("StartWhite");
}
if (Adder < thresholdDown)
{
StartCoroutine ("NegativeRepolarization");
}
}
}
if (Mathf.Abs(Adder) <= DampferAdder) Adder = 0f; //Демпфер сумматораif (Adder > DampferAdder) Adder -= DampferAdder;
if (Adder < -DampferAdder) Adder += DampferAdder;
if (Mathf.Abs(bonusThreshold) <= DempferBonusThreshold) bonusThreshold = 0f; //Демпфер дополнительного порогаif (bonusThreshold > DempferBonusThreshold) bonusThreshold -= DempferBonusThreshold;
if (bonusThreshold < -DempferBonusThreshold) bonusThreshold += DempferBonusThreshold;
}
privatevoidExcitationTransfer () //Передача возбуждения
{
foreach (GameObject valuein hitSinaps) // по всем синапсам
{
int T = value.GetComponent<SinapsScript>().TypeSinaps; //тип синапсаfloat F = value.GetComponent<SinapsScript>().Force; //его сила
GameObject NT = value.GetComponent<SinapsScript>().NeironTarget;//целевой нейронif (T == 0) NT.SendMessage("AddSummator", F);//Передача сообщенияif (T == 1) NT.SendMessage("AddTActual", F);
if (T == 2) NT.SendMessage("ActiveNeiron");
if (T == 3) NT.SendMessage("AddSummator", F);
value.GetComponent<SinapsScript>().GoAction = true;//Запуск анимации синапса
}
}
publicvoidAddSummator (float Summ) //Для управления сумматором из других нейронов
{
Adder += Summ;
if (Adder > MaxAdder) Adder = MaxAdder;
if (Adder < - MaxAdder) Adder = -MaxAdder;
}
publicvoidAddTActual (float T)// управление порогом, модулирующее воздействие
{
bonusThreshold += T;
if (bonusThreshold + thresholdTop < 0f) bonusThreshold = - thresholdTop + 0.0001f;
}
publicvoidStopNeiron(){//остановка всех корунтин, возможно из других обьектов GameOject.SendMessage("StopNeiron")
StopAllCoroutines();
}
publicvoidplasticSetTime (Vector2 plasticTime){
//для управления пластичностью, SendMessage может передать только один параметр, Vectir2 - это два реальных числа//уровень пластичности и время изменения if (!CorunPlasticRun) StartCoroutine("PlasticTimeCoruntine", plasticTime);
if (TypeIndexNeiron == 2) thresholdTop = thresholdAdapt;
}
}
Communication between neurons is carried out using a messaging system based on SendMessage, and all the processes associated with changing states are rendered to corundines.

In the block diagram, the basic basis of the neuroelement. SendMessage (“AddSummator”, F) - a synapse of direct action with a force F, increases the sum of the adder by a specified number. Every 0.01s, the FixedUpdate () function is triggered in which the modulo adder decreases by the set damper / number. And as there is a check for the excess of the threshold on the adder, if the threshold is exceeded, then coruntine is started. During the operation of coruntine, the mode of ignoring external signals is turned on, but the operation of the damper for the adder continues as well as the ability to replenish the sum. SendMessage (“ActiveNeiron”) - contact synapse (efaps), corinthine will be triggered if it is not currently running, otherwise the signal will be ignored.
Based on this base, further mechanisms related to cell metabolism (addiction and adaptation) were added, as well as the modulation system, which was derived from the work of Eric Kandel. And the idea of a directed transfer of excitation for the sake of checking which I started this project.
Many people were interested in the source code of the project, but not only for this reason, I post the source. The fact is that there is still a lot of work ahead, plans to seriously expand the capabilities and tools, to create a certain environment that allows you to conveniently work with a large array of elements, structure and organize them. I do not have extensive programming experience, but I am sure that a large number of people from the GeekTimes community can give recommendations on the structure, methods, and optimization that will qualitatively improve the project. I plan not to change the development environment, for me the empiricism of the development process is important, as well as the aesthetics of the final result and the Unity game engine so far helped me a lot in this.