How to implement 3rd order Polynomial Formula calculations in C on a 16bit MCU - c

it is my first time posting but I'll start by apologizing in advance if this question has been asked before.
I have been struggling on how to implement a 3rd order polynomial formula in C because of either extremely small values or larger than 32bit results (on a 16bit MCU).
I use diffrent values but as an example I would like to compute for "Y" in formula:
Y = ax^3 + bx^2 + cx + d = 0.00000012*(1024^3) + 0.000034*(1024^2) + 0.056*(1024) + 789.10
I need to use a base32 to get a meaningful value for "a" = 515
If I multiply 1024^3 (10bit ADC) then I get a very large amount of 1,073,741,824
I tried splitting them up into "terms A, B, C, and D" but I am not sure how to merge them together because of different resolution of each term and limitation of my 16bit MCU:
u16_TermA = fnBase32(0.00000012) * AdcMax * AdcMax * AdcMax;
u16_TermB = fnBase24(0.000034) * AdcMax * AdcMax;
u16_TermC = fnBase16(0.056) * AdcMax;
u16_TermD = fnBase04(789.10);
u16_Y = u16_TermA + u16_TermB + u16_TermC + u16_TermD;
/* AdcMax is a variable 0-1024; u16_Y needs to be 16bit */
I'd appreciate any help on the matter and on how best to implement this style of computations in C.
Cheers and thanks in advance!

One step toward improvement:
ax^3 + bx^2 + cx + d --> ((a*x + b)*x + c)*x + d
It is numerically more stable and tends to provide more accurate answers near the zeros of the function and less likely to overflow intermediate calculations.
2nd idea; consider scaling the co-efficents if they maintain their approximate relative values as given on the question.
N = 1024; // Some power of 2
aa = a*N*N*N
bb = b*N*N
cc = c*N
y = ((aa*x/N + bb)*x/N + cc)*x/N + d
where /N is done quickly with a shift.
With a judicious selection of N (maybe 2**14 for high precision avoid 32-bit overflow), then entire code might be satisfactorily done using only integer math.
As aa*x/N is just a*x*N*N, I think a scale of 2**16 works well.
Third idea:
In addition to scaling, often such cubic equations can be re-written as
// alpha is a power of 2
y = (x-root1)*(x-root2)*(x-root3)*scale/alpha
Rather than a,b,c, use the roots of the equation. This is very satisfactory if the genesis of the equation was some sort of curve fitting.
Unfortunately, OP's equation roots has a complex root pair.
x1 = -1885.50539
x2 = 801.08603 + i * 1686.95936
x3 = 801.08603 - i * 1686.95936
... in which case code could use
B = -(x1 + x2);
C = x1 * x2;
y = (x-x1)*(x*x + B*x + C)*scale/alpha

Related

How do you iterate through multiple arrays and substitute values into an equation?

Don't know if I phrased the question correctly because it's sort of hard to explain. But I have three arrays which represent temperature, salinity, and depth. They're massive so I've put the simplified versions of them below just to get the gist:
t = (np.arange(26)[25:21:-1]).reshape(2,2)
s = (np.arange(34,35,0.25).reshape(2,2))
z = (np.arange(0,100,25).reshape(2,2))
I have this equation here (also stripped down for simplicity):
velocity = 1402.5 + 5*(t) - (5.44 * 10**(-2) * t**(-2)) + (2.1 * 10**(-4) * t**(3)) + 1.33*(s) - (1.56*10**(-2)*z)
What I want to do is to iterate through the values from the t,s,z arrays and have them substituted into the equation to calculate velocity for each case. I want the resultant value to then append into a new array with the same configuration - (2,2) in this case. I can't seem to figure out the best way to approach this, so any sort of feedback would be appreciated.
Cheers!
Just use the same equation as-is with one change:
velocity = 1402.5 + 5*(t) - (5.44 * 10**(-2.0) * t**(-2.0)) + (2.1 * 10**(-4) * t**(3)) + 1.33*(s) - (1.56*10**(-2)*z)
Change: t**(-2) has been changed to t**(-2.0). To better understand why we need to change the type of the exponent see the answer here: https://stackoverflow.com/a/43287598/13389591.
The above gives the output:
[[1576.00116296 1570.56544556]
[1565.15996716 1559.7834676 ]]

