PIC, C Berekening

Ik ben bezig om een programma te schrijven in C voor een PIC.
Daarmee wil ik de 'uitslag' van een pijp berekenen.

Ik heb dit voorbeeld gevonden:
http://www.wisfaq.nl/show3archive.asp?id=29977&j=2004

Deze code probeer ik nu om te zetten in C.
Daarbij kan ik wel wat hulp gebruiken, dus vandaar dit topic.

Ik ben mij ervan bewust dat dit op het randje van elektronica zit en heb dan ook eerst contact gezocht met een van de MOD's.

Als eerste heb ik dit ervan gemaakt, klopt dit denken jullie?:
t := 30; //Dit is de hoek
Pijp_1 := 50;
Pijp_2 := 100;

X := Cos(t)/2;
y := Sin(t) * 1.7320508 / 4 + z/2;
Z_Pos := (-1.7320508 / 2) * Sin(t) + Sqrt(((Sin(t) * Sin(t)) + 3 ));
Z_Neg := (-1.7320508 / 2) * Sin(t) - Sqrt(((Sin(t) * Sin(t)) + 3 ));

Ik wil dus de 'Uitslag' van de dunste pijp berekenen als deze (bijvoorbeeld) 50 mm. is, en de dikste pijp (bijvoorbeeld) 100mm.,en deze onder een hoek van 30 graden wordt geplaatst.

Geen antwoord, maar wel iets om rekening mee te houden: Ik zie dat je een "magic number" gebruikt: 1.7320508 , dit staat ook wel bekend als √3. Noteer dit ook zo bij het uitdenken van je routine. Dit geeft namelijk een hoop meer rust, en kan zelfs wat zaken verduidelijken.

Verder: Ga niet de complete sinus en cosinus routines in je microcontroller schieten (kost veeeeel ruimte, en rekenen kost ook veeeel tijd), maar werk met een lookup tabel. Als je deze tabel met 1° resolutie op slaat, heb je slechts 90 elementen nodig voor zowel de sinus als de cosinus functies samen.

Zo goed als het vroeger was, is het nooit geweest.

Waarom wil je dit per sé in een PIC hebben, dat begrijp ik eerlijk gezegd niet helemaal.

Just find out what you like and let it kill you

Het is voor een soort van machine, waar niet altijd een PC in de buurt is.
Deze PIC bestuurt het een en ander, en kan toch wel wat rekenwerk doen lijkt mij.

Arco

Special Member

Als het maar om 1 geval met vaste hoek gaat, zou ik het op de pc uitrekenen, en dan in de pic als waarde opslaan...
(zoals gezegd, de Cos/Sin libraries consumeren heel veel geheugen en processortijd...)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

Klopt wel dat sin() en cos() en floating point duur zijn.

Maar het geeft wel een eenvoudig programma en dat is ook wat waard. Dus zolang het in de processor past qua code omvang en snelheid: gewoon doen.

Maar je zegt ook :
t := 30; //Dit is de hoek

Blijkbaar heb je een hoek in graden. Maar sin() en cos() in deze libraries werken meestal in radialen. Dus die moet je nog omrekenen.

[Bericht gewijzigd door deKees op dinsdag 10 juni 2014 23:53:08 (31%)

Is die wortel drie niet 2x cos van die 30 graden die je als voorbeeld neemt?

Ik snap niet wat je met de uitslag van een pijp bedoelt.... (dit kan hem niet zijn, want dat gaat over een halve pijp... :-) )

Als een staaf lengte L in he't xy vlak roteert over een hoek phi, zit het uiteinde op l sin phi, l cos phi... (zonder hoofdletter in C...)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Ik snap niet wat je met de uitslag van een pijp bedoelt....

http://www.wisfaq.nl/show3archive.asp?id=29977&j=2004
Als je naar dit plaatje kijkt, dan gaat het mij om de vorm die de dunne pijp moet krijgen om deze precies passend te krijgen voor de dikkere pijp.

De dunne pijp heb ik verdeeld in 360 graden, en wil dan per graad uitgerekend hebben hoeveel mm. deze ingekort moet worden.

