chun sung Park 2024-03-13
Queue Test
Tsamp - 순환 버퍼처럼 쓰던 배열을 큐로 바꿔서 교차 상관, 변화량 계산 다시 구현해서 Test
교차 상관 계산 범위가 -1~1의 범위를 벗어남
@2338ba20710f77cebc7e0fb6967332db20c7695b
ArcCTRL-23-NEXTSQ-CPU1/Main_Resource/source/FaultProcess.cpp
--- ArcCTRL-23-NEXTSQ-CPU1/Main_Resource/source/FaultProcess.cpp
+++ ArcCTRL-23-NEXTSQ-CPU1/Main_Resource/source/FaultProcess.cpp
@@ -9,6 +9,8 @@
 
 #include "Cpu1DeviceDefine.h"
 
+int FT_chk = 0;
+
 void InitFaultSet()
 {
 	memset(&Fault, 0, (sizeof(Fault) / sizeof(int)));
@@ -230,7 +232,7 @@
 	Dout.Data.bit.Ch00 = 1;
     Dout.Data.bit.Ch01 = 1;
 
-    if(FT_uv_vis_correlation == 0)
+    if(FT_chk == 0)
     {
         FT_uv_vis_correlation = uv_vis_correlation;
         FT_uv_ir_correlation = uv_ir_correlation;
@@ -240,9 +242,15 @@
         FT_uv_ir_change_correlation = uv_ir_change_correlation;
         FT_vis_ir_change_correlation = vis_ir_change_correlation;
 
+        FT_uv_change_magnitude = uv_change_magnitude;
+        FT_vis_change_magnitude = vis_change_magnitude;
+        FT_ir_change_magnitude = ir_change_magnitude;
+
         FT_stddev = stddev;
         FT_adaptive_threshold = adaptive_threshold;
         FT_latest_change = latest_change;
+
+        FT_chk = 1;
     }
 
 
@@ -430,8 +438,14 @@
     FT_uv_ir_change_correlation = 0;
     FT_vis_ir_change_correlation = 0;
 
+    FT_uv_change_magnitude = 0;
+    FT_vis_change_magnitude = 0;
+    FT_ir_change_magnitude = 0;
+
     FT_stddev = 0;
     FT_adaptive_threshold = 0;
     FT_latest_change = 0;
+
+    FT_chk = 0;
 }
 
ArcCTRL-23-NEXTSQ-CPU1/Main_Resource/source/RoutineTsamp.cpp
--- ArcCTRL-23-NEXTSQ-CPU1/Main_Resource/source/RoutineTsamp.cpp
+++ ArcCTRL-23-NEXTSQ-CPU1/Main_Resource/source/RoutineTsamp.cpp
@@ -6,17 +6,20 @@
 //              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 Testpcs4 = 0;
+int Adc_BUTTON = 0;
 
- int Chk_Botton = 0;
- int Chk_Botton_pre = 0;
+int Chk_Botton = 0;
+int Chk_Botton_pre = 0;
 
-//순환 버퍼
-#define BUFFER_SIZE 5       //10 이상 커지면 순간적인 변화를 계산하지 못함?
+// 순환 버퍼
+#define BUFFER_SIZE 10
+#include <cmath> // For sqrt() and std::abs()           // 10 이상 커지면 순간적인 변화를 계산하지 못함?
 int currentIndex = 0;
 
 int UV_buffer[BUFFER_SIZE];
@@ -28,119 +31,329 @@
 
 // 변화량을 저장할 배열
 int UV_change[BUFFER_SIZE], VIS_change[BUFFER_SIZE], IR_change[BUFFER_SIZE];
-int prev_avg =0;
+int prev_avg = 0;
 
