door Swets » zo 15 jan 2023, 16:41
RedCat schreef: ↑ma 29 nov 2021, 20:09
Swets schreef: ↑ma 29 nov 2021, 12:17
... maar ja , er komt steeds meer rekenwerk in, en nu dus de asin ...
Als het je om snelheid gaat, dan kunnen we waarschijnlijk veel winst behalen met een grovere benadering voor asin(), zie bijvoorbeeld
https://seblagarde.wordpress.com/2014/1 ... hitecture/
De asin() functie is in dat artikel een uitbreiding van de acos() functie. Als we onze formule omzetten naar acos() (in plaats van asin()) zijn we hiermee dus nog sneller:
\(\small ∠KML = \pi - ∠KMB - ∠BMP = \pi - acos\left(\frac{MK}{BM}\right) - acos\left(\frac{abs(mz-bz)}{BM}\right) \)
Hier werken we met hoeken van 0 .. pi/2 (= van 0° .. 90°), aangenomen dat de onderkant van het blok nooit boven het middelpunt van de bovenste katrol uit zal komen.
Daarom kunnen we de benaderingsformules van dat artikel nog verder vereenvoudigen:
Code: Selecteer alles
// IN: 0 <= x <= 1
// UIT: acos(x), maximale fout 0.0061
float acos1(float x)
{
return((-0.155972*x+1.56467)*sqrt(1.0f-x));
}
Code: Selecteer alles
// IN: 0 <= x <= 1
// UIT: acos(x), maximale fout 0.00061
float acos2(float x)
{
return(((0.0464619*x-0.201877)*x+1.57018)*sqrt(1.0f-x));
}
Code: Selecteer alles
// IN: 0 <= x <= 1
// UIT: acos(x), maximale fout 0.000071
float acos3(float x)
{
return((((-0.0186166*x+0.0740935)*x-0.212053)*x+1.57073)*sqrt(1.0f-x));
}
acos1() heeft een maximale fout van 0.0061, acos2() van 0.00061 en acos3() van 0.000071.
Omdat we die functie in onze formule 2 keer nodig hebben, en de cirkelstraal van het katrolwiel 12.49 is,
zijn de maximale fouten in de draadlengte bij
- acos1(): 0.0061 * 2 * 12.49 = 0.15
- acos2(): 0.00061 * 2 * 12.49 = 0.015
- acos3(): 0.000071 * 2 * 12.49 = 0.0018
Afhankelijk van de nauwkeurigheid van je motor kan je de optimale acos() kiezen.
Als ik op mijn desktop acos() in een lus 10^9 keer aanroep, dan dit duurt bij:
- acos1() 2.25 sec
- acos2() 2.48 sec
- acos3() 2.76 sec
terwijl de normale acos() (wel met double nauwkeurigheid) hier 52.8 sec over doet.
De bulk van het werk in de 3 benaderingsformules wordt waarschijnlijk veroorzaakt door de sqrt() berekening erin; de extra vermenigvuldigen, elk met factor 10 nauwkeurigheidswinst, lijken er niet zo toe te doen.
Alle 3 zijn ze wel zo'n 20 keer sneller dan de ingebouwde acos() functie.
Ik heb geen arduino, maar je kan zelf testen wat daarop de snelheidsverschillen zijn.
Ditzelfde kan je doen voor optellen, vermenigvuldigen etc. van float getallen versus long getallen.
Mocht je nog in assembly programmeren: het artikel geeft bovenstaande functies ook in een assembly vorm.
ik wil wel eens kijken wat het uitmaak.... maar ik heb dit al 3 keer door gelezen.... maar nu hoe ik het moet toepasen....
?
Code: Selecteer alles
long Mot1(float X, float Y, float Z)
{
// z,y,z uit rekenen van uit main x,y,z
// x,y,z van hoek 1
long result;
float XCorner1 = -(LengthFrame / 2.0);
float yCorner1 = -(WidhtFrame / 2.0);
float zCorner1 = (HighFrame / 2.0);
float Mot1LengthX = XCorner1 - X;
float Mot1lengthY = yCorner1 - Y;
float Mot1lengthZ = zCorner1 - Z;
float DB = Pythagoras(Mot1lengthY, Mot1LengthX, Mot1lengthZ);
float BP = DB - (DiaKatrol / 2.0);
float MP = zCorner1 - Z;
float BM = Pythagoras(MP, BP, 0);
float BK = Pythagoras(BM, (DiaKatrol / 2.0), 0);
float hoekKLM = phi - asin(BK / BM) - asin(BP / BM);
float KL = (DiaKatrol / 2.0) * hoekKLM;
float Mot1Length = BK + KL;
// Serial.print("Length Motor 1 :");
// Serial.print(Mot1Length);
// Serial.print("mm, total Steps :");
// Serial.println(Mot1Length * StepUnit);
result = ((Mot1Length * StepUnit) + 0.5);
return result;
};
ik heb deze code voor elke motor... daar heb ik 2x asin...
maar ik voer dit stuk best wel vaak uit... en natuurlijk voor alle 8 de motoren....
ik heb trouwens dit :
Code: Selecteer alles
float XCorner1 = -(LengthFrame / 2.0);
float yCorner1 = -(WidhtFrame / 2.0);
float zCorner1 = (HighFrame / 2.0);
ook ff ergens aan het begin gezet, by de setup... die hoef natuurlijk niet elke keer uitgerekend te worden.... er varanderd niets aan....
of ik het in assembly doe... pfff vroeger veel in Z80 assembly gewerkt...maar dit is allemaal in c++
[quote=RedCat post_id=1164177 time=1638212993 user_id=81532]
[quote=Swets post_id=1164158 time=1638184629 user_id=72692]
... maar ja , er komt steeds meer rekenwerk in, en nu dus de asin ...
[/quote]
Als het je om snelheid gaat, dan kunnen we waarschijnlijk veel winst behalen met een grovere benadering voor asin(), zie bijvoorbeeld
[url]https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/[/url]
De asin() functie is in dat artikel een uitbreiding van de acos() functie. Als we onze formule omzetten naar acos() (in plaats van asin()) zijn we hiermee dus nog sneller:
[tex]\small ∠KML = \pi - ∠KMB - ∠BMP = \pi - acos\left(\frac{MK}{BM}\right) - acos\left(\frac{abs(mz-bz)}{BM}\right) [/tex]
Hier werken we met hoeken van 0 .. pi/2 (= van 0° .. 90°), aangenomen dat de onderkant van het blok nooit boven het middelpunt van de bovenste katrol uit zal komen.
Daarom kunnen we de benaderingsformules van dat artikel nog verder vereenvoudigen:
[code]// IN: 0 <= x <= 1
// UIT: acos(x), maximale fout 0.0061
float acos1(float x)
{
return((-0.155972*x+1.56467)*sqrt(1.0f-x));
}
[/code]
[code]// IN: 0 <= x <= 1
// UIT: acos(x), maximale fout 0.00061
float acos2(float x)
{
return(((0.0464619*x-0.201877)*x+1.57018)*sqrt(1.0f-x));
}[/code]
[code]// IN: 0 <= x <= 1
// UIT: acos(x), maximale fout 0.000071
float acos3(float x)
{
return((((-0.0186166*x+0.0740935)*x-0.212053)*x+1.57073)*sqrt(1.0f-x));
}[/code]
acos1() heeft een maximale fout van 0.0061, acos2() van 0.00061 en acos3() van 0.000071.
Omdat we die functie in onze formule 2 keer nodig hebben, en de cirkelstraal van het katrolwiel 12.49 is,
zijn de maximale fouten in de draadlengte bij
- acos1(): 0.0061 * 2 * 12.49 = 0.15
- acos2(): 0.00061 * 2 * 12.49 = 0.015
- acos3(): 0.000071 * 2 * 12.49 = 0.0018
Afhankelijk van de nauwkeurigheid van je motor kan je de optimale acos() kiezen.
Als ik op mijn desktop acos() in een lus 10^9 keer aanroep, dan dit duurt bij:
- acos1() 2.25 sec
- acos2() 2.48 sec
- acos3() 2.76 sec
terwijl de normale acos() (wel met double nauwkeurigheid) hier 52.8 sec over doet.
De bulk van het werk in de 3 benaderingsformules wordt waarschijnlijk veroorzaakt door de sqrt() berekening erin; de extra vermenigvuldigen, elk met factor 10 nauwkeurigheidswinst, lijken er niet zo toe te doen.
Alle 3 zijn ze wel zo'n 20 keer sneller dan de ingebouwde acos() functie.
Ik heb geen arduino, maar je kan zelf testen wat daarop de snelheidsverschillen zijn.
Ditzelfde kan je doen voor optellen, vermenigvuldigen etc. van float getallen versus long getallen.
Mocht je nog in assembly programmeren: het artikel geeft bovenstaande functies ook in een assembly vorm.
[/quote]
ik wil wel eens kijken wat het uitmaak.... maar ik heb dit al 3 keer door gelezen.... maar nu hoe ik het moet toepasen....
?
[code]
long Mot1(float X, float Y, float Z)
{
// z,y,z uit rekenen van uit main x,y,z
// x,y,z van hoek 1
long result;
float XCorner1 = -(LengthFrame / 2.0);
float yCorner1 = -(WidhtFrame / 2.0);
float zCorner1 = (HighFrame / 2.0);
float Mot1LengthX = XCorner1 - X;
float Mot1lengthY = yCorner1 - Y;
float Mot1lengthZ = zCorner1 - Z;
float DB = Pythagoras(Mot1lengthY, Mot1LengthX, Mot1lengthZ);
float BP = DB - (DiaKatrol / 2.0);
float MP = zCorner1 - Z;
float BM = Pythagoras(MP, BP, 0);
float BK = Pythagoras(BM, (DiaKatrol / 2.0), 0);
float hoekKLM = phi - asin(BK / BM) - asin(BP / BM);
float KL = (DiaKatrol / 2.0) * hoekKLM;
float Mot1Length = BK + KL;
// Serial.print("Length Motor 1 :");
// Serial.print(Mot1Length);
// Serial.print("mm, total Steps :");
// Serial.println(Mot1Length * StepUnit);
result = ((Mot1Length * StepUnit) + 0.5);
return result;
};
[/code]
ik heb deze code voor elke motor... daar heb ik 2x asin...
maar ik voer dit stuk best wel vaak uit... en natuurlijk voor alle 8 de motoren....
ik heb trouwens dit :
[code]
float XCorner1 = -(LengthFrame / 2.0);
float yCorner1 = -(WidhtFrame / 2.0);
float zCorner1 = (HighFrame / 2.0);[/code]
ook ff ergens aan het begin gezet, by de setup... die hoef natuurlijk niet elke keer uitgerekend te worden.... er varanderd niets aan....
of ik het in assembly doe... pfff vroeger veel in Z80 assembly gewerkt...maar dit is allemaal in c++