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

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 ]]

Related

Creating a logarithmic spaced array in IDL

I was looking for a way to generate a logarithmic spaced array in IDL.
From the L3 Harris Geospatial website I came across "arrgen" and was trying to use it for this purpose. However,
arrgen(1,215,/log)
returns the error: Variable is undefined: ARRGEN.
What would be the correct way to do it?
Thanks in advance for your help
Start by defining your lower and upper bounds in which ever log-base you prefer. I will use base $e$ for brevity sake.
lowe = ALOG(low[0])
uppe = ALOG(upp[0])
where low and upp are scalar, numerical values you, the user, define (e.g., 1 and 215 in your example). Then construct an evenly spaced array of n elements, such as:
dinde = DINDGEN(n[0])*(uppe[0] - lowe[0])/(n[0] - 1L) + lowe[0]
where n is a scalar integer. Now convert back to linear space to get:
dind = EXP(dinde)
This will be a logarithmically spaced array. If you want to use base-10 log, then substitute ALOG for ALOG10. If you need another base, then you can use the logarithmic change of base rule given by:
logb x = logc x / logc b

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

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

Creating a linearly spaced array of a particular size

I am new to MATLAB and currently working on my homework assignment. I am trying to declare the x variable as the following:
Create a linearly spaced array x of size (1 × 200) comprising values ranging from –pi to pi.
I've tried this code:
x=[-pi:200:pi];
but I'm not sure if it's the correct way to do this or not.
You can use linspace as follow:
x = linspace(-pi, pi, 200);
check this out for an example:
https://www.mathworks.com/help/matlab/ref/linspace.html
The other answer shows how to use linspace, this is the correct method.
But you can also use the colon operator and some simple arithmetic to do this:
x = -pi : 2*pi/199 : pi -- This means: go from -π to π in steps of such a size that we get exactly 200 values.
x = (0:199) * (2*pi/199) - pi -- This means: create an array with 200 integer values, then scale them to the right range.
Note that you shouldn't use square brackets [] here. They are for concatenating arrays. The colon operator creates a single array, there is nothing to concatenate it with.

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);
}

Dynamically creating and naming an array

Consider the following code snippet
for i = 1:100
Yi= x(i:i + 3); % i in Yi is not an index but subscript,
% x is some array having sufficient values
i = i + 3
end
Basically I want that each time the for loop runs the subscript changes from 1 to 2, 3, ..., 100. SO in effect after 100 iterations I will be having 100 arrays, starting with Y1 to Y100.
What could be the simplest way to implement this in MATLAB?
UPDATE
This is to be run 15 times
Y1 = 64;
fft_x = 2 * abs(Y1(5));
For simplicity I have taken constant inputs.
Now I am trying to use cell based on Marc's answer:
Y1 = cell(15,1);
fft_x = cell(15,1);
for i = 1:15
Y1{i,1} = 64;
fft_x{i,1} = 2 * abs(Y1(5));
end
I think I need to do some changes in abs(). Please suggest.
It is impossible to make variably-named variables in matlab. The common solution is to use a cell array for Y:
Y=cell(100,1);
for i =1:100
Y{i,1}= x(i:i+3);
i=i+3;
end
Note that the line i=i+3 inside the for-loop has no effect. You can just remove it.
Y=cell(100,1);
for i =1:100
Y{i,1}= x(i:i+3);
end
It is possible to make variably-named variables in matlab. If you really want this do something like this:
for i = 1:4:100
eval(['Y', num2str((i+3)/4), '=x(i:i+3);']);
end
How you organize your indexing depends on what you plan to do with x of course...
Yes, you can dynamically name variables. However, it's almost never a good idea and there are much better/safer/faster alternatives, e.g. cell arrays as demonstrated by #Marc Claesen.
Look at the assignin function (and the related eval). You could do what asked for with:
for i = 1:100
assignin('caller',['Y' int2str(i)],rand(1,i))
end
Another related function is genvarname. Don't use these unless you really need them.

Resources