Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Merenje efektivnog napona/struje 50 Hz microkontrolerom
#1
Znaci mikrokontroler uzima uzorke i radi ADC 
Dalje secanje od pre 30++ godina dok je Ti slao knjizice o pocecima DSP dizem ih na kvadrat i dalje nema Sad
Merio bih samo jednu poluperiodu , druga je simetricna jednostavniji hardwer Pic ili AVR sa nekim OP 
Hvala bilo bi lepo neki C primer
Reply
#2
Sumu kvadrata podeliš sa brojem uzoraka pa odatle vadiš koren Smile

E problem je taj koren koji zahtevan za namučeni PIC. Postoji skraćeni algoritam koji daje približan rezultat pa ako ti to nije problem možeš da ga koristiš. Algoritam je opisan u Microchip TB040 "Fast Integer Square Root"
https://www.microchip.com/en-us/application-notes/tb040

Ovo ispod je moj c kod za taj algoritam. Projekat merenja je stao vrlo nakon što je započet ali koliko se sećam davao je zadovoljavajući rezultat.
Evo koda za taj deo. Treba da je OK.

Code:
unsigned int isqrt(unsigned long data)
{
unsigned int bitloc = 0x8000;
unsigned int result = 0x8000;
unsigned int tmp = 0;
unsigned long ltmp = 0;
unsigned char i = 16;

    while(i--)
    {
        ltmp = (unsigned long)result * (unsigned long)result;
        if(ltmp > data)
        {
            result = tmp;
            bitloc >>= 1;
            result |= bitloc;

        }
        else
        {

            tmp = result;
            bitloc >>= 1;
            result |= bitloc;

        }
    }

    return result;
}
Reply
#3
(10-15-2022, 09:45 PM)gorankg Wrote: Sumu kvadrata podeliš sa brojem uzoraka pa odatle vadiš koren Smile

E problem je taj koren koji zahtevan za namučeni PIC. Postoji skraćeni algoritam koji daje približan rezultat pa ako ti to nije problem možeš da ga koristiš. Algoritam je opisan u Microchip TB040 "Fast Integer Square Root"
https://www.microchip.com/en-us/application-notes/tb040

Ovo ispod je moj c kod za taj algoritam. Projekat merenja je stao vrlo nakon što je započet ali koliko se sećam davao je zadovoljavajući rezultat.
Evo koda za taj deo. Treba da je OK.

Code:
unsigned int isqrt(unsigned long data)
{
unsigned int bitloc = 0x8000;
unsigned int result = 0x8000;
unsigned int tmp = 0;
unsigned long ltmp = 0;
unsigned char i = 16;

    while(i--)
    {
        ltmp = (unsigned long)result * (unsigned long)result;
        if(ltmp > data)
        {
            result = tmp;
            bitloc >>= 1;
            result |= bitloc;

        }
        else
        {

            tmp = result;
            bitloc >>= 1;
            result |= bitloc;

        }
    }

    return result;
}
Reply
#4
Ovaj kod sam pisao za jedan projekat sa PIC16F18855, fantastični malli mikrokontroler. Iz ranijeg iskustva, kao što je i Goran pisao, računanje kvadratnog korena je priličan "overkill" za ovakve mikrokontrolere, međutim na moje prijatno iznenađenje PIC16F18855 se odlično i junački držao. Pravljen je neki punjač akumulatora sa faznom regulacijom, pa je bilo potrebno da se struja meri kao efektivna vrednost, zbog faznog ugla nakon tiristora... Nisam previše ulazio u to kolika je preciznost i tačnost merenja, ali smo brzinskom proverom digitalnim TrueRMS unimerom ustanovili da je merenje veoma korektno za ovu namenu. Rađeno je jednom mom prijatelju, brzinski za jedno popodne, tako da je za ovu namenu prošao... za neke ozbiljnije i brže signale, ovo svakako ne bi moglo da se izvede sa majušnim PIC16Fxxx

Code:
#define ADC_REF_VOLTAGE 5.00
#define ADC_RESOLUTION  1023.00

// **** VARIABLES ****
bit Na10msFlag;
bit CalculateCurrentRMS;

float MeasuredCurrentmA;

volatile adc_result_t ADCCurrentRawVal = 0;
volatile adc_result_t ADCVoltageRawVal = 0;
 
uint32_t ADCCurrentRawForSquareRoot;

uint8_t SampleChannel = 0;

uint16_t ADCVoltageRawValFiltered = 0;

// FUNCTIONS
void TMR0_UserInterruptHandler(void)
{
  Na10msFlag = 1;
}

// ADC Interapt
// TMR5 je podesen da radi na 1ms i on radi triger semplovanja
void ADCC_UserInterruptHandler(void)
{
  static uint32_t ADCCurrentRawValSqAccu = 0;
  static uint8_t SamplesCountCurrent = 0;

  static unsigned long SampleAcuVolt = 0;

  if(SampleChannel == ADCCHStrujaPunjenja)
  {
    ADCCurrentRawVal = ADCC_GetConversionResult();
    SampleChannel = ADCCHNaponAkumulatora;
    // select the A/D channel
    ADPCH = ADCCHNaponAkumulatora;

    // Idemo u deo racunice za TrueRMS, ovde radimo sumu kvadrata semplova
    // Dole u main petlji kada se prepozna da vrednost ADCCurrentRawForSquareRoot
    // nije nula, on okida racunicu za Sqrt(ADCCurrentRawForSquareRoot) jer
    // je ADCCurrentRawForSquareRoot sadrzana suma kvadrata podeljena sa brojem
    // uzoraka! To je u nasem slucaiju 128 uzoraka
    ADCCurrentRawValSqAccu += ADCCurrentRawVal * ADCCurrentRawVal;
    if(++SamplesCountCurrent >= 128)
    {
      SamplesCountCurrent = 0;
      ADCCurrentRawValSqAccu = ADCCurrentRawValSqAccu / 128;
      ADCCurrentRawForSquareRoot = ADCCurrentRawValSqAccu;
      CalculateCurrentRMS = 1;
      ADCCurrentRawValSqAccu = 0;
    }
  }
}

/*
                         Main application
*/
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();

    TMR0_SetInterruptHandler(TMR0_UserInterruptHandler);
    TMR2_SetInterruptHandler(TMR2_UserInterruptHandler);
    ADCC_SetADIInterruptHandler(ADCC_UserInterruptHandler);

    // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
    // Use the following macros to:

    // Enable the Global Interrupts
    INTERRUPT_GlobalInterruptEnable();

    // Enable the Peripheral Interrupts
    INTERRUPT_PeripheralInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    // Disable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptDisable();
   
    TMR6_StartTimer();
    SampleChannel = ADCCHStrujaPunjenja;
    ADCC_StartConversion(ADCCHStrujaPunjenja);

    TMR0_StartTimer();
   
    while (1)
    {
    
      // Add your application code
      if(Na10msFlag)
      {
        Na10msFlag = 0;
       
        if(CalculateCurrentRMS)
        {
          CalculateCurrentRMS = 0;
         
          float ADCCurrentRawValFinal = sqrt(ADCCurrentRawForSquareRoot);
          MeasuredCurrentmA = (float)1000.00 * (( (float)ADC_REF_VOLTAGE / (float)ADC_RESOLUTION) * (float)ADCCurrentRawValFinal) / (float)CURRENT_SENS_RESISTOR; // Rsens = 0.1
        }
  }
}
Reply
#5
Postoji i druga varijanta koju ja praktikujem (lookup-tablica) uvek kada ima slobodne programske memorije u kontroleru, a obično ima, da se naprave pre-izračunate sve vrednosti matematičkog računa, dakle jedna "velika tablica" i u njoj poredjani rezultati za sva stanja/vrednosti ADC ulaza (primer 10bit A/D):

ADC=0  Rezultat=123
ADC=1  Rezultat=129
....

ADC=1023  Rezultat=3281

Praktično memorija se definiše kao 

koeficienti[1024] = {123, 129 .... 3281}; 

To zauzima 2kByte programske memorije ali zato radi DRASTIČNO BRŽE, u okviru nekoliko clock ciklusa koliko treba da se pročita memoriska lokacija u poredjenju da se to radi svaki put iznova u realnom vremenu, ovo je prakitično feed-forward tehnika gde smo neke konkretne rezultate ili neke medju rezlutate tj šta-god što može da pomogne "unapred" da se ne radi posle i tako se uštedi gomila procesorskog vremena i onda može opušteno da se dalje rade razne stvari po programu. To praktikujem i na procesorima koji imaju FPU unit u sebi, čak i na Cortex-A, kad se preskoči floating-point u realnom vremenu i predje na look-up tablice to tek počne da radi kako treba Smile

BTW: Više se svodi na to u kom programskom jeziku ćeš da izračunaš i formatiraš to parče memorije/C-code, neki Python, JavaScript i tome slično.
Na primer, na STM32 preko terminala imao sam funkciju koja mi je vraćala C-formatiran tekst koji je "popunjen" sa svim potrebnim stvarima, C funkcije i podaci koji je predvidjen da se uradi copy/paste preko terminala i da se to parče "pejstuje" u program za drugi kontroler koji radi neku drugu "uparenu" logiku pa se onda to prevede da se takve neke stvari nebi morale rade opet u realnom vremenu da se prozivaju kontroleri za neka stanja i statuse koji moraju da budu striktno upareni.
Reply
#6
@npejcic, nešto me buni kod tvog koda. Uzimaš uzorak na 1ms i to 128 puta pa izlazi da ti je period uzorkovanja 128ms a perioda signala je 20ms (za 50Hz). Ako dobro gledam kod Huh tvoj rezultat treba da je preko 6 puta veći od stvarnog. Ja imam isti metod ali uzorkujem tačno 20ms pa onda računam. Ispravi me ako negde grešim.
Reply
#7
Code:
...         
float ADCCurrentRawValFinal = sqrt(ADCCurrentRawForSquareRoot);
MeasuredCurrentmA = (float)1000.00 * (( (float)ADC_REF_VOLTAGE / (float)ADC_RESOLUTION) * (float)ADCCurrentRawValFinal) / (float)CURRENT_SENS_RESISTOR; // Rsens = 0.1
...

Koliko god da je kompleksan račun, nama je diskretizovana ulazna vrednost i za 10bit A/D može da ima 1024 rezultata jer su sve ostale vrednosti u računu konstatne.

Ovaj gore račun se prebaci u tablicu i program istog momenta POLETI, tu se više ne troši vreme Smile

I kad se tako rastereti MCU/CPU onda se "odvrne" malo sampling-rate da to sve radi sa više uzoraka u sekundi i onda se preostalo CPU vreme potroši za neku neophodnu minimalnu FP matematiku da se rezultati fino ujednače/filtriraju i eventualno poboljša preciznost rezultata.
Reply
#8
Malo off-topic ali nekako povezano, da li ste znali da je HP svoj model najboljeg metrološkog instrumenta koji su dizajnirali jednom-zauvek 80' godina, čuveni HP3458A sa 8.5 cifara (28bit A/D) da se još uvek proizvodi i pravi potpuno isto, kompletan Analogni deo je 100% identičan kao pre 40 godina, iste PCB, isti hibridi i ostale komponente, istih dimenzija kao u starim primercima jedino su zamenili digitalnu-glavnu PCB gde je bio stari beše Motorolin procesor sa gomilom nekih diskret-logic delova i to sve rešili sa JEDNIM STM32F407 gde su dodali samo LAN i Fiber-optičku konekciju i nema dalje, "Hvala lepo, dovidjenja!" Smile Može da se kupi nova digitalna PCB i stavi u stare modele HP-a jer je sve ostalo 100% identično i uklapa se u dimenzije!

Toliko o mernim instrumentima i šta je analogija a šta digitalija, taj STM32 je sve odradio savršeno tu što treba ali isključivo u digitalnom domenu, čika HP je tu preuzeo analogni deo i to rešio tako da ne bude zavisno od upravljačkog kontrolera dokle god je tačan "timing" tamo nekih digitalnih I/O nožica.

[Image: attachment.php?aid=38597]


Attached Files Thumbnail(s)

Reply
#9
https://www.analog.com/en/parametricsearch/11023#/

Ovo gore su rms to dc konverter integralna kola, ko ne voli mnogo matematike u uC.
Reply
#10
(10-19-2022, 08:44 PM)gorankg Wrote: @npejcic, nešto me buni kod tvog koda. Uzimaš uzorak na 1ms i to 128 puta pa izlazi da ti je period uzorkovanja 128ms a perioda signala je 20ms (za 50Hz). Ako dobro gledam kod Huh tvoj rezultat treba da je preko 6 puta veći od stvarnog. Ja imam isti metod ali uzorkujem tačno 20ms pa onda računam. Ispravi me ako negde grešim.

Nije neophodno da bude tačno jedna perioda, to je bitno ako hoćeš što pre da dobiješ rezultat, recimo neki zaštitni algoritam. Kod mene nije bilo kritično, pa sam uzeo veći "prozor"... brzinski sam našao dokument koji to opisuje:
https://www.egr.msu.edu/classes/ece480/c...cation.pdf
Reply
#11
(10-20-2022, 06:43 AM)mikikg Wrote:
Code:
...        
float ADCCurrentRawValFinal = sqrt(ADCCurrentRawForSquareRoot);
MeasuredCurrentmA = (float)1000.00 * (( (float)ADC_REF_VOLTAGE / (float)ADC_RESOLUTION) * (float)ADCCurrentRawValFinal) / (float)CURRENT_SENS_RESISTOR; // Rsens = 0.1
...

Koliko god da je kompleksan račun, nama je diskretizovana ulazna vrednost i za 10bit A/D može da ima 1024 rezultata jer su sve ostale vrednosti u računu konstatne.

Ovaj gore račun se prebaci u tablicu i program istog momenta POLETI, tu se više ne troši vreme Smile

I kad se tako rastereti MCU/CPU onda se "odvrne" malo sampling-rate da to sve radi sa više uzoraka u sekundi i onda se preostalo CPU vreme potroši za neku neophodnu minimalnu FP matematiku da se rezultati fino ujednače/filtriraju i eventualno poboljša preciznost rezultata.

Apsolutno si u pravu... pravili smo tabele i tabele ranije sa PIC16F628, PIC16F877 itd... ali sada je nekako došlo novo vreme i poroka na sve strane. Ja eto, podlegao da korisim float-point matematiku i na malim PIC-ovima Smile Smile Današnji "klinci" ne mogu da shvate o čemu pričamo, zar ne Wink

Šalu na stranu, Mikijev pristup je najispravniji, jer je "matematika" na ovaj način extremno brza, a jedina "žrtva" je malo više kodne memorije. Dodatno, umesto float-point uvek je moguće koristiti integer kalkulacije u veći domen, pa zatim podeliti rezultat sa 1000, 1000000, itd...

P.S. STM32F4 već imaju ugrađen math koprocesor za float 32bita, dok STM32H idu i na float 64 bita...
Reply
#12
Zar nema u PIC da se podesi kompajler na float32? Ja sam imao manjka mesta na jednom projektu a resio sam tako sto sam postavio da mi float bude u 32bit, tako sam dobio mesta vazda. Ako ti ikako moze pomoci primer iz atacmenta, to sam radio jedan buck konverter a na ekranu sam imao struju, napon i snagu 32bit preciznosti koristeci 32bit float umesto 64bit float, ali adc mi je ina226 mada moze i sa pic adc da se odradi ali daleko ne preciznije.


