Часть 28: Генетический алгоритм на ATmega328P

Да, мы можем запустить эволюцию на микроконтроллере! Генетические алгоритмы идеально подходят для оптимизации параметров (например, настройка PID-регулятора).

Генетический алгоритм для нахождения минимума функции:

#include <avr/random.h>

#define POPULATION_SIZE 20
#define GENOME_SIZE 8
#define GENERATIONS 100

// Структура особи
struct Individual {
    uint8_t genes[GENOME_SIZE];
    uint16_t fitness;
};

Individual population[POPULATION_SIZE];
Individual best;

// Функция приспособленности (чем меньше, тем лучше)
uint16_t calculateFitness(uint8_t* genes) {
    uint16_t result = 0;
    for (uint8_t i = 0; i < GENOME_SIZE; i++) {
        // Целевая функция: найти минимум
        result += (genes[i] - 128) * (genes[i] - 128);
    }
    return result;
}

// Создание начальной популяции
void initPopulation() {
    for (uint8_t i = 0; i < POPULATION_SIZE; i++) {
        for (uint8_t j = 0; j < GENOME_SIZE; j++) {
            population[i].genes[j] = random(256);
        }
        population[i].fitness = calculateFitness(population[i].genes);
    }
}

// Селекция (турнирная)
uint8_t tournamentSelection() {
    uint8_t bestIndex = random(POPULATION_SIZE);
    for (uint8_t i = 0; i < 3; i++) {
        uint8_t contender = random(POPULATION_SIZE);
        if (population[contender].fitness < population[bestIndex].fitness) {
            bestIndex = contender;
        }
    }
    return bestIndex;
}

// Кроссинговер (одноточечный)
void crossover(uint8_t* parent1, uint8_t* parent2, uint8_t* child1, uint8_t* child2) {
    uint8_t point = random(GENOME_SIZE);
    for (uint8_t i = 0; i < GENOME_SIZE; i++) {
        if (i < point) {
            child1[i] = parent1[i];
            child2[i] = parent2[i];
        } else {
            child1[i] = parent2[i];
            child2[i] = parent1[i];
        }
    }
}

// Мутация
void mutate(uint8_t* genes) {
    for (uint8_t i = 0; i < GENOME_SIZE; i++) {
        if (random(100) < 5) {  // 5% вероятность мутации
            genes[i] += random(-10, 10);
        }
    }
}

// Основной цикл эволюции
void evolve() {
    Individual newPopulation[POPULATION_SIZE];
    
    // Элитизм: сохраняем лучшую особь
    best = population[0];
    for (uint8_t i = 1; i < POPULATION_SIZE; i++) {
        if (population[i].fitness < best.fitness) {
            best = population[i];
        }
    }
    newPopulation[0] = best;
    
    // Создаем остальную популяцию
    for (uint8_t i = 1; i < POPULATION_SIZE; i += 2) {
        uint8_t p1 = tournamentSelection();
        uint8_t p2 = tournamentSelection();
        
        crossover(population[p1].genes, population[p2].genes,
                  newPopulation[i].genes, newPopulation[i+1].genes);
        
        mutate(newPopulation[i].genes);
        mutate(newPopulation[i+1].genes);
        
        newPopulation[i].fitness = calculateFitness(newPopulation[i].genes);
        newPopulation[i+1].fitness = calculateFitness(newPopulation[i+1].genes);
    }
    
    // Копируем новую популяцию
    memcpy(population, newPopulation, sizeof(population));
}

void setup() {
    Serial.begin(115200);
    randomSeed(analogRead(A0));
    
    initPopulation();
    
    for (uint16_t gen = 0; gen < GENERATIONS; gen++) {
        evolve();
        
        Serial.print("Поколение ");
        Serial.print(gen);
        Serial.print(": лучшее значение = ");
        Serial.println(best.fitness);
    }
    
    Serial.print("Оптимальные гены: ");
    for (uint8_t i = 0; i < GENOME_SIZE; i++) {
        Serial.print(best.genes[i]);
        Serial.print(" ");
    }
    Serial.println();
}

void loop() {}

Вам также может понравиться

About the Author: ардуинчиков

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *