[feat] add quadratic and calc concentration by pp value

This commit is contained in:
zhji 2024-08-25 18:33:19 +08:00
parent e12afdc85a
commit 98ae861a70
9 changed files with 132 additions and 145 deletions

View File

@ -24,7 +24,7 @@ add_definitions(-DUSE_STDPERIPH_DRIVER)
enable_language(ASM)
add_executable(${PROJ_NAME}.elf main.c)
target_sources(${PROJ_NAME}.elf PUBLIC start.S)
target_sources(${PROJ_NAME}.elf PUBLIC ${CMAKE_CURRENT_LIST_DIR}/start.S)
add_subdirectory(../driver driver)
target_link_libraries(${PROJ_NAME}.elf driver)

View File

@ -175,7 +175,7 @@ void adc_loop(void)
val = adc_det_temp_from_ltc1867;
}
#endif
debug_write_data(DEBUG_CH_ADC_RAW + ch, (float)val);
// debug_write_data(DEBUG_CH_ADC_RAW + ch, (float)val);
adc_input_data(ch, val); /* input data from ADC to sort buffer */
if (ch == 0) {
val = adc_get_filter_data(ch);
@ -184,19 +184,19 @@ void adc_loop(void)
#else
value = adc_rtot(val);
#endif
debug_write_data(DEBUG_CH_ADC_FILTER + ch, (float)value);
// debug_write_data(DEBUG_CH_ADC_FILTER + ch, (float)value);
device_data.detector_temperature = value;
ch = 1;
} else if (ch == 1) {
val = adc_get_filter_data(ch);
value = adc_rtot(val);
debug_write_data(DEBUG_CH_ADC_FILTER + ch, (float)value);
// debug_write_data(DEBUG_CH_ADC_FILTER + ch, (float)value);
device_data.lamp_temperature = value;
ch = 3;
} else if (ch == 3) {
val = adc_get_filter_data(ch);
value = (uint32_t)val * 6600 / 4096;
debug_write_data(DEBUG_CH_ADC_FILTER + ch, (float)value);
// debug_write_data(DEBUG_CH_ADC_FILTER + ch, (float)value);
device_data.lamp_voltage = value;
ch = 0;
} else {

View File

@ -2,7 +2,7 @@
#define __CALC_H__
#define NUM_TYPE float
#define CALC_POINTS (128)
#define CALC_POINTS (32)
/* y = a * x^2 + b * x + c */
struct quadratic_coefficient_s {

View File

@ -6,8 +6,7 @@
#endif
#define LEDIR_FREQ (8)
#define SAMPLES_PER_PERIOD (64)
#define CALC_CNT (SAMPLES_PER_PERIOD / 2)
#define SAMPLES_PER_PERIOD (256)
#ifdef __cplusplus
}

View File

@ -14,13 +14,12 @@
#define DEBUG_UART_BAUDRATE (2 * 1000 * 1000)
#define DEBUG_CH_RAW (0 * 4)
#define DEBUG_CH_SUM_1 (1 * 4)
#define DEBUG_CH_SUM_2 (2 * 4)
#define DEBUG_CH_MEDIAN (3 * 4)
#define DEBUG_CH_WINDOW (4 * 4)
#define DEBUG_CH_ADC_RAW (5 * 4)
#define DEBUG_CH_ADC_FILTER (6 * 4)
#define DEBUG_CHAN_MAX (7 * 4)
#define DEBUG_CH_QUADRATIC (1 * 4)
#define DEBUG_CH_MEDIAN (2 * 4)
#define DEBUG_CH_WINDOW (3 * 4)
// #define DEBUG_CH_ADC_RAW (4 * 4)
// #define DEBUG_CH_ADC_FILTER (5 * 4)
#define DEBUG_CHAN_MAX (4 * 4)
struct debug_data_s {
uint8_t enable;

View File

@ -1,13 +1,10 @@
#include "filter.h"
#include "ltc1867.h"
#include "calc.h"
#include "device.h"
#include "debug.h"
#include "user_misc.h"
static uint32_t sum_gas1[FILTER_SUM_LEN_GAS1] __attribute__((section(".bss_ccm")));
static uint32_t sum_gas2[FILTER_SUM_LEN_GAS2] __attribute__((section(".bss_ccm")));
static uint32_t sum_gas3[FILTER_SUM_LEN_GAS3] __attribute__((section(".bss_ccm")));
static uint32_t sum_gas4[FILTER_SUM_LEN_GAS4] __attribute__((section(".bss_ccm")));
static struct list_s median_gas1[FILTER_MEDIAN_LEN_GAS1] __attribute__((section(".bss_ccm")));
static struct list_s median_gas2[FILTER_MEDIAN_LEN_GAS2] __attribute__((section(".bss_ccm")));
static struct list_s median_gas3[FILTER_MEDIAN_LEN_GAS3] __attribute__((section(".bss_ccm")));
@ -22,26 +19,18 @@ struct data_filter_s data_filter[4] __attribute__((section(".bss_ccm")));
void filter_init(void)
{
/* data_filter parameter init */
data_filter[0].sum_len = FILTER_SUM_LEN_GAS1;
data_filter[0].sum_buff = sum_gas1;
data_filter[0].median_len = FILTER_MEDIAN_LEN_GAS1;
data_filter[0].median_buff = median_gas1;
data_filter[0].window_len = FILTER_WINDOW_LEN_GAS1;
data_filter[0].window_buff = window_gas1;
data_filter[1].sum_len = FILTER_SUM_LEN_GAS2;
data_filter[1].sum_buff = sum_gas2;
data_filter[1].median_len = FILTER_MEDIAN_LEN_GAS2;
data_filter[1].median_buff = median_gas2;
data_filter[1].window_len = FILTER_WINDOW_LEN_GAS2;
data_filter[1].window_buff = window_gas2;
data_filter[2].sum_len = FILTER_SUM_LEN_GAS3;
data_filter[2].sum_buff = sum_gas3;
data_filter[2].median_len = FILTER_MEDIAN_LEN_GAS3;
data_filter[2].median_buff = median_gas3;
data_filter[2].window_len = FILTER_WINDOW_LEN_GAS3;
data_filter[2].window_buff = window_gas3;
data_filter[3].sum_len = FILTER_SUM_LEN_GAS4;
data_filter[3].sum_buff = sum_gas4;
data_filter[3].median_len = FILTER_MEDIAN_LEN_GAS4;
data_filter[3].median_buff = median_gas4;
data_filter[3].window_len = FILTER_WINDOW_LEN_GAS4;
@ -50,14 +39,6 @@ void filter_init(void)
for (uint8_t i = 0; i < 4; i++) {
uint16_t len;
/* sum filter init */
len = data_filter[i].sum_len;
for (uint16_t j = 0; j < len; j++) {
data_filter[i].sum_buff[j] = 0;
}
data_filter[i].sum_sum = 0;
data_filter[i].sum_idx = 0;
/* media filter init */
data_filter[i].median_idx = 0;
len = data_filter[i].median_len;
@ -91,29 +72,27 @@ void filter_init(void)
flag.filter_climb = FILTER_WINDOW_LEN_GAS1 + FILTER_MEDIAN_LEN_GAS1;
}
void filter_input_data(uint8_t channel, uint32_t data)
void filter_quadratic_process(void)
{
data_filter[channel].input = data;
}
void filter_sum_process(void)
{
uint32_t sum, val;
uint16_t idx;
struct quadratic_coefficient_s coeff;
float rative, peak;
uint32_t pos_ravine, pos_peak;
pos_ravine = data_ltc1867.pos_ravine + SAMPLES_PER_PERIOD / 4 - CALC_POINTS / 2;
pos_peak = data_ltc1867.pos_peak + SAMPLES_PER_PERIOD / 4 - CALC_POINTS / 2;
for (uint8_t i = 0; i < 4; i++) {
idx = data_filter[i].sum_idx;
sum = data_filter[i].sum_sum;
val = data_filter[i].input;
debug_write_data(DEBUG_CH_SUM_1 + i, (float)val);
sum = sum - data_filter[i].sum_buff[idx];
data_filter[i].sum_buff[idx] = val;
sum = sum + val;
data_filter[i].sum_sum = sum;
debug_write_data(DEBUG_CH_SUM_2 + i, (float)(data_filter[i].sum_sum));
data_filter[i].sum_idx++;
if (data_filter[i].sum_idx >= data_filter[i].sum_len) {
data_filter[i].sum_idx = 0;
calc_quadratic_fit(data_ltc1867.p_calc[i] + pos_ravine, &coeff, CALC_POINTS);
rative = coeff.c - coeff.b * coeff.b / (4.0f * coeff.a);
calc_quadratic_fit(data_ltc1867.p_calc[i] + pos_peak, &coeff, CALC_POINTS);
peak = coeff.c - coeff.b * coeff.b / (4.0f * coeff.a);
data_filter[i].raw_f = peak - rative;
debug_write_data(DEBUG_CH_QUADRATIC + i, data_filter[i].raw_f);
if (data_filter[i].raw_f < 0.0f) {
data_filter[i].raw_u = 0;
} else if (data_filter[i].raw_f >= 65535.0f) {
data_filter[i].raw_u = 65535;
} else {
data_filter[i].raw_u = (uint32_t)(data_filter[i].raw_f);
}
}
}
@ -131,7 +110,7 @@ void filter_median_process(void)
list->prev->next = list->next; /* connect prev to next */
list->next->prev = list->prev; /* connect next to prev */
/* add new node */
data = data_filter[i].sum_sum;
data = data_filter[i].raw_u;
data_filter[i].median_buff[idx].data = data;
len = data_filter[i].median_len + 1;
data_filter[i].head.data = 0xFFFFFFFF;
@ -207,7 +186,7 @@ void filter_loop(void)
return;
}
flag.filter = data_ltc1867.calc_flag;
filter_sum_process();
filter_quadratic_process();
filter_median_process();
filter_window_process();
filter_output_process();

View File

@ -7,11 +7,6 @@
#include "stm32f4xx.h"
#define FILTER_SUM_LEN_GAS1 (8 * 2)
#define FILTER_SUM_LEN_GAS2 (8 * 2)
#define FILTER_SUM_LEN_GAS3 (8 * 2)
#define FILTER_SUM_LEN_GAS4 (8 * 2)
#define FILTER_MEDIAN_LEN_GAS1 (128)
#define FILTER_MEDIAN_LEN_GAS2 (64)
#define FILTER_MEDIAN_LEN_GAS3 (64)
@ -29,12 +24,8 @@ struct list_s {
};
struct data_filter_s {
uint32_t input;
uint16_t sum_len;
uint16_t sum_idx;
uint32_t *sum_buff;
uint32_t sum_sum;
float raw_f;
uint32_t raw_u;
uint16_t median_len;
uint16_t median_idx;
@ -50,8 +41,7 @@ struct data_filter_s {
};
extern void filter_init(void);
extern void filter_input_data(uint8_t channel, uint32_t data);
extern void filter_sum_process(void);
extern void filter_quadratic_process(void);
extern void filter_median_process(void);
extern void filter_window_process(void);
extern void filter_output_process(void);

View File

@ -10,10 +10,9 @@
#include "stm32f4xx_tim.h"
#include "stm32f4xx_spi.h"
#define diff32768(data) ((data > 32768) ? (data - 32768) : (32768 - data))
float data_ltc1867_raw[2][4][SAMPLES_PER_PERIOD * 2] __attribute__((section(".bss_ccm")));
struct data_ltc1867_s data_ltc1867 __attribute__((section(".bss_ccm")));
static const uint16_t ltc1867_spi_data[LTC1867_CH_CNT] = {0xC400, 0x9400, 0xD400, 0xA400, 0x8400}; /* order: ch1, ch2, ch3, ch4, ch0 */
__attribute__((section(".data_ccm"))) uint16_t ltc1867_spi_data[LTC1867_CH_CNT] = {0xC400, 0x9400, 0xD400, 0xA400, 0x8400}; /* order: ch1, ch2, ch3, ch4, ch0 */
void ltc1867_init(void)
{
@ -101,15 +100,14 @@ void ltc1867_init(void)
ltc1867_transfer(ltc1867_spi_data[LTC1867_CH_CNT - 1]);
/* data_ltc1867 init */
data_ltc1867.sum[0] = 0; /* store temporary sum of half period sum */
data_ltc1867.sum[1] = 0;
data_ltc1867.sum[2] = 0;
data_ltc1867.sum[3] = 0;
data_ltc1867.calc_flag = 0; /* half period complete, need calc */
data_ltc1867.calc_cnt = 0;
data_ltc1867.calc_flag = 0; /* 2 period complete, need calc */
data_ltc1867.ledir_cnt = 0; /* index of led count, for togglr IR led */
data_ltc1867.val_idx = 0; /* index of value in half period, for sum */
data_ltc1867.warm = SAMPLES_PER_PERIOD * LEDIR_FREQ; /* in first 1s, only toggle IR led, discard sample ADC value */
data_ltc1867.locked = 0; /* zero point capture */
data_ltc1867.state_idx = 0; /* index for search point of 32768 */
for (uint8_t i = 0; i < 4; i++) {
data_ltc1867.p_samp[i] = data_ltc1867_raw[0][i];
data_ltc1867.p_calc[i] = data_ltc1867_raw[1][i];
}
}
void ltc1867_ledir_on(void)
@ -175,17 +173,19 @@ uint16_t ltc1867_transfer(uint16_t data_send)
void TIM2_IRQHandler(void)
{
static uint16_t pre_ref = 0;
uint16_t val[LTC1867_CH_CNT];
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
/* for control led IR */
data_ltc1867.ledir_cnt++;
if (data_ltc1867.ledir_cnt == (SAMPLES_PER_PERIOD / 2)) {
if ((data_ltc1867.ledir_cnt == (SAMPLES_PER_PERIOD / 2)) || \
(data_ltc1867.ledir_cnt == (SAMPLES_PER_PERIOD / 2 * 3))) {
ltc1867_ledir_on();
} else if (data_ltc1867.ledir_cnt >= SAMPLES_PER_PERIOD) {
} else if ((data_ltc1867.ledir_cnt == (SAMPLES_PER_PERIOD)) || \
(data_ltc1867.ledir_cnt == (SAMPLES_PER_PERIOD * 2))) {
ltc1867_ledir_off();
data_ltc1867.ledir_cnt = 0;
}
/* sample 5 channel adc data */
@ -195,66 +195,81 @@ void TIM2_IRQHandler(void)
ltc1867_spi_select(); /* convert complete, make convert pin low for reading sample data by SPI */
val[i] = ltc1867_transfer(ltc1867_spi_data[i]); /* read convert data and send next channel information */
}
/* split 2 for loop, because sample timing is strict, only place important code in sample duration */
/* ltc1867 original sample data */
for (uint8_t i = 0; i < 4; i++) {
data_ltc1867.sum[i] += diff32768(val[i]); /* add every channel original data for next process */
debug_write_data(DEBUG_CH_RAW + i, (float)val[i]); /* channel 0~3 for ltc1867 original sample data */
}
adc_det_temp_from_ltc1867 = val[4]; /* channel 4 for ltc1867 detector temperature sample data */
data_ltc1867.val_idx++;
if ((data_ltc1867.val_idx >= CALC_CNT) && (data_ltc1867.locked != 0)) {
data_ltc1867.val_idx = 0;
if (cli_data_comb.force_available & CLI_FORCE_FILTER_INPUT1_MASK) {
filter_input_data(0, cli_data_comb.force_data[CLI_FORCE_FILTER_INPUT1] / FILTER_SUM_LEN_GAS1);
} else {
filter_input_data(0, data_ltc1867.sum[0]);
}
if (cli_data_comb.force_available & CLI_FORCE_FILTER_INPUT2_MASK) {
filter_input_data(1, cli_data_comb.force_data[CLI_FORCE_FILTER_INPUT2] / FILTER_SUM_LEN_GAS2);
} else {
filter_input_data(1, data_ltc1867.sum[1]);
}
if (cli_data_comb.force_available & CLI_FORCE_FILTER_INPUT3_MASK) {
filter_input_data(2, cli_data_comb.force_data[CLI_FORCE_FILTER_INPUT3] / FILTER_SUM_LEN_GAS3);
} else {
filter_input_data(2, data_ltc1867.sum[2]);
}
if (cli_data_comb.force_available & CLI_FORCE_FILTER_INPUT4_MASK) {
filter_input_data(3, cli_data_comb.force_data[CLI_FORCE_FILTER_INPUT4] / FILTER_SUM_LEN_GAS4);
} else {
filter_input_data(3, data_ltc1867.sum[3]);
}
data_ltc1867.sum[0] = 0;
data_ltc1867.sum[1] = 0;
data_ltc1867.sum[2] = 0;
data_ltc1867.sum[3] = 0;
data_ltc1867.calc_flag++;
float val_f = (float)val[i]; /* convert to float */
data_ltc1867.p_samp[i][data_ltc1867.ledir_cnt - 1] = val_f;
debug_write_data(DEBUG_CH_RAW + i, val_f);
}
if (data_ltc1867.warm > 0) {
/* in warm stage */
data_ltc1867.warm--;
} else {
/* warm complete */
if (data_ltc1867.locked > 0) {
/* nothing, normal running state */
} else {
/* has not locked wave */
static uint16_t pre_ref = 32768;
/* channel 4 for ltc1867 detector temperature sample data */
adc_det_temp_from_ltc1867 = val[4];
/* search point of 32768 */
if ((pre_ref < 32768) && (val[0] >= 32768)) {
/* meet lock condition */
data_ltc1867.sum[0] = diff32768(val[0]);
data_ltc1867.sum[1] = diff32768(val[1]);
data_ltc1867.sum[2] = diff32768(val[2]);
data_ltc1867.sum[3] = diff32768(val[3]);
data_ltc1867.val_idx = 1;
data_ltc1867.locked = 1;
} else {
/* not meet lock condition */
data_ltc1867.state_pos[data_ltc1867.state_idx] = data_ltc1867.ledir_cnt - 1;
data_ltc1867.state_edge[data_ltc1867.state_idx++] = 1; /* 1 for rising edge */
} else if ((pre_ref >= 32768) && (val[0] < 32768)) {
data_ltc1867.state_pos[data_ltc1867.state_idx] = data_ltc1867.ledir_cnt - 1;
data_ltc1867.state_edge[data_ltc1867.state_idx++] = 0; /* 0 for falling edge */
}
pre_ref = val[0];
/* 2 cycle complete */
if (data_ltc1867.ledir_cnt >= SAMPLES_PER_PERIOD * 2) {
float *p;
/* exchange pointor of calc/samp data */
for (uint8_t i = 0; i < 4; i++) {
p = data_ltc1867.p_calc[i];
data_ltc1867.p_calc[i] = data_ltc1867.p_samp[i];
data_ltc1867.p_samp[i] = p;
}
/* ledir count need empty */
data_ltc1867.ledir_cnt = 0;
data_ltc1867.calc_cnt++;
/* check whether the data meets requirements */
if (data_ltc1867.state_idx == 4) {
if ((data_ltc1867.state_pos[0] < SAMPLES_PER_PERIOD / 4) && \
(data_ltc1867.state_pos[1] >= SAMPLES_PER_PERIOD / 2) && (data_ltc1867.state_pos[1] < SAMPLES_PER_PERIOD / 4 * 3) && \
(data_ltc1867.state_pos[2] >= SAMPLES_PER_PERIOD) && (data_ltc1867.state_pos[2] < SAMPLES_PER_PERIOD / 4 * 5) && \
(data_ltc1867.state_pos[3] >= SAMPLES_PER_PERIOD / 2 * 3) && (data_ltc1867.state_pos[3] < SAMPLES_PER_PERIOD / 4 * 7)) {
/* pos is head */
if ((data_ltc1867.state_edge[0] == 0) && (data_ltc1867.state_edge[1] == 1) && (data_ltc1867.state_edge[2] == 0) && (data_ltc1867.state_edge[3] == 1)) {
data_ltc1867.state = 1; /* first ravine late */
data_ltc1867.pos_peak = data_ltc1867.state_pos[1];
data_ltc1867.pos_ravine = data_ltc1867.state_pos[2];
data_ltc1867.calc_flag++; /* trig calc */
} else if ((data_ltc1867.state_edge[0] == 1) && (data_ltc1867.state_edge[1] == 0) && (data_ltc1867.state_edge[2] == 1) && (data_ltc1867.state_edge[3] == 0)) {
data_ltc1867.state = 3; /* first peak late */
data_ltc1867.pos_ravine = data_ltc1867.state_pos[1];
data_ltc1867.pos_peak = data_ltc1867.state_pos[2];
data_ltc1867.calc_flag++; /* trig calc */
}
} else if ((data_ltc1867.state_pos[0] >= SAMPLES_PER_PERIOD / 4) && (data_ltc1867.state_pos[0] < SAMPLES_PER_PERIOD / 2) && \
(data_ltc1867.state_pos[1] >= SAMPLES_PER_PERIOD / 4 * 3) && (data_ltc1867.state_pos[1] < SAMPLES_PER_PERIOD) && \
(data_ltc1867.state_pos[2] >= SAMPLES_PER_PERIOD / 4 * 5) && (data_ltc1867.state_pos[2] < SAMPLES_PER_PERIOD / 2 * 3) && \
(data_ltc1867.state_pos[3] >= SAMPLES_PER_PERIOD / 4 * 7) && (data_ltc1867.state_pos[3] < SAMPLES_PER_PERIOD *2)) {
/* pos is later */
if ((data_ltc1867.state_edge[0] == 0) && (data_ltc1867.state_edge[1] == 1) && (data_ltc1867.state_edge[2] == 0) && (data_ltc1867.state_edge[3] == 1)) {
data_ltc1867.state = 2; /* first peak ahead */
data_ltc1867.pos_ravine = data_ltc1867.state_pos[0];
data_ltc1867.pos_peak = data_ltc1867.state_pos[1];
data_ltc1867.calc_flag++; /* trig calc */
} else if ((data_ltc1867.state_edge[0] == 1) && (data_ltc1867.state_edge[1] == 0) && (data_ltc1867.state_edge[2] == 1) && (data_ltc1867.state_edge[3] == 0)) {
data_ltc1867.state = 0; /* first ravine ahead */
data_ltc1867.pos_peak = data_ltc1867.state_pos[0];
data_ltc1867.pos_ravine = data_ltc1867.state_pos[1];
data_ltc1867.calc_flag++; /* trig calc */
}
}
}
data_ltc1867.state_idx = 0;
}
cali_flash_write();
debug_send_frame();
}

View File

@ -25,12 +25,17 @@
#define PIN_SPI_SDI (GPIO_Pin_7)
struct data_ltc1867_s {
uint32_t sum[4]; /* store temporary sum of half period sum */
uint32_t calc_flag; /* half period complete, need calc */
uint32_t calc_flag; /* double period complete, need calc */
uint32_t calc_cnt; /* totle count of double period complete */
uint16_t ledir_cnt; /* index of led count, for togglr IR led */
uint16_t val_idx; /* index of value in half period, for sum */
uint16_t warm; /* in first 1s, only toggle IR led, discard sample ADC value */
uint8_t locked; /* 32768 point capture */
uint8_t state; /* 0~3 is available, 0:first ravine ahead, 1:first ravine late, 2:first peak ahead, 3:first peak late */
uint8_t state_idx; /* 0~3 is available, sample 4 times of point 32768 */
uint8_t state_edge[4]; /* 0 or 1 is available, 0:falling edge, 1:rising edge */
uint16_t state_pos[4]; /* position of every edge, 0~(SAMPLES_PER_PERIOD*2-1) is available */
uint16_t pos_ravine; /* position of ravine */
uint16_t pos_peak; /* position of peak */
float *p_calc[4]; /* pointor for calculation */
float *p_samp[4]; /* pointor for store sample data */
};
extern struct data_ltc1867_s data_ltc1867;