Converting C code into R code: parsing to change a C function in R (pow(a,b) to a^b)

I am using Mathematica to generate equations as C code (using CForm[]), in order to export the equation as a character string and use it in R.
For example, the CForm[] output imported into R as a character string looks like this:
"Tau * Power(Omega * (-(R * Gamma) + R),(Tau + R))"
My question is how best to convert the above C code into an R expression like this:
Tau * (Omega * (-(R * Gamma) + R ))^(Tau + R)
Following a suggestion from an earlier post about converting Mathematica code into R code (Convert Mathematica equations into R code), I'm aware that a reasonable thing to do is to redefine Power() as a function, i.e.,:
Power <- function(a,b) {a^b}
But, through a series of tests, I discovered that evaluating an expression that's in the form of:
eval(parse(text="Tau * (Omega * (-(R * Gamma) + R ))^(Tau + R)"))
is much faster (about 4 times fast on my mac) than the alternative of defining Power() as a function and evaluating the following:
eval(parse(text="Tau * Power(Omega * (-(R * Gamma) + R),(Tau + R))"))
It seems like a complex pattern matching problem, but I could not find any solutions. I appreciate any suggestions.
There are multiple issues here:
Your equation is not standard C code. CForm[] from Mathematica is not translating your code to proper C syntax. Perhaps you could follow this answer and use SymbolicC to solve this part
Your question is more about parsing from Language A to Language B. As mentioned by #Olaf in the comments: You might be better of either using a true C function and call it from R or convert it manually, depending on how often you do this
But, as per your request (if I understood correctly what you want to achieve) and for educational purposes; here's an example in which we will use R to convert your "pseudo-C" string and create an in-lined cfunction()
Note: This is by no mean intended to be elegant or practical, but the general idea should hopefully help you getting started
Assuming the following equation:
v1 <- "4 * Power(Omega * (-(R * Gamma) + R),(Tau + R))"
Extract all variables and functions from the original string
n1 <- stringi::stri_extract_all_words(v1)[[1]]
Create a named vector of "functions to recode" (and a subset without them and without numerics)
newFunc <- c("Power" = "pow")
n2 <- setdiff(n1, names(newFunc))
n3 <- n2[is.na(as.numeric(n2))]
Build a replacement list to feed gsubfn(). For the sake of this example, we replace the old function with the new one and wrap asReal() around the variables
toreplace <- setNames(
as.list(c(newFunc, paste0("asReal(", n3, ")"))),
c(names(newFunc), n3)
)
v2 <- gsubfn::gsubfn(paste(names(toreplace), collapse = "|"), toreplace, v1)
You could then pass this new string to a cfunction() to execute in R
#install.packages("inline")
library(inline)
foo <- cfunction(
sig = setNames(rep("integer", length(n3)), n3),
body = paste0(
"SEXP result = PROTECT(allocVector(REALSXP, 1));
REAL(result)[0] = ", v2, ";
UNPROTECT(1);
return result;"
)
)
This should be faster than using eval(parse("...")) with ^ or defining a Power() function
Tau = 21; Omega = 22; R = 42; Gamma = 34
Power <- function(x,y) {x^y}
microbenchmark::microbenchmark(
C = foo(Omega, R, Gamma, Tau),
R1 = eval(parse(text="4 * ((Omega * (-(R * Gamma) + R ))^(Tau + R))")),
R2 = eval(parse(text="4 * Power(Omega * (-(R * Gamma) + R),(Tau + R))")),
times = 10L
)
#Unit: microseconds
# expr min lq mean median uq max neval
# C 1.233 2.194 5.9555 2.9955 3.302 34.194 10
# R1 190.012 202.781 230.5187 218.1035 243.891 337.209 10
# R2 189.162 191.798 374.5778 207.6875 225.078 1868.746 10