Deze code werkt als beide pijpen 100mm. zijn en haaks op elkaar staan:

code:


Rad:= Pi / 180;

For Graden:= 0 to 359 do begin  //360 maal herhalen (Oplopend)

 if (Graden <= 90) then Graden_Reken_waarde := 90 - Graden;
 if ((Graden > 90) and (Graden <= 180)) then Graden_Reken_waarde := Graden - 90;
 if ((Graden > 180) and (Graden <= 270)) then Graden_Reken_waarde := 270 - Graden;
 if ((Graden > 270) and (Graden <= 360)) then Graden_Reken_waarde := Graden - 270;

 A:= Sin(Graden_Reken_waarde * Rad) * 50;  //50 is Straal

 A:= 50 - A; //A is het lengte verschil

end;

Nu hebben de pijpen niet altijd dezelfde maat, daarom probeer ik de formules uit die link werkend te krijgen.

Dan moet je me nog eens uitleggen waarom je dat op een PIC zou willen doen....

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 11 juni 2014 12:09:55 schreef rew:
Dan moet je me nog eens uitleggen waarom je dat op een PIC zou willen doen....

Ik denk dat de machine waarop deze PIC wordt aangesloten pijpen snijdt zodat ze aan elkaar gelast kunnen worden.
De operator zou dan moeten kunnen opgeven welke diameters en hoek hij wil gebruiken.

Eén ding dat ik kan bedenken is om alleen de uitslagen voor 1 helft van de pijp te berekenen.
De uitslagen voor de andere helft zijn dan gelijk maar in spiegelbeeld.

En snelheid is minder belangrijk als je eerst de uitslag berekent en dan pas aan het snijden begint.

@MMSoft:
C gebruikt toch geen :=, For en end?
Hoe bekend ben je zelf met C en waarmee wil je precies hulp?
-Schrijven in C en compileren voor de PIC?
-Omzetten van de wiskunde naar een programma?
-Wiskundig uitwerken van de formules tot een algemeen bruikbare functie Uitslag(diameter1, diameter2, hoek)?

Arco

Special Member

E.e.a. klopt alleen als de afgaande pijp in de opening in de doorgaande pijp schuift.
Als hij ertegen of erop wordt gelast, moet je ook nog rekening houden met de diameter van de pijpen.
Dit omdat de kleine pijp de ronding van de grote moet volgen. (die is afhankelijk van de verhouding tussen de diameter van beide buizen)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

En komen ze alleen aan elkaar te zitten of moet er ook iets doorheen kunnen vloeien?
Op wat voor manieren kan de machine bewegen? (aantal vrijheidsgraden)
Hoe wordt er gesneden?
Komt de dunne pijp altijd precies midden op de dikke of kan deze er ook wat meer zijdelings op komen.