Attached Files
.c   main.c (Size: 30,4 KB / Downloads: 7)
Reply
#13
@savan Da, naravno... ali to su sve softverske implementacije matematičkih algoritama ako pričamo o PIC16F, 18F, 24F, dspic33... Problem je što užasno mnogo traju na slabijim MCU... usudio bih se da kažem da su u pitanju desetine milisekundi za neku od kalkulacija sa float numericima, ili hiljadama puta sporije od integer matematike.
Reply
#14
Probao na arduino nano samo simulacija. SQRT je negde oko 400ms. Onaj skraćeni algoritam koji sam dao gore je oko 200ms. Tabela u flash-u je najbrža ako imaš prostora na raspolaganju.
Reply
#15
U pitanju su rms value, ok kontam sad. Da pic ima vecu internu memoriju i veci eeprom mogla bi da se predimenzionise multi array tabela sa vec izracunatim vrednostima recimo pickup tabela sa 1024 x 8byte, ali ovako tesko da moze bolje od ovoga http://www.magusporta.com/tips/true_rms/true_rms.html
Reply
#16
(10-21-2022, 02:50 PM)savan Wrote: Zar nema u PIC da se podesi kompajler na float32?

Za PIC16 seriju (a verovatno i PIC18) možeš da u postavkama projekta promeniš veličinu za float, sa 32 na 24 i time dobiješ još mesta s tim da gubiš na tačnosti rezultata.
Reply
#17
Kombinuje se tablica (sa 32bit int rezultatima) sa 32bit integer matematikom i sve ovo go što smo pisali može da radi relativno brzo, umesto na primer spomenutih 400ms i 200ms ta funkcija radiće u okviru 1-2us što je odprilike 200.000 puta brže i sa takvom postavkom nema problema i može da se još dodatno ubrza sample rate da se dobiju još finiji rezultati.

Čak i ako se ima 12bit A/D u MCU, takav MCU sigurno ima mesta u programskoj memoriji da se smesti jedna lookup-tablica veličine 4096 lokacija x 4 bytes = 16KBytes, odvoji se ta memoriji i sve ostalo onda legne na svoje mesto i dobije se vrlo precizna kalkulacija i u SW domenu tu nema mnogo dalje da se radi, pri ovim A/D rezulucijama počinje HW da pravi problem, driftovanje reference, šhum, smetnje i ostale stvari koje se dešavaju u analognom domenu ispred A/D ulaza.

BTW: Ako nema mesta u internom flash, uvek može da se koristi externi SPI EEPROM ili Flash memorija, tu stoje tablice i čitanje odatle preko SPI je i daje dosta brže nego da se to računa u realnom vremenu.

BTW2: 32bit Integer matematika ima dovoljo dobru preciznost tj dinamiku procesiranja signala.
Recimo 32bit opseg je +2,147,483,648 do -2,147,483,647 samo se postavlja pitanje "čega toliko" i u ovom konkretnom slučaju mogu da budu mikro-Volti ili mikro-Amperi tako da dobijemo opseg +/-2147V sa rezolucijom 1uV što je nešto što ni gore spomenuti HP3485A nema u realnosti tako da sa SW ne mora da se brine, predjite malo na Analogiju, gde su filteri, gde su atenuatori, gde su izolatori, kako se struja meri, transformatori, burden, zaštite, za referencu da ne pitam ... ? Smile
Reply
#18
Specifično za merenje AC napona i struje postoje posebni A/D konverteri poput na primer ADS131M08, malo ozbiljnija sprava sa integrisanim filterima i PGA i generalno ima sve što treba u alogonom domenu za takve vrste merenja:

Quote:The ADS131M08 is a eight-channel, simultaneously- sampling, 24-bit, delta-sigma (ΔΣ), analog-to-digital converter (ADC) that offers wide dynamic range, low power, and energy-measurement-specific features, making the device an excellent fit for energy metering, power metrology, and circuit breaker applications. The ADC inputs can be directly interfaced to a resistor-divider network or a power transformer to measure voltage or to a current transformer or a Rogowski coil to measure current.

