# MyLibs: E:/.WORK/STM32/STM32_ExtendedLibs/MyLibsGeneral/Inc/evolve_optimizer.h Source File

Loading...
Searching...
No Matches
evolve_optimizer.h
Go to the documentation of this file.
/**
******************************************************************************
* @file evolve_optimizer.h
* @brief Заголовочный файл для адаптивного подбора параметров
******************************************************************************
* @addtogroup EVOLVE_OPTIMIZER Evolve optimizer
* @ingroup MYLIBS_DEFINES
* @brief Библиотека для эволюционного подбора параметров
* @details
Поддерживает:
- Любое количество параметров
- Генерацию новых параметров на основе лучших кандидатов
- Мутацию для поиска оптимальных параметров
- Несколько независимых оптимизаторов в одной программе
Параметры для конфигурации:
- @ref ENABLE_EVOLVE_OPTIMIZATION - Включить оптимизацию параметров
Если библиотека отключена @ref ENABLE_EVOLVE_OPTIMIZATION, то вставляются
заглушки, никак не влияющие на параметры и остальную программу
- @ref EVOLVE_MAX_PARAMS - Максимальное количество параметров
- @ref EVOLVE_MAX_CANDIDATES - Максимальное количество кандидатов для обучения
@par Пример использования:
@code
#include "evolve_optimizer.h"
#define N_PARAMS 4
#define N_CANDIDATES 100
#define N_BEST 10
#define IQ_MUTATION (PARAM_SCALE_Q16(0.1, 0, 1))
int32_t params[N_PARAMS];
EvolveOptimizer_t optimizer;
// Формирование параметров
uint16_t param_u16 = 800;
float param_f = 0.01f;
uint8_t param_u8 = 40;
int16_t param_i16 = 1600;
params[0] = PARAM_SCALE_Q16(param_u16, 0, 1000);
params[1] = PARAM_SCALE_Q16(param_f, 0.001f, 0.1f);
params[2] = PARAM_SCALE_Q16(param_u8, 10, 100);
params[3] = PARAM_SCALE_Q16(param_i16, 500, 5000);
// Инициалиазция
EvolveOptimizer_Init(&optimizer, N_PARAMS, N_CANDIDATES, N_BEST, IQ_MUTATION, params);
// Шаг эволюции
int32_t loss = calc_iq_loss(); // расчет эффективности параметров
EvolveOptimizer_Step(&optimizer, params, loss);
// Взятие следующих для эволюции параметров
param_u16 = PARAM_UNSCALE_Q16(params[0], 0, 1000);
param_f = PARAM_UNSCALE_Q16(params[1], 0.001f, 0.1f);
param_u8 = PARAM_UNSCALE_Q16(params[2], 10, 100);
param_i16 = PARAM_UNSCALE_Q16(params[3], 500, 5000);
@endcode
* @{
*****************************************************************************/
#ifndef __EVOLVE_OPTIMIZER_H_
#define __EVOLVE_OPTIMIZER_H_
#include "mylibs_defs.h"
#include <stdint.h>
#include <stdlib.h>
#ifdef ENABLE_EVOLVE_OPTIMIZATION
/**
* @brief Линейное масштабирование x из диапазона [min_val, max_val] в Q16.16 [0, 65536)
*/
#define PARAM_SCALE_Q16(x, min_val, max_val) \
((int32_t)((((float)(x) - (float)(min_val)) / ((float)(max_val) - (float)(min_val))) * 65536.0f))
/**
* @brief Обратное линейное масштабирование Q16.16 значения в диапазон [min_val, max_val]
*/
#define PARAM_UNSCALE_Q16(q16_val, min_val, max_val) \
(((float)(q16_val) / 65536.0f) * ((float)(max_val) - (float)(min_val)) + (float)(min_val))
#ifndef local_time
#define local_time() HAL_GetTick() ///< Локальное время
#endif
/**
* @brief Структура эволюционного оптимизатора
*/
typedef struct {
uint16_t n_params; ///< Количество параметров
uint16_t n_cand; ///< Количество кандидатов
uint16_t n_best; ///< Количество лучших, усредняемых
uint16_t iq_mutation; ///< Амплитуда мутации в Q16.16
uint16_t cand_index; ///< Индекс кандидата для обработки
int32_t loss[EVOLVE_MAX_CANDIDATES]; ///< Loss для каждого кандидата
int32_t candidates[EVOLVE_MAX_CANDIDATES][EVOLVE_MAX_PARAMS]; ///< Параметры кандидатов
uint16_t sorted_idx[EVOLVE_MAX_CANDIDATES]; ///< Индексы отсортированных кандидатов
} EvolveOptimizer_t;
/**
* @cond EVOLVE_INTERNAL
*/
#define Q16_MUL(a,b) ((int32_t)(((int64_t)(a) * (int64_t)(b)) >> 16))
// Вспомогательный указатель для сортировки
static EvolveOptimizer_t *g_sort_opt; // глобальный указатель на текущий оптимизатор
static int cmp_idx(const void *a, const void *b) {
if (g_sort_opt->loss[*(const uint16_t*)a] < g_sort_opt->loss[*(const uint16_t*)b])
return -1;
if (g_sort_opt->loss[*(const uint16_t*)a] > g_sort_opt->loss[*(const uint16_t*)b])
return 1;
return 0;
}
/** @endcond */
/**
* @brief Инициализация эволюционного оптимизатора.
* @param opt Указатель на структуру оптимизатора
* @param n_params Количество параметров в одном кандидате
* @param n_cand Количество кандидатов
* @param n_best Количество лучших, усредняемых
* @param iq_mutation Амплитуда мутации в Q16.16
* @param start_params Начальные параметры (Q16.16)
* @return 0 — если окей,
* -1 — если ошибка
*/
__STATIC_INLINE int EvolveOptimizer_Init(EvolveOptimizer_t* opt,
uint16_t n_params,
uint16_t n_cand,
uint16_t n_best,
uint16_t iq_mutation,
int32_t* start_params)
{
if((opt = NULL) || (start_params == NULL))
return -1;
if(n_params > EVOLVE_MAX_PARAMS)
return -1;
opt->n_params = n_params;
if(n_cand > EVOLVE_MAX_CANDIDATES)
return -1;
opt->n_cand = n_cand;
if(n_best > EVOLVE_MAX_CANDIDATES/2)
return -1;
opt->n_best = n_best;
if(iq_mutation > 32768)
return -1;
opt->iq_mutation = iq_mutation;
for (uint16_t i = 0; i < n_cand; i++) {
for (uint16_t j = 0; j < n_params; j++) {
opt->candidates[i][j] = start_params[j];
}
opt->loss[i] = 0;
}
uint32_t seed = local_time() + (ADC1->DR & 0xFF);
srand(seed);
return 0;
}
/**
* @brief Один шаг эволюционного оптимизатора.
* @param opt Указатель на структуру оптимизатора
* @param params Массив параметров, которые будут обновлены (на выходе — новые параметры)
* @param loss Loss текущего кандидата (Q16.16)
* @return 0 — если окей,
* -1 — если ошибка
* @details
* Сохраняет loss текущего кандидата и формирует параметры следующего кандидата.
* Если накоплено n_cand кандидатов, генерируется новое поколение.
* Новое поколение формируется случайным выбором из n_best лучших с добавлением мутации.
*
* На выходе params содержит параметры следующего кандидата для измерений.
* @note Функция использует глобальную внутреннюю переменную для сортировки.
* Надо убедится что только один экземпляр функции запущен в момент времени
*/
__STATIC_INLINE int EvolveOptimizer_Step(EvolveOptimizer_t* opt,
int32_t* params,
int32_t loss)
{
if((opt = NULL) || (params == NULL))
return -1;
uint16_t n_params = opt->n_params;
if(n_params > EVOLVE_MAX_PARAMS)
return -1;
uint16_t n_cand = opt->n_cand;
if(n_cand > EVOLVE_MAX_CANDIDATES)
return -1;
uint16_t n_best = opt->n_best;
if(n_best > EVOLVE_MAX_CANDIDATES/2)
return -1;
uint16_t mut = opt->iq_mutation;
if(mut > 32768)
return -1;
// 1. Сохраняем loss текущего кандидата
opt->loss[opt->cand_index] = loss;
opt->cand_index++;
if (opt->cand_index >= n_cand) {
// 2. Сортируем текущее поколение по loss
for(uint16_t i = 0; i < opt->n_cand; i++)
opt->sorted_idx[i] = i;
g_sort_opt = opt;
qsort(opt->sorted_idx, opt->n_cand, sizeof(uint16_t), cmp_idx);
g_sort_opt = NULL;
// for (uint16_t i = 0; i < n_cand - 1; i++) {
// for (uint16_t j = i + 1; j < n_cand; j++) {
// if (opt->loss[j] < opt->loss[i]) {
// int32_t tmp_loss = opt->loss[i];
// opt->loss[i] = opt->loss[j];
// opt->loss[j] = tmp_loss;
// for (uint16_t k = 0; k < n_params; k++) {
// int32_t tmp = opt->candidates[i][k];
// opt->candidates[i][k] = opt->candidates[j][k];
// opt->candidates[j][k] = tmp;
// }
// }
// }
// }
// 3. Генерируем новое поколение: каждый кандидат берется случайно из лучших с мутацией
uint16_t n_elite = 2; // количество элитных кандидатов, которые сохраняем без изменений
for (uint16_t c = 0; c < n_cand; c++) {
if (c < n_elite) {
// Копируем лучших кандидатов напрямую без мутации
for (uint16_t i = 0; i < n_params; i++) {
opt->candidates[c][i] = opt->candidates[opt->sorted_idx[c]][i]; // просто сохраняем параметры
}
opt->loss[c] = 0;
} else {
// Остальные кандидаты формируются с кроссовером и мутацией
for (uint16_t i = 0; i < n_params; i++) {
int32_t noise = (rand() % (2 * mut)) - mut;
uint16_t parent = opt->sorted_idx[rand() % opt->n_best]; // каждый параметр из случайного лучшего
opt->candidates[c][i] = opt->candidates[parent][i] + noise;
}
opt->loss[c] = 0;
}
}
opt->cand_index = 0;
}
// 4. Возвращаем параметры следующего кандидата
for (uint16_t i = 0; i < opt->n_params; i++)
params[i] = opt->candidates[opt->cand_index][i];
return 0;
}
#else // ENABLE_EVOLVE_OPTIMIZATION
//заглушки
typedef struct {
uint16_t n_params;
uint16_t n_cand;
uint16_t n_best;
uint16_t iq_mutation;
int32_t loss[0];
int32_t candidates[0][0];
} EvolveOptimizer_t;
#define EvolveOptimizer_Init(opt, n_params, n_cand, n_best, iq_mutation, start_params)
#define EvolveOptimizer_Step(opt, params, LossFunc)
#define PARAM_SCALE_Q16(x, min_val, max_val) (x)
#define PARAM_UNSCALE_Q16(q16_val, min_val, max_val) (q16_val)
#endif // ENABLE_EVOLVE_OPTIMIZATION
#endif // __EVOLVE_OPTIMIZER_H_
/** EVOLVE_OPTIMIZER
* @}
*/
EVOLVE_MAX_CANDIDATES
#define EVOLVE_MAX_CANDIDATES
Максимальное количество кандидатов для обучения
Definition mylibs_config.h:66
EVOLVE_MAX_PARAMS
#define EVOLVE_MAX_PARAMS
Максимальное количество параметров
Definition mylibs_config.h:65
EvolveOptimizer_Step
__STATIC_INLINE int EvolveOptimizer_Step(EvolveOptimizer_t *opt, int32_t *params, int32_t loss)
Один шаг эволюционного оптимизатора.
Definition evolve_optimizer.h:187
local_time
#define local_time()
Локальное время
Definition evolve_optimizer.h:81
EvolveOptimizer_Init
__STATIC_INLINE int EvolveOptimizer_Init(EvolveOptimizer_t *opt, uint16_t n_params, uint16_t n_cand, uint16_t n_best, uint16_t iq_mutation, int32_t *start_params)
Инициализация эволюционного оптимизатора.
Definition evolve_optimizer.h:132
mylibs_defs.h
Заголочный файл для дефайнов библиотеки MyLibsGeneral.
EvolveOptimizer_t
Структура эволюционного оптимизатора
Definition evolve_optimizer.h:87
EvolveOptimizer_t::cand_index
uint16_t cand_index
Индекс кандидата для обработки
Definition evolve_optimizer.h:92
EvolveOptimizer_t::n_params
uint16_t n_params
Количество параметров
Definition evolve_optimizer.h:88
EvolveOptimizer_t::iq_mutation
uint16_t iq_mutation
Амплитуда мутации в Q16.16.
Definition evolve_optimizer.h:91
EvolveOptimizer_t::candidates
int32_t candidates[100][20]
Параметры кандидатов
Definition evolve_optimizer.h:94
EvolveOptimizer_t::sorted_idx
uint16_t sorted_idx[100]
Индексы отсортированных кандидатов
Definition evolve_optimizer.h:95
EvolveOptimizer_t::n_best
uint16_t n_best
Количество лучших, усредняемых
Definition evolve_optimizer.h:90
EvolveOptimizer_t::n_cand
uint16_t n_cand
Количество кандидатов
Definition evolve_optimizer.h:89
EvolveOptimizer_t::loss
int32_t loss[100]
Loss для каждого кандидата
Definition evolve_optimizer.h:93