[Bericht gewijzigd door jeroen79 op woensdag 11 juni 2014 16:59:25 (54%)

Op 11 juni 2014 14:49:25 schreef jeroen79:@MMSoft:
C gebruikt toch geen :=, For en end?
Hoe bekend ben je zelf met C en waarmee wil je precies hulp?
-Schrijven in C en compileren voor de PIC?
-Omzetten van de wiskunde naar een programma?
-Wiskundig uitwerken van de formules tot een algemeen bruikbare functie Uitslag(diameter1, diameter2, hoek)?

Voorbeeld lijkt meer op Pascal. Nou ja, er zijn natuurlijk ook Pascal compilers voor de PIC.

Just find out what you like and let it kill you

Dan moet je me nog eens uitleggen waarom je dat op een PIC zou willen doen....

De machine waar deze PIC in zit snijdt pijpen zodat ze aan elkaar gelast kunnen worden. De operator geeft in welke diameters en hoek hij wil gebruiken.

Ik probeer de berekeningen eerst werkend te krijgen in Delphi en ga ze dan omzetten naar C (dat is makelijker en sneller testen).

De pijpen worden OP elkaar gelast !
Het is mogelijk dat de hoek niet altijd 90 graden is.

Het is voor mij laaaang geleden dat ik met wiskunde bezig was, dus daarbij is hulp erg welkom...

Als je het wilt voor een willekeurige hoek/straal van je buizen kan je evt. als volgt te werk gaan. Dit is de parametervergelijking van je eerst buis:

\begin{align}
x&=R_1\cos(t) \\
y&=R_1\sin(t) \qquad t\in [0, 2\pi] \\
z&=z
\end{align}

En dit voor de tweede (kleinere) buis onder een hoek theta

\begin{align}
x&=R_2\cos(\theta)\cos(t)+z\sin(\theta) \\
y&=R_2\sin(t) \\
z&=-R_2\sin(\theta)\cos(t)+z\cos(\theta)
\end{align}

Dan wordt de doorsnijding gegeven door

\begin{align}
x &= \cosh(t)\sqrt{R_1^2-R_2^2} \\
y &=\pm\sqrt{R_1^2-\cosh(t)^2(R_1^2-R_2^2)} \\
z&=\frac{\left(\cosh(t)\cos(\theta)-\sinh(t)\right)\sqrt{R_1^2-R_2^2}}{\sin(\theta)}
\end{align}

Met als resulterende omtrek

\begin{align}
O & = 2\int\limits_{-arcsinh(R_1)}^{arcsinh(R_1)} \sqrt{\left(\frac{dx}{dt}\right)^2+\left(\frac{dy}{dt}\right)^2+\left(\frac{dz}{dt}\right)^2} dt \\
&=2\int\limits_{-arcsinh(R_1)}^{arcsinh(R_1)} \sqrt{ \sinh(t)^2(R_1^2-R_2^2) +\frac{\cosh(t)^2\sinh(t)^2(R_1^2-R_2^2)^2}{R_1^2-\cosh(t)^2(R_1^2-R_2^2)} +\frac{(\cosh(t)\cos(\theta)-\sinh(t))^2\sqrt{R_1^2-R_2^2}}{\sin(\theta)^2} } dt
\end{align}

Dit is nogal moeilijk om te vereenvoudigen, vandaar zul je die integraal wellicht numeriek moeten uitrekenen.

-edit-
Een prentje van 2 buizen met de doorsnijdingskromme https://www.dropbox.com/s/dj06spq7iy8falv/resultaat.png
En de berekeningen https://www.dropbox.com/s/iwgl2k0aaw1aijn/berekeningen.mw

Eerst waren het atomen, dan waren het protonen, neutronen, elektronen, nog later waren het quarks en nu blijken het snaren te zijn...

Het voorbeeld is zeker Pascal :)

Ik zie trouwens 'z' nergens terug. Verder weet ik niet hoe 'slim' de compiler is met optimaliseren van je code voor de PIC, maar herhalingen in code zou ik altijd proberen te voorkomen. Je kan best 'Sqrt(((Sin(t) * Sin(t)) + 3 )' opslaan in een variabele, ze worden nu (afhankelijk van de optimalisatie) misschien twee keer uitgevoerd. Je kan ook voor de leesbaarheid besparen op haakjes ((iets)) is net zo goed als (iets).

Dit is hoe ik pascal geleerd heb trouwens:

c code:


iHoek    := 30;
iZ       := ???;
iPijp1   := 50;
iPijp2   := 100;

dSinHoek := Sin(iHoek);
dX       := Cos(iHoek) / 2;
dY       := dSinHoek  * 1.7320508/4 + iZ/2;
dV1      := -1.7320508 / 2;
dV2      := Sqrt( dSinHoek*dSinHoek  + 3 );
dZPos    := dV1 * dSinHoek + dV2;
dZNeg    := dV1 * dSinHoek - dV2;

Geen dubbele berekeningen, respect voor hoofdletters, lekkere met spatie inspringen en de eerste letter geeft het soort variabele weer (i=heel nummer, d=kommagescheiden)... maar misschien is dat wat veel eer hiervoor :p

