
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
//-------------------------------------------------------//
// Project Code : V2H6K01-23-ENEMAN
// File Name : RoutineTsamp.cpp
// Created on : 2023. 8. 8.
// Description :
// Author : KimJeongWoo
// Last modified Date :
//-------------------------------------------------------//
#include "Cpu1DeviceDefine.h"
#include <numeric> // std::accumulate와 std::inner_product를 위해 필요
#include <vector>
#include <cmath> // For sqrt() and std::abs()
int Testpcs4 = 0;
int Adc_BUTTON = 0;
int Chk_Botton = 0;
int Chk_Botton_pre = 0;
// 순환 버퍼
#define BUFFER_SIZE 10
#include <cmath> // For sqrt() and std::abs() // 10 이상 커지면 순간적인 변화를 계산하지 못함?
int currentIndex = 0;
int UV_buffer[BUFFER_SIZE];
int VIS_buffer[BUFFER_SIZE];
int IR_buffer[BUFFER_SIZE];
// 이전 센서 값 저장을 위한 변수 초기화
int CH4_UV_prev = 0, CH4_VIS_prev = 0, CH4_IR_prev = 0;
// 변화량을 저장할 배열
int UV_change[BUFFER_SIZE], VIS_change[BUFFER_SIZE], IR_change[BUFFER_SIZE];
int prev_avg = 0;
//////////////////////////////////////////////////////////
// 큐 구조체 정의
typedef struct {
int items[BUFFER_SIZE];
int front;
int rear;
int size;
double total; // 총합을 저장하기 위한 변수
int lastValue; // 마지막으로 추가된 값
} Queue;
// 큐 초기화 함수
void initQueue(Queue *q) {
q->front = 0;
q->rear = -1;
q->size = 0;
q->total = 0;
q->lastValue = 0; // 초기화 시 마지막 값은 0으로 가정
memset(q->items, 0, sizeof(q->items));
}
// 큐에 데이터 추가 및 누적 계산 수행 함수
void enqueueAndUpdateStats(Queue *q, int value) {
// 이전 값 저장
int prevValue = (q->size > 0) ? q->items[q->rear] : 0;
// 큐에 데이터 추가
if (q->size == BUFFER_SIZE) {
// 큐가 꽉 찼을 때, 가장 오래된 데이터를 빼고 새 데이터 추가
q->total -= q->items[q->front]; // 총합에서 가장 오래된 데이터 제거
q->front = (q->front + 1) % BUFFER_SIZE;
} else {
q->size++;
}
q->rear = (q->rear + 1) % BUFFER_SIZE;
q->items[q->rear] = value;
q->total += value; // 새 값 추가로 총합 업데이트
// 마지막 값 업데이트
q->lastValue = value;
// 평균 및 변화량 계산은 필요에 따라 진행
}
// 큐에서 데이터 제거 함수 (이 예제에서는 사용하지 않음)
int dequeue(Queue* q) {
if (q->size == 0) {
// printf("Queue is empty\n");
return -1;
}
else {
int item = q->items[q->front];
q->front = (q->front + 1) % BUFFER_SIZE;
q->size--;
return item;
}
}
////////////////////////////////////////////////////////
// 큐 내 데이터의 평균을 계산하는 함수
double calculateAverage(Queue* q) {
int sum = 0;
int i = 0;
if (q->size > 0) {
int idx = (q->front + i) % BUFFER_SIZE;
sum += q->items[idx];
i++;
}
return q->size > 0 ? (double)sum / q->size : 0;
}
// 큐 내 모든 데이터의 평균 변화량을 계산하는 함수
double calculateAverageChange(Queue* q) {
if (q->size < 2) {
// 큐에 데이터가 2개 미만일 때는 평균 변화량을 계산할 수 없음
return 0.0;
}
int currentIdx = q->front;
int nextIdx = (currentIdx + 1) % BUFFER_SIZE;
int changeSum = q->items[nextIdx] - q->items[currentIdx];
int count = 1;
while (nextIdx != q->rear) {
currentIdx = nextIdx;
nextIdx = (nextIdx + 1) % BUFFER_SIZE;
int currentChange = q->items[nextIdx] - q->items[currentIdx];
changeSum += currentChange;
count++;
}
// 평균 변화량 계산
return (double)changeSum / count;
}
////////////////////////////////////////////////////////////////////////////
// 상관 계수를 계산하는 함수
double calculate_correlation(const int* x, const int* y, int n) {
long long sum_x = std::accumulate(x, x + n, 0LL);
long long sum_y = std::accumulate(y, y + n, 0LL);
long long sum_x2 = std::inner_product(x, x + n, x, 0LL);
long long sum_y2 = std::inner_product(y, y + n, y, 0LL);
long long sum_xy = std::inner_product(x, x + n, y, 0LL);
double numerator = (double)n * sum_xy - sum_x * sum_y;
double denominator = sqrt(((double)n * sum_x2 - sum_x * sum_x) * ((double)n * sum_y2 - sum_y * sum_y));
if (denominator == 0)
return 0; // 분모가 0이면, 상관관계를 계산할 수 없음
return numerator / denominator;
}
double calculateCorrelationFromQueues(Queue* q1, Queue* q2) {
if (q1->size != q2->size || q1->size < 2) {
// 큐의 크기가 다르거나 데이터 포인트가 2개 미만이면 계산할 수 없음
return 0;
}
int n = q1->size;
long long sumX = 0, sumY = 0, sumX2 = 0, sumY2 = 0, sumXY = 0;
for (int i = 0; i < n; ++i) {
int idx1 = (q1->front + i) % BUFFER_SIZE;
int idx2 = (q2->front + i) % BUFFER_SIZE;
int x = q1->items[idx1];
int y = q2->items[idx2];
sumX += x;
sumY += y;
sumX2 += x * x;
sumY2 += y * y;
sumXY += x * y;
}
double numerator = n * sumXY - sumX * sumY;
// 상관 계수를 계산하는 함수 내에서 sqrt 사용 시 타입 명확히 하기
double denominator = sqrt(static_cast<double>((n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY)));
if (denominator == 0) {
// 분모가 0이면, 상관관계를 계산할 수 없음
return 0;
}
return numerator / denominator;
}
// 변화량의 크기를 계산하는 함수
double calculate_change_magnitude(const int* change_array, int n) {
double sum = 0.0;
for (int i = 0; i < n; i++) {
sum += std::abs(change_array[i]); // 변화량의 절대값을 더함
}
return sum / n; // 평균을 반환
}
double calculateChangeMagnitudeFromQueue(Queue* q) {
if (q->size < 2) {
// 큐에 데이터가 2개 미만일 때는 변화량을 계산할 수 없음
return 0.0;
}
double changeSum = 0;
int prev = q->items[q->front]; // 시작 요소를 이전 요소로 설정
for (int i = 1; i < q->size; ++i) {
int idx = (q->front + i) % BUFFER_SIZE; // 순환 인덱싱
int current = q->items[idx]; // 현재 요소
changeSum += std::abs(current - prev); // 이전 요소와의 차이(변화량)의 절대값 더하기
prev = current; // 현재 요소를 다음 루프의 이전 요소로 설정
}
return changeSum / (q->size - 1); // 변화량의 평균 반환
}
void calculateAverageStddevAndAdaptiveThresholdFromQueue(Queue* q, double& avg, double& stddev, double& adaptive_threshold) {
if (q->size == 0) {
// 큐가 비어있으면 계산 불가
avg = 0;
stddev = 0;
adaptive_threshold = 0;
return;
}
// 평균 계산
double sum = 0;
for (int i = 0; i < q->size; ++i) {
int idx = (q->front + i) % BUFFER_SIZE;
sum += q->items[idx];
}
avg = sum / q->size;
// 표준 편차 계산
double sum_sq_diff = 0;
for (int i = 0; i < q->size; ++i) {
int idx = (q->front + i) % BUFFER_SIZE;
double diff = q->items[idx] - avg;
sum_sq_diff += diff * diff;
}
stddev = sqrt(sum_sq_diff / q->size);
// 적응형 임계값 설정
adaptive_threshold = avg + 2 * stddev;
}
/////////////////////////////////////////////////////////////////////////////////////
void RoutineTsamp() {
static Queue uvQueue;
static Queue visQueue;
static Queue irQueue;
static int initialized = 0;
if (!initialized) {
initQueue(&uvQueue);
initQueue(&visQueue);
initQueue(&irQueue);
initialized = 1;
}
Lpf1stRun();
// if (Testpcs4 == 1)
// {
// EepromWriteAdcScale();
// Testpcs4 = 0;
// }
// if (Testpcs4 == 2)
// {
// EepromReadAdcScale();
// Testpcs4 = 0;
// }
ModbusACheckBuffer();
// 새 센서 값 추가
enqueueAndUpdateStats(&uvQueue, CH4_UV_Flt);
enqueueAndUpdateStats(&visQueue, CH4_VIS_Flt);
enqueueAndUpdateStats(&irQueue, CH4_IR_Flt);
// /////////////////////////////////////////////
// UV_buffer[currentIndex] = CH4_UV_Flt; // 배열에 센싱값 저장
// VIS_buffer[currentIndex] = CH4_VIS_Flt; // 배열에 센싱값 저장
// IR_buffer[currentIndex] = CH4_IR_Flt; // 배열에 센싱값 저장
//
// // 센서 값 갱신 및 변화량 계산
// UV_change[currentIndex] = CH4_UV_Flt - CH4_UV_prev; // UV 변화량 계산
// VIS_change[currentIndex] = CH4_VIS_Flt - CH4_VIS_prev; // VIS 변화량 계산
// IR_change[currentIndex] = CH4_IR_Flt - CH4_IR_prev; // IR 변화량 계산
//
// // 현재 값을 '이전 값'으로 저장
// CH4_UV_prev = CH4_UV_Flt;
// CH4_VIS_prev = CH4_VIS_Flt;
// CH4_IR_prev = CH4_IR_Flt;
//
// currentIndex = (currentIndex + 1) % BUFFER_SIZE; // 인덱스 갱신
if (CH4_UV_Flt > CH4_UV_max)
CH4_UV_max = CH4_UV_Flt; // 새로운 최대값 발견 시 갱신
if (CH4_VIS_Flt > CH4_VIS_max)
CH4_VIS_max = CH4_VIS_Flt; // 새로운 최대값 발견 시 갱신
if (CH4_IR_Flt > CH4_IR_max)
CH4_IR_max = CH4_IR_Flt; // 새로운 최대값 발견 시 갱신
FaultChecker();
Chk_Botton = Din.Data.bit.Button;
if ((Chk_Botton_pre == 0) && (Chk_Botton == 1)) {
FaultReset = 1;
}
else {
FaultReset = 0;
}
Chk_Botton_pre = Chk_Botton;
// // 임계값을 넘었을 때만 계산
// if (SystemFault == 1) {
// uv_vis_correlation = calculate_correlation(UV_buffer, VIS_buffer, BUFFER_SIZE);
// uv_ir_correlation = calculate_correlation(UV_buffer, IR_buffer, BUFFER_SIZE);
// vis_ir_correlation = calculate_correlation(VIS_buffer, IR_buffer, BUFFER_SIZE);
uv_vis_correlation = calculateCorrelationFromQueues(&uvQueue, &visQueue);
uv_ir_correlation = calculateCorrelationFromQueues(&uvQueue, &irQueue);
vis_ir_correlation = calculateCorrelationFromQueues(&visQueue, &irQueue);
// 변화량의 크기 계산
// uv_change_magnitude = calculate_change_magnitude(UV_change, BUFFER_SIZE);
// vis_change_magnitude = calculate_change_magnitude(VIS_change, BUFFER_SIZE);
// ir_change_magnitude = calculate_change_magnitude(IR_change, BUFFER_SIZE);
uv_change_magnitude = calculateChangeMagnitudeFromQueue(&uvQueue);
vis_change_magnitude = calculateChangeMagnitudeFromQueue(&visQueue);
ir_change_magnitude = calculateChangeMagnitudeFromQueue(&irQueue);
// UV 평균과 표준 편차 계산
// double sum = 0, sum_sq_diff = 0;
// for (int i = 0; i < BUFFER_SIZE; ++i) {
// sum += UV_buffer[i];
// sum_sq_diff += (UV_buffer[i] - (sum / BUFFER_SIZE)) * (UV_buffer[i] - (sum / BUFFER_SIZE));
// }
// double avg = sum / BUFFER_SIZE;
// stddev = sqrt(sum_sq_diff / BUFFER_SIZE);
// adaptive_threshold = avg + 2 * stddev;
calculateAverageStddevAndAdaptiveThresholdFromQueue(&uvQueue, avg, stddev, adaptive_threshold);
// 최신 값과 바로 이전 값 사이의 변화율 계산을 위한 인덱스 계산
// int latest_index = (currentIndex - 1 + BUFFER_SIZE) % BUFFER_SIZE;
// int prev_index = (latest_index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
// latest_change = UV_buffer[latest_index] - UV_buffer[prev_index];
// latest_change = avg - prev_avg;
// prev_avg = avg;
// if (abs(latest_change) > adaptive_threshold) {
// // 변화율이 적응형 임계값을 초과하는 경우 처리
// // 예: 알림 발송, 로깅, 경고 등
// SET_FT_UV_Level = adaptive_threshold;
// }
// }
}