You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

262 lines
9.4 KiB

#include "ozone_control_service.h"
#include "../zes8p5066lib/basic.h"
#include "../zes8p5066lib/systicket.h"
#include "frequency_sweep_service.h"
#include "kalmanFilter.h"
#include "state_machine.h"
//
#include "least_square_method.h"
/**
* @brief
*
* 状态机:
* 不工作 ------> 扫描频率 ----> 工作
*
**/
#define PRV_START_EVENT (STATE_MACHINE_PUBLIC_EVENT + 1)
#define PRV_STOP_EVENT (STATE_MACHINE_PUBLIC_EVENT + 2)
state_machine_state_t m_states[] = {
[kIdleState] =
{
.name = "kIdleState",
.stateId = kIdleState,
},
[kBeforeWorkingStateSweepFrequency] =
{
.name = "kBeforeWorkingStateSweepFrequency",
.stateId = kBeforeWorkingStateSweepFrequency,
},
[kWorkingState] = //
{
.name = "kWorkingState",
.stateId = kWorkingState,
}
//
};
state_machine_t m_statemachine;
static ozone_control_working_state_t s_workingstate;
static uint16_t get_resonant_frequency(uint16_t startfreq, uint16_t step, uint16_t endfreq) {
/**
* @brief
* 计算谐振频率,频率和功率的图像接近下图,由此可知,当设备工作正常时,在一定频率范围内,查找功率最小的点即可。
*
* http://192.168.1.3:3000/project_ozone_generator/doc/src/branch/master/ref/20220815频率-功率关系图.png
*/
float minpower = 0;
uint16_t retfreq = 0;
bool inited = false;
for (uint16_t freq = startfreq; freq <= endfreq; freq += step) {
float power = frequency_sweep_get_power(freq);
if (!inited) {
minpower = power;
retfreq = freq;
inited = true;
continue;
}
if (power < minpower) {
minpower = power;
retfreq = freq;
}
}
return retfreq;
}
static KFP KFPConfig = KALMAN_FILTER_PARA;
static float __mf_get_ozone_power() {
float powersum = 0;
for (size_t i = 0; i < 10; i++) {
powersum += port_adc_get_ozone_generator_power();
}
return powersum / 10;
}
static void mf_get_ozone_power_reset_filter() { KFPConfig.LastP = __mf_get_ozone_power(); }
static float mf_get_ozone_power() { return kalmanFilter(&KFPConfig, __mf_get_ozone_power()); }
float get_expect_power() {
float expectpower = 0;
if (thisDevice.level == klevel1) {
expectpower = LEVEL1_EXPECT_POWER;
} else if (thisDevice.level == klevel2) {
expectpower = LEVEL2_EXPECT_POWER;
}
return expectpower;
}
static float gety(int x) { return frequency_sweep_get_power((uint16_t)x); }
static float compute_slope(uint16_t startfreq, uint16_t step, uint16_t endfreq) {
float k = 0;
float c = 0;
least_square_method(startfreq, step, endfreq, gety, &c, &k);
return k;
}
static float compute_avarage_power(uint16_t startfreq, uint16_t step, uint16_t endfreq) {
float sumpower = 0;
int count = 0;
for (uint16_t freq = startfreq; freq <= endfreq; freq += step) {
count++;
float power = frequency_sweep_get_power(freq);
sumpower += power;
}
return sumpower / count;
}
static state_machine_state_t* processBeforeWorkingStateSweepFrequency(state_machine_t* machine, state_machine_state_t* nowstate, int event) {
/**
* @brief 扫频
*/
if (event == ENTER_STATE) {
frequency_sweep_start(20000, 100, 41000, 3000);
} else if (event == TIME_EVENT) {
if (frequency_sweep_is_finished()) {
s_workingstate.resonant_frequency = get_resonant_frequency(25000, 100, 35000); //谐振频率点
s_workingstate.slope_when_freq40k = compute_slope(39000, 100, 41000); //利用最小二乘法计算出45K频率的斜率
s_workingstate.avarage_power = compute_avarage_power(20000, 100, 41000); //平均功率
printf("----------Summarize--------\n");
printf("-resonant_frequency: %d\n", s_workingstate.resonant_frequency);
printf("-slope_when_freq40k: %f\n", s_workingstate.slope_when_freq40k);
printf("-avarage_power : %f\n", s_workingstate.avarage_power);
s_workingstate.nowfreq = s_workingstate.resonant_frequency;
return &m_states[kWorkingState];
}
} else if (event == EXIT_STATE) {
frequency_sweep_stop();
}
return NULL;
}
static state_machine_state_t* processWorkingState(state_machine_t* machine, state_machine_state_t* nowstate, int event) {
/**
* @brief 检查当前功率是否正常
*
* 当功率在期望功率窗口之外时候([expertpower+window,expertpower-window]),
* 开始调整当前频率,直到功率接近期望功率。
*/
if (event == ENTER_STATE) {
/**
* @brief 在谐振点启动,此时臭氧功率最小
*/
if (s_workingstate.nowfreq < s_workingstate.resonant_frequency) {
s_workingstate.nowfreq = s_workingstate.resonant_frequency;
}
port_ozone_pwm_set_duty(s_workingstate.nowfreq, 5000);
port_ozone_pwm_start();
s_workingstate.adjustedToTheProperPower = false;
mf_get_ozone_power_reset_filter();
printf("----------start working--------\n");
} else if (event == TIME_EVENT) {
float nowpower = mf_get_ozone_power();
// float fanpower = mf_fan_get_power();
if (s_workingstate.adjustedToTheProperPower) {
/**
* 检查当前功率是否在期望功率窗口之外时候([expertpower+window,expertpower-window]),
*/
// printf("change freq [ no ],freq %d, ozonePower %f-->%f fanPower:%f\n", s_workingstate.nowfreq, nowpower, get_expect_power(), fanpower);
if (nowpower < (get_expect_power() - EXPECT_POWER_WINDONWS) || //
nowpower > (get_expect_power() + EXPECT_POWER_WINDONWS)) {
s_workingstate.adjustedToTheProperPower = false;
if (nowpower < get_expect_power()) {
s_workingstate.changefreqdirection = true;
} else {
s_workingstate.changefreqdirection = false;
}
}
} else {
/**
* 调整功率到期望功率
*/
if (s_workingstate.changefreqdirection) {
if (nowpower < get_expect_power()) {
s_workingstate.nowfreq += 25;
if (s_workingstate.nowfreq > MAX_FREQ) s_workingstate.nowfreq = MAX_FREQ;
printf("change freq [ up ],freq %d, ozonePower %f-->%f\n", s_workingstate.nowfreq, nowpower, get_expect_power());
port_ozone_pwm_set_duty(s_workingstate.nowfreq, kconst_pwm_work_dutyns);
} else {
// printf("reach %f->%f\n", nowpower, get_expect_power());
s_workingstate.adjustedToTheProperPower = true;
}
} else {
if (nowpower > get_expect_power()) {
s_workingstate.nowfreq -= 25;
if (s_workingstate.nowfreq < s_workingstate.resonant_frequency) s_workingstate.nowfreq = s_workingstate.resonant_frequency;
printf("change freq [down],freq %d, ozonePower %f-->%f\n", s_workingstate.nowfreq, nowpower, get_expect_power());
port_ozone_pwm_set_duty(s_workingstate.nowfreq, kconst_pwm_work_dutyns);
} else {
// printf("reach %f->%f\n", nowpower, get_expect_power());
s_workingstate.adjustedToTheProperPower = true;
}
}
}
} else if (event == EXIT_STATE) {
port_ozone_pwm_stop();
}
return NULL;
}
static state_machine_state_t* state_machine_process_event(state_machine_t* machine, state_machine_state_t* nowstate, int event) {
/**
* @brief 处理Start和Stop事件
*/
if (event == PRV_START_EVENT || event == PRV_STOP_EVENT) {
if (event == PRV_START_EVENT) {
printf("start\n");
return &m_states[kBeforeWorkingStateSweepFrequency];
} else {
printf("stop\n");
return &m_states[kIdleState];
}
}
/**
* @brief 处理其他事件
*/
if /* */ (nowstate == &m_states[kIdleState]) {
} else if (nowstate == &m_states[kBeforeWorkingStateSweepFrequency]) {
return processBeforeWorkingStateSweepFrequency(machine, nowstate, event);
} else if (nowstate == &m_states[kWorkingState]) {
return processWorkingState(machine, nowstate, event);
}
return NULL;
}
/***********************************************************************************************************************
* ======================================================Export======================================================= *
***********************************************************************************************************************/
void ozone_control_init() { state_machine_init(&m_statemachine, m_states, ZARR_SIZE(m_states), state_machine_process_event); }
void ozone_control_start() { state_machine_trigger_event(&m_statemachine, PRV_START_EVENT); }
void ozone_control_stop() { state_machine_trigger_event(&m_statemachine, PRV_STOP_EVENT); }
void ozone_control_schedule() {
static uint32_t ticket = 0;
if (systicket_haspassedms(ticket) > 10) {
ticket = systicket_get_now_ms();
state_machine_schedule_each10ms(&m_statemachine);
}
frequency_sweep_schedule();
}
ozone_control_working_state_id_t ozone_control_get_working_state_id() {
if (state_machine_get_now_state(&m_statemachine) == &m_states[kIdleState]) {
return kIdleState;
}
if (state_machine_get_now_state(&m_statemachine) == &m_states[kBeforeWorkingStateSweepFrequency]) {
return kBeforeWorkingStateSweepFrequency;
}
if (state_machine_get_now_state(&m_statemachine) == &m_states[kWorkingState]) {
return kWorkingState;
}
return kIdleState;
}
ozone_control_working_state_t* ozone_control_get_working_state() { return &s_workingstate; }
float ozone_control_get_ozone_power() { return mf_get_ozone_power(); }
float ozone_control_get_expect_power() { return get_expect_power(); }
// float ozone_control_get_fan_power() { return mf_fan_get_power(); }