https://www.ti.com/lit/ds/symlink/ads131m08.pdf

Dodatan HW da se to prikljući recimo na 3x380VAC za merenje U/I se svodi na 6 "malih" transformatora i 6 otpornika (3 strujna trafoa + 3 naponska trafoa) koji idu direktno na ADC ulaze i to je sve, odatle nadalje ADC preuzima kontrolu i postoji kalibracija za phase-offset, voltage-offset i gain-offset što su tu najbitnije stvari i nadalje je sve čista digitalna logika.
Ovakav merni sistem radi u 4-kvadranta i može da meri generalno snagu koja ulazi ili koja izlazi iz električne mreže.

[Image: attachment.php?aid=38622]


Attached Files Thumbnail(s)

Reply
#19
XC8 ne podrzava 24 bitnu aritmetiku po standardu C99 vec samo po C90
Reply
#20
Ne znam sad koliko često se na kraju tih proračuna traži kvadratni koren od nekih ranije sračunatih zbirova, ali bih dodao par teorijskih razmišljanja o problemu kvadratnog korena.
Prvo treba videti da li se radi o korenu celobrojnih vrednosti (integer) ili onih u pokretnom zarezu (floating-point).
Celobrojni:
-što duže raditi u integer aritmetici, te tek na kraju preći u floating-point. To je jednostavno sa integerima. Pogleda se pozicija prve jedinice. Recimo da je to 11. To znači da se radi o celom broju između 1024 i 2047, zato što to može biti broj između 1 00000 00000 (=1024) i 1 11111 11111 (=2047). Zamislimo da je to broj 1500. Njegov koren je 38,7298... Ideja ovog mog postupka je da celobrojnom aritmetikom dođemo do najbližeg celog broja traženog korena (u ovom slučaju je to 38) i da tad pređemo u floating-point, što je i normalno jer ne možemo tako lako da decimale računamo sa integer aritmetikom. Kako doći do 38? Prvo da kažem, da je ovo moja ideja, nisam kopao po člancima, jer smatram da postojeća rešenja mogu da ograniče način razmišljanja. Takođe sam siguran da postoje bolja rešenja od ovog mog, jer da ne postoje, bio bih iskreno razočaran. Tako da ovaj moj post možete više shvatiti kao jednu matematičku vežbu moždanih vijuga, više nego kao konkretnu pomoć. Dakle, kako doći brzo i lako do broja 38 koji je jedna dobra aproksimacija  i dobar (najbolji) početak za neki iterativni postupak koji će nam dati tačan rezultat. To sam zamislio kao skraćeni postupak ponovljenog oduzimanja rednih neparnih brojeva. Verovatno se ne sećate (ili nikad niste sami primetili) da je zbir prvih N neparnih brojeva u stvari N na kvadrat? Primer: 1+3+5+7+9=? Neću sabirati, jer znam da je rezultat 25, jer sam sabrao prvih 5 neparnih brojeva. Ako dodamo sledeći (11) dobićemo 6 na kvadrat, zatim dodamo sledeći neparan broj (13), to je 7 na kvadrat. E sad da ne bismo od broja 1500 oduzimali 38 rednih neparnih brojeva (u 38-oj iteraciji bismo došli do reda gde piše 113-75= 56 i tu stajemo jer oduzimanjem sledećeg neparnog broja (77) prelazimo u negativu - dakle, zaključujemo 1500= 38^2 + 56), moj metod se svodi na skraćivanje broja iteracija. U binarnom zapisu broja 1500 imamo 1 kao vodeći na 11-og poziciji. Tražimo kvadratni koren iz njemu bliskog broja, a to je 1 i deset nula iza njega, što se odmah zna da je 2^5 (polovina nula, time smo u stvari korenovali broj 1024), a to je 32. Onda radimo 33. iteraciju počev od razlike 1500 - 1024= 476 -> 476 - 65= 411. Odakle nam 65? To je 33-i neparni broj (33*2 -1). Onda redom oduzimamo 67, pa 69, pa 71, pa 73, pa 75. Kao što sam rekao tu stajemo, jer oduzimanjem 77, prelazimo u negativu. Mogli smo da krenemo od početka sa oduzimanja (oduzmemo 1, pa 3, pa 5...) ali bismo tako uzalud potrošili 32 oduzimanja da bismo došli do identičnog rezultata 1500 - 32^2= 476. Korenovanjem broja 1024 (jednostavnim prepolovljavanjem broja nula u binarnom zapisu - običan šift) smo uštedeli vreme za to. Nakon toga smo oduzeli još 6 neparnih brojeva pre prelaska u negativu i došli do zaključka da nam je potrebno ukupno 38 oduzimanja, tj da je broj 1500 nešto veći od 38^2, ali je manji od 39^2. Dakle, čistom integer aritmetikom došli smo do odlične prve aproksimacije korena iz 1500, a to je 38. Sad prelazimo u floating point, jer treba da sračunamo one decimale iza 38. Ne znam koje algoritme koriste kompajleri za 8-bitne procesore, ali pošto se sećam da je za prve PC računare korišćeni Intelovi 16-bitni procesori 8086 i 8088, a da su kvadratni koren računali tako što su logartmovali broj, podelili ga sa 2, pa ga onda antilogaritmovali. Tako su dobijali nešto vrlo približno kvadratnom korenu, jer algoritmi za logaritam i antilogaritam su komplikovaniji od korektnog algoritma za kvadratni koren, koji nisu primenili. Ko je čuo za prof. Dušana Slavića, zna o čemu pričam.
Da se vratimo korenu iz 1500. Još u doba Vavilona postojao je jedan približni algoritam za proračun kvadratnog korena. Taj postupak je zapisao Heron iz Aleksandrije (onaj što je izmislio formulu za proračun površine bilo kog trougla čije dužine stranica znamo). U toj formuli se koristi kvadratni koren, pa je logično što je Heron primenio najbolji dotada metod, a on je:
- Ako tražimo koren iz x i na neki način smo došli do približnog broja y, onda ćemo novi, tačniji y dobiti po formuli y=(y+x/y)/2. Npr: tražimo koren iz 10 i došli smo do zaključka da je to nešto veće od 3, onda je nova aproksimacija =(3+10/3)/2 = 3,16666. Sledeća iteracija je (3,166666+10/3,166666)/2 = 3,16228, što je koren iz 10 sa 6 značajnih cifara, tj 5 decimala.
Primenjeno na naš slučaj, gde tražimo koren iz 1500, što je 38,7298335 imamo u floating-pointu (38+1500/38)/2= 38,736842. Ovde je greška manja od 0,2 promila! Ne odustajemo, još jednu, konobar! (38,736842 +1500/38,736842)/2 = 38,7298341. Ovde možemo da stanemo, jer već imamo 8 značajnih dekadnih cifri, što prevazilazi tačnost floating-point aritmetike i kod 24 i kod 32 bita, što su približno 5 i 7 cifri...

Šta smo imali za ručak?
- jedan šift udesno da dobijemo broj 32 (korenovanjem broja 1024)
- 6 integer oduzimanja
- 2x primenu floating-point formule samo sa sabiranjem i deljenjem...
A dobili smo koren tačan do tačnosti kompajlera...

Imao sam nameru da objasnim i korenovanje floating-point broja, ali vidim da sam preterao u dužini posta i verovatno sam podavio većinu neopreznih čitalaca, pa odustajem. Zasada. Možda se nekome ovo i svidelo i daj Bože je primeni u svojim projektima. Recimo, dosta proračuna se može uraditi u celobrojnoj ili 24-bitnoj aritmetici i onda na kraju se u 32-bitnoj primeni Heronova formula i dobije se tačnost na par dodatnih decimala...
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)