Thông báo

Collapse
No announcement yet.

Xin giúp đỡ về vấn đề tìm trị đỉnh sóng sin ?

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Xin giúp đỡ về vấn đề tìm trị đỉnh sóng sin ?

    Mình dùng mạch chỉnh lưu chính xác kết hợp
    khuếch đại để lấy ra sóng dạng sin bán kì tần số 50Hz mình đã đo ossillo ( tín hiệu từ CT) mình mới học avr nên còn gà lám mong các bạn góp ý cho code của mình .vì phần này làm miết mà kô chạy sai tùm lum ah.
    mình không dùng thêm phần cứng để tìm trị đỉnh cũng như dò zero tất cả đều dùng soft để giải quyết. vấn đề truyền 485 cũng như quét led hiển thị trên board dùng spi đã chạy rất oke.

    - Vấn đề nan giải còn lại như mình đã nói là quét tìm trị đỉnh để tính ra trị hiệu dụng . do mình dùng atmega8 nên tín hiệu ra từ chỉnh lưu bán kì +khếch đại được đưa qua phân kênh analog 4052 nên dù có tới 6 CT mình cũng chỉ dùng 2 ADC0 và ADC1 thôi còn các ADC khác mình dùng như là các I/O để điều khiển chọn kênh cũng như hiển thị quét led.

    - Bình thường khi không có tín hiệu từ cảm biến tức không có gắn tải vô mạch thì ngõ ra ADC đọc về vẫn có giá trị khác 0 chưa kể vân đề sai số của adc 10bit ( do vậy vấn đề muốn tìm điểm zero là bỏ mình không có ý định designe lại board) với ADC 10 bit thì có thể cho độ phân giải đến 4.8mV với Vreff 5V.

    - vì mình chỉ định thiết kế với tải ngõ vào là (200mA -- >5A ) nên ngõ vào của ADC khuếch đại lên với tải nhỏ nhất cũng hơn 100mV rồi.

    ==> Hướng giải quyết của mình :
    // đọc giá trị ADC ban đầu và so sánh xem nó có lớn hơn 10mV không ( tại bán kì không được chỉnh lưu vẫn có áp chừng 10mV chẳng hạn, tại bán kì có chỉnh lưu thì sẽ là 10mV+ V_rectifier_amp).

    code: int backup;
    unsigned char pa_flag;
    if( pa_flag == 0) // chưa có mẫu nào
    {
    samp_1 = ADCW ; // dọc lần đầu.
    backup = samp_1;
    samp_1 = samp_1*5000/1024; // đổi ra mV
    if(samp_1 < 10) // nếu nhỏ hơn 10mV
    samp_1 = 0; // bỏ mẫu ban đầu lấy đi
    else
    { // giữ lại mẫu ban đầu
    samp_1 = backup;
    // thiết lập một biến để báo đã lấy được mẫu đầu tiên
    pa_flag = 1;
    }
    }
    else // đã có mẫu
    if( samp_1 < ACDW ) // ta đang lấy mẫu ở bên trái sườn sóng sin (giá trị sau lớn hơn trước)
    // lưu tiếp mẫu mới này
    samp_1 = ADCW;

    else // trường hợp này xảy ra khi ta lấy mẫu ở bên phải sườn sóng sin.
    // hoặc là sóng từ sườn trái đi qua phải ?
    // nếu là trường hợp thứ 2 từ trái đi sang phải thì mình giữ nguyên mẫu trươc đó.
    V_peak = samp_1;
    // vậy là bài toán tìm trị đỉnh đã được giải quyết bằng soft.
    nhưng vấn đề cũng phát sinh chính trong đoạn
    Code:
     else  // trường hợp này xảy ra khi ta lấy mẫu ở bên phải sườn sóng sin.
                                         // hoặc là sóng từ sườn trái đi qua phải ? 
                                         // nếu là trường hợp thứ 2 từ trái đi sang phải thì mình giữ nguyên mẫu trươc đó.
                                         V_peak = samp_1;
    đó chỉ có 1 khả năng được xảy ra trong 2 khả năng xảy ra vậy muốn biết khả năng nào xảy ra thì sao ? và cái khả năng không mong muốn là ta đang lấy mẫu tại sườn phải sẽ giải quyết tiếp ra sao.
    chưa kể chuyện ở khoảng gần trị đỉnh cho là mỗi lần lấy mẫu mất 100us đi thì giá trị giữa 2 lần lấy mẫu thây đổi còn nhỏ hơn cả độ phân giải của ADC 10bit kết hợp với sai số của ADC 10bit sẽ gây hiểu nhầm và lấy lộn đỉnh sóng hoặc kô dò được. điều này khá nguy hiểm khi kết hợp nó với do pha.
    Mong các bạn cho hướng giải quết


    chỉnh lưu lý tưởng :

  • #2
    Ngay đỉnh sin tín hiệu là hằng số kéo dài nên lấy được chính xác đỉnh sin là cả vấn đề, phải xử lý nhiễu đầu vào, nhiễu ADC cho tốt và lấy trung bình nhiều mẫu thì bạn mới có thể lấy chính xác đỉnh. Còn về cái thuật toán thì bạn phải lấy mẫu hàng loạt mẫu đến khi gặp đỉnh thì mới dừng được, tôi thấy chtr của bạn có thể làm theo cách này
    bool sườn_phải=1;
    mẫu_trước= ADCW;
    delay(xx);
    while (sườn_phải){ //bắt đầu ở sườn phải
    mẫu_sau=ADCW;
    if (mẫu_sau>mẫu_trước) sườn_phải=0; //chuyển sang sườn trái
    mẫu_trước= mẫu_sau;
    };

    while(!sườn_phải) { //đang ở sườn trái
    mẫu_sau=ADCW;
    if (mẫu_sau==mẫu_trước) đỉnh=mẫu sau;
    mẫu_trước= mẫu_sau;
    }
    như đã nói có thể dò được trong vùng đỉnh sin nhưng độ chính xác thì bạn phải thử mới biết. chờ hết vòng lặp while thứ hai phát ra một xung và dò trên osc xem cái xung này có khớp với đỉnh không, nếu không thì sửa code
    Đã bỏ nghề về quê chăn gà...

    Comment


    • #3
      Code mình xử lý cũng tương tự bạn nhưng kết quả không được như ý muốn vậy là hai ý tưởng gặp nhau rồi nhỉ !.. trong chương trình mình dùng ngắt ADC để giải quết thuật toán so sánh và không dùng delay để chờ ( chuyển đổi xong ADC) hoặc ổn định... vì chương trình của mình còn lo xủ lý truyền thông quyét led nên hầu hết mình dùng ngắt để xử lý.. nếu mình lấy mẫu liên tục rồi lấy trung bình + do pha thì vấn đề lại khá nặng cho chương trình không.. vì khi trên cp gửi xuống yêu cầu lấy dữ liệu từ ngoại vi gửi lên hoặc ngắt ngoài trên board yêu cầu quét CT khác thì vấn đề thời gian có đảm bảo không.

      -- phải bám theo tín hiệu nên việc đợi và có một mẫu mới được xử lý tốn hơn 20ms một tí đi (50HZ - chỉnh lưu bán kì) ... vậy là với 50 mẫu mình mất 1s không ổn. vậy cõ khoảng 10 mẫu tính toán cho là mất 250ms .. ==> được U_peak , I_peak, cosphi

      Comment


      • #4
        với tín hiệu 220 mình dùng lun cái biến áp này cấp nguồn cho board mạch và lấy áp trước chỉnh lưu (12vac --> cầu phân áp đưa qua chỉnh lưu chính xác --> phân kênh analog --> adc).. + mẹo thì nó giao động ( 1020...1021,1023...1019...........ADC 10 bit).. nếu không kết hợp cái mẹo này thì (500,1020,,,900,..1023..vv).

        - Tuy nhiên mình nghĩ đến một khả năng lấy sai rất lớn do VDK hiểu nhầm đỉnh :

        lấy ví dụ như sau : mau_n = ADCW. ( dk sườn trái)
        mau_(n+1) = ADCW ( thực tế sóng vẫn đang ở sườn trái)
        --> tuy nhiên do hai mẫu quá gần nhau nhỏ hơn độ phân giải của adc 10 BIT dẫn đến nó không tăng giá trị )

        vd : v_(n) = 3,000v ... v_(n+1) = 3.004v (ADC 10bit 5v/1024 ~ 4.88v)
        ADCW _(n) có đảm bảo là nhỏ hơn hoặc bằng ADCW_(n+1) không
        ở trường hợp này rất có thể là ADC_(n+1) < ADC_(n) ==> hiểu nhầm là sóng vừa vượt qua đỉnh trong khi thực tế không phải vậy == > hiểu nhầm đỉnh sóng do ADC 10 bit có sai số.
        để loại trừ sai số mình định sẽ bỏ đi 2 bít cuối như sau
        samp_1 |= 0x0003;
        samp_2 = ADCW;
        samp_2 |= 0x0003;
        // rồi đem so sánh vậy là chấp nhận bỏ đi 2 bít cuối nhưng vẫn không được kết quả như ý không biết là lệnh trên nó có thao tác rồi tách ra 8 bit để làm không vì mấy biến kia 16 ko nhưng trình dịch không báo gì cả.
        if( samp_1 < samp_2)
        ==> vẫn ở sườn trái lúc này là chắc chắn lun nhỉ ?

        Comment

        Về tác giả

        Collapse

        newbie_avr Tìm hiểu thêm về newbie_avr

        Bài viết mới nhất

        Collapse

        Đang tải...
        X