[Bericht gewijzigd door david9k op woensdag 11 juni 2014 20:19:43 (40%)

eagle987: Bedankt voor deze (waarschijnlijk complete) berekening, maar daar ik ik helaas nog niet erg wijs uit.

david9k: Bedankt voor deze berekeningen, hier kan ik beter wijs uit maar dit is toch nog niet compleet als ik mij niet vergis ?

Is het mogelijk aan de hand van een voorbeeld een berekening te maken ?
Stel:
Pijp 1 = 100 mm.
Pijp 2 = 50 mm. (deze pijp moet gesneden worden)
Hoek = 30 Graden.

Hoe reken ik dit dan precies uit ?

Waarom de berekeningen in de PIC doen? Als je, zoals voorgesteld, voor de sin/cos een lookup table gaat maken (en dan neem ik aan ook voor de SQRT), kun je - lijkt mij - veel zinniger direct een lookuptable voor de de diverse formules maken.

En de waarden van t lopen volgens mij maar van 0..90 (volgens het plaatje lijkt me de boel op de rest van het bereik symetrisch daaraan?), dus qua geheugengebruik blijft het ook redelijk beperkt.

Naar de stapgroote binnen je tabel kun je ook nog kijken: je kan waarden linear interpoleren; het kan best zijn dat als de tabel stapjes van bijv 5 graden maakt, de uitkomst nog steeds binnen de tollerantie valt.

Voordeel is dat de formules enorm complex kunnen zijn (zoals die integralen van eagle987), zonder dat dat echt impact heeft op de performance van de PIC.

Waarom de berekeningen in de PIC doen?

Dat heb ik toch al uitgelegd ?

Als je, zoals voorgesteld, voor de sin/cos een lookup table gaat maken

Ik ben druk aan het zoeken hoe zo'n tabel er precies uit komt te zien.

(en dan neem ik aan ook voor de SQRT), kun je - lijkt mij - veel zinniger direct een lookuptable voor de de diverse formules maken.

Je heb vast en zeker gelijkt, kan je een voorbeeld geven, want hier kan ik helaas nog niet veel mee.

Sorry, ik wou niet kort door de bocht doen...

Hoe de tabel er inhoudelijk uit moet zien, kan ik niet zeggen (ik zit niet diep genoeg in die materie).

Qua implementatie zou ik gaan voor 16bit fixed point berekeningen (voor een bereik van 0..255mm met een nouwkeurigheid van ~0.004mm; geen idee of dat voor jouw toepassing past). Code wordt dan iets van:

code:


unsigned short luTable[90] = {0, 4, 9, 13, 18, 22, 27, 31, 36, 40, 44, 49, 53, 58, 62, 66, 71, 75, 79, 83, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 139, 143, 147, 150, 154, 158, 161, 165, 168, 171, 175, 178, 181, 184, 187, 190, 193, 196, 199, 202, 204, 207, 210, 212, 215, 217, 219, 222, 224, 226, 228, 230, 232, 234, 236, 237, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 254, 255, 255, 255, 256, 256, 256};

unsigned short formula(unsigned short t)
{
  // t should be within (0*256) .. (90*256)

  if(t>=23040)
    return 0;

  // fetch values from lookup table based on t, and interpolate
  unsigned short a = luTable[t>>8];
  unsigned short b = luTable[(t>>8) + (t&0xff?0:1)];

  return a*(256 - (t&0xff)) + b*(t&0xff);
}

De code heb ik niet getest; op dit moment berekent het de sinus van t, maar door het anders vullen van de tabel kun je er natuurlijk andere dingen mee berekenen...

Ik heb nog geen idee hoe zwaar de PIC belast gaat als deze Sin, Cos enz. moet gaan berekenen. Ik gebruik een 18F PIC op 20Mhz...
Deze berekeningen worden gedaan voordat de machine start, en de PIC heeft dan ook wel even de tijd...

Als ik naar deze berekening kijk:

c code:


iHoek    := 30;
iZ       := ???;
iPijp1   := 50;
iPijp2   := 100;

dSinHoek := Sin(iHoek);
dX       := Cos(iHoek) / 2;
dY       := dSinHoek  * 1.7320508/4 + iZ/2;
dV1      := -1.7320508 / 2;
dV2      := Sqrt( dSinHoek*dSinHoek  + 3 );
dZPos    := dV1 * dSinHoek + dV2;
dZNeg    := dV1 * dSinHoek - dV2;

Waar staat de z voor ?

Hoe krijg ik nu precies de uitslag, want dat begrijp ik helaas nog niet.

Wat algemene info:
Wat met wortels vaak een goed idee is, is te kijken of je berekening eerst in het kwadraat uitgevoerd kan worden waarna je de wortel pas van het eindresultaat trekt. Hierdoor kun je vaak een heel eind eerst met integere getallen werken (vermenigvuldig alles met de benodigde precisie).

Soms kun je een formule omvormen om zo min mogelijk rekenwerk in de uC te doen dmv constantes. (bv 1/(x+b) = c/x+d/b, vind c en d)

Houd ook rekening met de precisie van de uC: eerst 1/<groot> getal gebruiken om later te vermenigvuldigen met <nog veel groter getal> kan een rekenfout opleveren als niet in de juiste volgorde.

Bij zo een enorme formule als die ik hierboven zie, zou ik zeker overwegen een n-de graad polynoom te fitten over je werkgebied.
(http://en.wikipedia.org/wiki/Curve_fitting, taylor approx.)

Wortel trekken approximatie gaat goed met een newton-iteratie: http://mathworld.wolfram.com/NewtonsIteration.html

1/sqrt(x) kan nog preciezer (en dus minder iteraties). Staat heel leuk verhaal over hier: http://en.wikipedia.org/wiki/Fast_inverse_square_root

Voor wat betreft de sin/cos lookup: http://devmaster.net/posts/9648/fast-and-accurate-sine-cosine
Mijn ervaring (op een PC getest) is dat een lookup table _trager_ is dan de sin/cos functies in de standaard c-library, m.a.w.: Er is code die het sneller kan. En die is open source: http://stackoverflow.com/questions/4541130/definitions-of-sqrt-sin-cos…

Succes!

Grt Tijs

Op 12 juni 2014 10:24:43 schreef knifter:
Mijn ervaring (op een PC getest) is dat een lookup table _trager_ is dan de sin/cos functies in de standaard c-library, m.a.w.: Er is code die het sneller kan.

Dat is een vergelijking die niet helemaal opgaat. Een PC processor heeft al sinds decenia een math co-processor (de 486sx/dx was volgens mij de laatste generatie waar het niet standaard was) die floatingpoint berekingen kan doen, en ook ingebouwde functies voor sqrt, sin en cos enzo heeft. Het verbaast me niets dat een coprocessor sneller is dan een lookup tabel... Een PIC heeft echter een behoorlijk andere architectuur en geen hardwareondersteuning voor deregelijke functies.

Verder heb je een aantal goede punten!

Ik heb eens even gekeken hoe lang de PIC nodig heeft om deze berekeningen 360 keer uit te voeren:

c code:


unsigned Graden;
unsigned short iHoek;
unsigned short iZ;
unsigned short iPijp1;
unsigned short iPijp2;
long dSinHoek;
long dX;
long dY;
long dV1;
long dV2;
long dZPos;
long dZNeg;


for( Graden=0 ; Graden<360 ; Graden++ )  
 {
  iHoek = Graden;
  dSinHoek = Sin(iHoek);
  dX       = Cos(iHoek) / 2;
  dY       = dSinHoek  * 1.7320508/4 + iZ/2;
  dV1      = -1.7320508 / 2;
  dV2      = Sqrt( dSinHoek*dSinHoek  + 3 );
  dZPos    = dV1 * dSinHoek + dV2;
  dZNeg    = dV1 * dSinHoek - dV2;
 }

[/code=c]
Dat kost slecht ca. 2 sec.
Ook het geheugen gebruik vindt ik erg mee vallen, dus ik denk eraan om geen tabel te gebruiken.
Arco

Special Member

Meeste Cos/Sin routines geven een waarde van -1...+1 terug, dat gaat dus niet in een long... (float)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com