Skocz do zawartości

Autozerowanie i wyliczenie wartości skutecznej - potrzebne poprawki w kodzie.


Pomocna odpowiedź

Napisano (edytowany)

Cześć. Buduję urządzenie które będzie mierzyło prąd za pomocą ASC712 oraz ESP32S3. Ponieważ chcę aby to mogło odbywać się zarówno dla przebiegu zmiennego jak i stałego założyłem użycie pomiaru wartości skutecznej. Matematykę i algorytm częściowo napisał model Ai od googla, jednak mam pewne problemy ponieważ założyłem że układ potrafi sam się wyzerować, nie wszystko działa według oczekiwań.

Idea jest taka że kiedy przekaźnik odłączy obciążenie, ma działać zerowanie. w momencie kiedy obciążenie zostaje załączone następuje pomiar właściwy. Niestety nie udało mi się do tej pory na tyle tego wykalibrować aby zero było faktycznie zerem, lub przynajmniej blisko tego:
 

// --- KONFIGURACJA SPRZĘTU (GPIO/ADC) ---
#define RELAY               GPIO_NUM_6
 #define CURR_ADC_UNIT       ADC_UNIT_1
 #define CURR_ADC_CHANNEL    ADC_CHANNEL_0
 #define ADC_MAX_STORE_BUF_SIZE 1024
 #define ADC_CONV_FRAME_SIZE    1024

// // --- PARAMETRY POMIAROWE I FILTRY ---
 #define RMS_WINDOW             2000    // 100ms przy 20kHz
 #define DEADBAND               0.1f    // minimalny sygnał
 #define OFFSET_FILTER_WEIGHT   0.01f
 #define RMS_FILTER_ALPHA       0.2f
 #define CURRENT_SCALE          0.038f
// #define OFFSET_MAX_STEP        50.0f
 #define OFFSET_BROADCAST_INTERVAL_MS 500
  
  // --- ZMIENNE STANU POMIARÓW ---
float dynamic_offset = 0.0f;
float sum_sq = 0.0f;
int total_samples = 0;

// Funkcja konfigurująca i inicjalizująca tryb ciągły
void init_adc_continuous(void)
{
    // 1. Inicjalizacja uchwytu (przydział pamięci i buforów DMA)
    adc_continuous_handle_cfg_t alloc_cfg = {
        .max_store_buf_size = ADC_MAX_STORE_BUF_SIZE,
        .conv_frame_size = ADC_CONV_FRAME_SIZE,
    };
    ESP_ERROR_CHECK(adc_continuous_new_handle(&alloc_cfg, &continuous_adc_handle));

    // 2. Konfiguracja "wzorca" (pattern) - czyli listy kanałów do odczytu
    // My mamy tylko jeden kanał, ale układ pozwala na sekwencyjne czytanie wielu pinów
    adc_digi_pattern_config_t adc_pattern[1] = {0};
    adc_pattern[0].atten = ADC_ATTEN_DB_12;
    adc_pattern[0].channel = CURR_ADC_CHANNEL;
    adc_pattern[0].unit = CURR_ADC_UNIT;
    adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;// 12-bit dla ESP32-S3

    // 3. Główna konfiguracja trybu ciągłego
    adc_continuous_config_t dig_cfg = {
        .pattern_num = 1,
        .adc_pattern = adc_pattern,
        .sample_freq_hz = 20000, // Częstotliwość próbkowania: 20 kHz
        .conv_mode = ADC_CONV_SINGLE_UNIT_1, // Używamy tylko ADC1
        .format = ADC_DIGI_OUTPUT_FORMAT_TYPE2, // ESP32-S3 używa formatu danych TYPE2
    };

    ESP_ERROR_CHECK(adc_continuous_config(continuous_adc_handle, &dig_cfg));
};