Freefem Fisher's equation

I'm new with Freefem++, the problem I'm trying to solve is Fisher's equation:
du/dt = d^2u/dx^2 + d^2u/dy^2 + k * u * (1-u)
du/dn = 0 - border condition
I've tried to reformulate the problem in weak form, however Freefem shows a mistake with formula:
problem Fisher(uh, vh) = int2d(Th)(uh * vh/dt + Grad(uh)' * Grad(vh) ) - int2d(Th)(k * uh * vh) + int2d(Th)(uh0 * vh/dt) - int2d(Th)(k * uh * vh * uh);
Could you please tell what I do wrong? Something is wrong with last terms.
This is a 2D transient diffusion/conduction equation with a temperature-dependent, non-linear generation term.
If you leave off the non-linear generation term, the equations should look exactly like the weak form for the 2D transient diffusion/conduction equation.
How does freefem++ linearize that non-linear term? How did you plan to handle it?
You realize, of course, that the last term makes the solution a very different animal. You have to use iteration within time steps to solve it (e.g. a Newton-Raphson solver).
The algorithm becomes an iterative, non-linear one. You won't solve for u anymore; you'll solve for an increment du and iterate until convergence.
You linearize the last term like this:
d(k*u(1-u)) = k*du(1-u) - k*u*du = k*(1-2*u)*du ~ k*du
You still have a product u*du that's non-linear. What to do? Throw it away.
Now you're solving a non-linear transient equation for du.
The easiest way to model Fisher's equations is to linearize the nonlinear part so that the computational method stays stable. In our case it means that in discrete formulations we replace the term u_i(1 - u_i) with u_{i-1}(1 - u_i) (where i is time counter) and choose attentively the space and time steps. Here I provide an example of resulting code:
verbosity=0.;
real Dx=.1,Dy=.1;
mesh Th=square(floor(10./Dx),floor(10./Dy), [-5 + 10*x, -5 + 10*y]);
fespace Vh(Th,P1);
Vh uh, vh, uh0 = ((x)^2+(y)^2)<=1;
real mu = 0.1, dt=0.01, Tf=10., k = 3.0;
macro Grad(u)[dx(u),dy(u)]//
problem KFisher(uh,vh) = int2d(Th)(uh*vh/dt + Grad(uh)'*Grad(vh)*mu) - int2d(Th)(uh0*vh/dt) + int2d(Th)(k*uh0*uh*vh) - int2d(Th)(k*vh*uh0);
for (real t=0.;t<Tf;t+=dt)
{
KFisher;
uh0 = uh;
plot(uh0, cmm="t="+t+"[sec]", dim=2, fill=true, value=true, wait=0);
}

2d trilateration

I am writing some code to participate in an AI challenge. The main objective for the AI challenge is to take a simulated robot and navigate it through a maze to a destination zone. The secondary objective which is optional is to find a recharger placed in the maze at an unknown location. This is all done in a 2D grid.
My program can call a method to get a distance measurement from the recharger. So using trilateration I should be able to locate the recharger by calling this method, recording my ai's current position and the distance the recharger is away from that point 3 times over.
I found this example of trilateration on wikipedia http://en.wikipedia.org/wiki/Trilateration but this applies to a 3d space. I'm only dealing with a 2D space. Also I don't understand how to use the formula shown in Wikipedia, searching the web for a working example with numbers plugged in and boiling down to the final coordinates is scarce with Google searches.
I'm not a math major; I am just an enthusiast exploring AI problems.
An explanation and step by step example of how to calculate the problem is what I need as mathematics are not my strong point. Below is some sample data:
Point 1: x=39, y=28, distance=8
Point 2: x=13, y=39, distance=11
Point 3: x=16, y=40, distance=8
Any example using my sample data would be greatly appreciated. The programming to this will be very straight forward once I can wrap my head around the mathematics.
As the Wikipedia trilateriation article describes, you compute (x,y) coordinates by successively calculating: ex, i, ey, d, j, x, y. You have to be familiar with vector notation, so, for example, ex = (P2 - P1) / ‖P2 - P1‖ means:
ex,x = (P2x - P1x) / sqrt((P2x - P1x)2 + (P2y - P1y)2)
ex,y = (P2y - P1y) / sqrt((P2x - P1x)2 + (P2y - P1y)2)
Your data is:
P1 = (39, 28); r1 = 8
P2 = (13, 39); r2 = 11
P3 = (16, 40); r3 = 8
The calculation steps are:
ex = (P2 - P1) / ‖P2 - P1‖
i = ex(P3 - P1)
ey = (P3 - P1 - i · ex) / ‖P3 - P1 - i · ex‖
d = ‖P2 - P1‖
j = ey(P3 - P1)
x = (r12 - r22 + d2) / 2d
y = (r12 - r32 + i2 + j2) / 2j - ix / j

Calculate initial velocity to move a set distance with inertia

I want to move something a set distance. However in my system there is inertia/drag/negative accelaration. I'm using a simple calculation like this for it:
v = oldV + ((targetV - oldV) * inertia)
Applying that over a number of frames makes the movement 'ramp up' or decay, eg:
v = 10 + ((0 - 10) * 0.25) = 7.5 // velocity changes from 10 to 7.5 this frame
So I know the distance I want to travel and the acceleration, but not the initial velocity that will get me there. Maybe a better explanation is I want to know how hard to hit a billiard ball so that it stops on a certain point.
I've been looking at Equations of motion (http://en.wikipedia.org/wiki/Equations_of_motion) but can't work out what the correct one for my problem is...
Any ideas? Thanks - I am from a design not science background.
Update: Fiirhok has a solution with a fixed acceleration value; HTML+jQuery demo:
http://pastebin.com/ekDwCYvj
Is there any way to do this with a fractional value or an easing function? The benefit of that in my experience is that fixed acceleration and frame based animation sometimes overshoots the final point and needs to be forced, creating a slight snapping glitch.
This is a simple kinematics problem.
At some time t, the velocity (v) of an object under constant acceleration is described by:
v = v0 + at
Where v0 is the initial velocity and a is the acceleration. In your case, the final velocity is zero (the object is stopped) so we can solve for t:
t = -v0/a
To find the total difference traveled, we take the integral of the velocity (the first equation) over time. I haven't done an integral in years, but I'm pretty sure this one works out to:
d = v0t + 1/2 * at^2
We can substitute in the equation for t we developed ealier:
d = v0^2/a + 1/2 * v0^2 / a
And the solve for v0:
v0 = sqrt(-2ad)
Or, in a more programming-language format:
initialVelocity = sqrt( -2 * acceleration * distance );
The acceleration in this case is negative (the object is slowing down), and I'm assuming that it's constant, otherwise this gets more complicated.
If you want to use this inside a loop with a finite number of steps, you'll need to be a little careful. Each iteration of the loop represents a period of time. The object will move an amount equal to the average velocity times the length of time. A sample loop with the length of time of an iteration equal to 1 would look something like this:
position = 0;
currentVelocity = initialVelocity;
while( currentVelocity > 0 )
{
averageVelocity = currentVelocity + (acceleration / 2);
position = position + averageVelocity;
currentVelocity += acceleration;
}
If you want to move a set distance, use the following:
Distance travelled is just the integral of velocity with respect to time. You need to integrate your expression with respect to time with limits [v, 0] and this will give you an expression for distance in terms of v (initial velocity).

Resources