-// 상관 계수를 계산하는 함수
-double calculate_correlation(const int *x, const int *y, int n) {
-    long long sum_x = 0, sum_y = 0, sum_x2 = 0, sum_y2 = 0, sum_xy = 0;
-    for (int i = 0; i < n; ++i) {
-        sum_x += x[i];
-        sum_y += y[i];
-        sum_x2 += (long long)x[i] * x[i];
-        sum_y2 += (long long)y[i] * y[i];
-        sum_xy += (long long)x[i] * y[i];
+//////////////////////////////////////////////////////////
+// 큐 구조체 정의
+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이면, 상관관계를 계산할 수 없음
+
+    if (denominator == 0)
+        return 0; // 분모가 0이면, 상관관계를 계산할 수 없음
+
     return numerator / denominator;
 }
 
-void RoutineTsamp()
-{
-
-//	PllRun();
-	Lpf1stRun();
-	FaultChecker();
-
-	if(Testpcs4 == 1)
-	{
-	    EepromWriteAdcScale();
-	    Testpcs4 = 0;
-	}
-    if(Testpcs4 == 2)
-    {
-        EepromReadAdcScale();
-        Testpcs4 = 0;
+double calculateCorrelationFromQueues(Queue* q1, Queue* q2) {
+    if (q1->size != q2->size || q1->size < 2) {
+        // 큐의 크기가 다르거나 데이터 포인트가 2개 미만이면 계산할 수 없음
+        return 0;
     }
 
-//    receivedChar = SCI_readCharBlockingFIFO(SCIC_BASE);
-//    SCI_writeCharBlockingFIFO(SCIC_BASE, receivedChar);
+    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))
-    {
+    if ((Chk_Botton_pre == 0) && (Chk_Botton == 1)) {
         FaultReset = 1;
     }
-    else
-    {
+    else {
         FaultReset = 0;
     }
     Chk_Botton_pre = Chk_Botton;
 
-    /////////////////////////////////////////////
-    UV_buffer[currentIndex] = CH4_UV_Flt; // 배열에 센싱값 저장
-    VIS_buffer[currentIndex] = CH4_VIS_Flt; // 배열에 센싱값 저장
-    IR_buffer[currentIndex] = CH4_IR_Flt; // 배열에 센싱값 저장
+//    // 임계값을 넘었을 때만 계산
+//     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[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 변화량 계산
+         // 변화량의 크기 계산
+//         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);
 
-    // 현재 값을 '이전 값'으로 저장
-    CH4_UV_prev = CH4_UV_Flt;
-    CH4_VIS_prev = CH4_VIS_Flt;
-    CH4_IR_prev = CH4_IR_Flt;
+         // 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;
 
-    currentIndex = (currentIndex + 1) % BUFFER_SIZE; // 인덱스 갱신
+            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;
 
-    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;    // 새로운 최대값 발견 시 갱신
+         // latest_change = UV_buffer[latest_index] - UV_buffer[prev_index];
+         // latest_change = avg - prev_avg;
+         // prev_avg = avg;
 
-    // 버퍼가 한 바퀴 돌았을 때 상관 계수 계산
-     if (currentIndex == 0)
-     {
-         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_change_correlation = calculate_correlation(UV_change, VIS_change, BUFFER_SIZE);
-        uv_ir_change_correlation = calculate_correlation(UV_change, IR_change, BUFFER_SIZE);
-        vis_ir_change_correlation = calculate_correlation(VIS_change, IR_change, BUFFER_SIZE);
-
-
-        // 평균과 표준 편차 계산
-        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;
-
-        // 최신 값과 바로 이전 값 사이의 변화율 계산을 위한 인덱스 계산
-        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;
-        }
-     }
+         // if (abs(latest_change) > adaptive_threshold) {
+         //     // 변화율이 적응형 임계값을 초과하는 경우 처리
+         //     // 예: 알림 발송, 로깅, 경고 등
+         //     SET_FT_UV_Level = adaptive_threshold;
+         // }
+//     }
 }
-
 
Common_Resource/CommonLibrary/include/SystemVar.h
--- Common_Resource/CommonLibrary/include/SystemVar.h
+++ Common_Resource/CommonLibrary/include/SystemVar.h
@@ -82,6 +82,10 @@
 extern double uv_ir_change_correlation;
 extern double vis_ir_change_correlation;
 
+extern double uv_change_magnitude;
+extern double vis_change_magnitude;
+extern double ir_change_magnitude;
+
 extern double FT_uv_vis_correlation;
 extern double FT_uv_ir_correlation;
 extern double FT_vis_ir_correlation;
@@ -94,10 +98,17 @@
 extern double adaptive_threshold;
 extern int latest_change;
 
+extern double FT_uv_change_magnitude;
+extern double FT_vis_change_magnitude;
+extern double FT_ir_change_magnitude;
+
 extern double FT_stddev;
 extern double FT_adaptive_threshold;
 extern int FT_latest_change;
 
+extern double avg;
+extern double stddev;
+extern double adaptive_threshold;
 extern int SystemReady;
 //
 //extern int FlagInvGating;
Add a comment
List