static void adcTask(void * arg)
{
    init_adc_continuous();
    ESP_ERROR_CHECK(adc_continuous_start(continuous_adc_handle));
    //int sw_last_state = 0;
    float rms_filtered = 0.0f;   // RMS po filtrze wygładzającym
    static uint8_t result_buf[ADC_CONV_FRAME_SIZE];
    static uint32_t ret_num = 0;
    TickType_t last_offset_broadcast = 0;  // ostatni czas wysłania offsetu
    while(1)
    {
            // Odczyt danych ADC z DMA
    esp_err_t ret = adc_continuous_read(
                        continuous_adc_handle,
                        result_buf,
                        ADC_CONV_FRAME_SIZE,
                        &ret_num,
                        0);

    if (ret == ESP_OK)
    {
        int count = ret_num / SOC_ADC_DIGI_RESULT_BYTES;

                
        int relay = get_set_relay_status(-1);

        // 
        static int prev_relay = -1;
        if (relay != prev_relay)
        {
            sum_sq = 0.0f;
            total_samples = 0;
            rms_filtered = 0.0f;
            prev_relay = relay;
        }


        for (int i = 0; i < count; i++)
        {
            adc_digi_output_data_t *p =
                (adc_digi_output_data_t*)&result_buf[i * SOC_ADC_DIGI_RESULT_BYTES];

            float raw_val = (float)p->type2.data;


            // =====================================
            // Kalibracja offsetu w tle
            // =====================================
            if (0 == get_set_relay_status(-1))
            {
                // Filtr IIR offsetu (powolna adaptacja)
               // dynamic_offset += (raw_val - dynamic_offset) * OFFSET_FILTER_WEIGHT;
                   dynamic_offset += (raw_val - dynamic_offset) * OFFSET_FILTER_WEIGHT;
                    
            // reset RMS AC+DC przy wyłączeniu przekaźnika
            //    rms_filtered = 0.0f;
            //    sum_sq = 0.0f;
            //    total_samples = 0;
            
            
            
            }

            // =====================================
            // Pomiar RMS AC+DC (przekaźnik ON)
            // =====================================
            if (1 == get_set_relay_status(-1))
            {
                float val = raw_val - dynamic_offset;
                sum_sq += val * val;
                total_samples++;

                if (total_samples >= RMS_WINDOW)
                {
                    float rms = sqrtf(sum_sq / total_samples);

                    if (rms < DEADBAND)
                        rms = 0.0f;

                    // Filtr RMS
                    rms_filtered = (1.0f - RMS_FILTER_ALPHA) * rms_filtered + RMS_FILTER_ALPHA * rms;

                    //ESP_LOGI(TAG, "Dynamic Offset: %.2f  RMS AC+DC: %.2f (filtered: %.2f)",
                    //         dynamic_offset, rms, rms_filtered);

                    sum_sq = 0.0f;
                    total_samples = 0;
                }
            }

            // =====================================
            // Broadcast offset co ~0.5s, niezależnie od przekaźnika
            // =====================================
            TickType_t now = xTaskGetTickCount();
            if ((now - last_offset_broadcast) * portTICK_PERIOD_MS >= OFFSET_BROADCAST_INTERVAL_MS)
            {
               
               float xAdc =  rms_filtered * CURRENT_SCALE; 
                xQueueOverwrite(xQueueAdcHandle,&xAdc);
            
                xTaskNotify(xLogicTaskHandle, BIT_QUEUE, eSetBits); 
               
                last_offset_broadcast = now;
                

               
            }
        }
    }
    else if (ret == ESP_ERR_TIMEOUT)
    {
        // Oddaj CPU, żeby WiFi/BLE działały
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    }
}



chrome_5fmDStTFDI.thumb.png.ba45a0ae5e4b2ff79425f6a5c1f74100.png
 

chrome_v2lLaJTK5T.png

Problem ujawnia się kiedy załączam pomiar a na ASC nie jest podany żaden sygnał, wartość nigdy nie spada do zera więc jakby nie było to brane pod uwagę.

Edytowano przez _LM_

A wziąłeś pod uwagę, że dla czujnika  ACS711 napięcie na wyjściu przy zerowym przepływie prądu wynosi dokładnie połowę napięcia zasilania ?
 

(edytowany)
11 minut temu, jand napisał:

ACS711 napięcie na wyjściu przy zerowym przepływie prądu wynosi dokładnie połowę napięcia zasilania ?

Wziąłem, rezystory w dzielniku są tak dobrane żeby nie przekroczyć zakresu ADC dodatkowy kondensator zapewnia ładunek dla przetwornika jak i filtr dla f > 100Hz

Mógłbym również wpisać tam stałą wartość offsetu ale wolałem skorzystać z możliwości wyliczenia tego 

Edytowano przez _LM_

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...