I've been having issues implementing a built-in controls algorithm (LQR) in Modelica/Dymola. I've created a simpler model that shows the problems I've been having.
Basically, I am calling LQR externally and passing it a matrix with an entry (named Ctest) that changes each time step. This Ctest is also found through an external function named findC.
The funny thing is, Dymola will run fine for if you make Ctest = 0, but if you make Ctest = 0 in an if-loop, it shows the many errors which look something like this:
Unsupported: In function Modelica_LinearSystems2.Math.Matrices.dare variable AT was declared with dimension ":".
That is not yet supported in dsmodel.c, and the function will fail if called in the model.
For example, I ran 3 different cases with the following code:
1. in function findC, if you define C as 0 (as copied below) everything runs fine.
2. if you instead make an if loop in which C will still be 0, the model won't simulate. I've copied the if loop below and commented it out.
3. if you keep findC as in case 1, but just uncomment "Real tether_l = 151.61;", it gives the same errors as case 2.
Any help would be greatly appreciated!
model SimplerModel
import Utilities;
Modelica.Mechanics.MultiBody.Joints.FreeMotion freeMotion(
useQuaternions=false,
angles_fixed=true,
r_rel_a(start={1,0,0}, fixed=true),
v_rel_a(start={0,0,0}, fixed=true),
a_rel_a(start={0,0,0}),
angles_start={0,0,0},
w_rel_a_fixed=true,
w_rel_a_start={0,0,0},
z_rel_a_fixed=false)
annotation (Placement(transformation(extent={{-50,60},{-30,80}})));
Modelica.Mechanics.MultiBody.Parts.BodyShape bodyShape(
r={0,0,1},
m=600,
I_11=100,
I_22=100,
I_33=500,
angles_start={0,0,0},
sequence_start={1,2,3},
w_0_start={0,0,0},
z_0_start={0,0,0},
r_0(start={0,0,0}),
v_0(start={0,0,0}),
a_0(start={0,0,0}),
angles_fixed=false,
w_0_fixed=false,
z_0_fixed=false,
r_CM={0,0,0.5})
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
inner Modelica.Mechanics.MultiBody.World world
annotation (Placement(transformation(extent={{-80,60},{-60,80}})));
Real[6,6] restMat=
[276533.0, 0.0, 0.0, 0.0, 0.0, 0.0;
0.0, 276533.0, 0.0, 0.0, 0.0, 0.0;
Ctest, 0.0, 319160000.0, 0.0, 0.0, 0.0;
0.0, 0.0, 0.0, 86086300000.0, 0.0, 0.0;
0.0, 0.0, 0.0, 0.0, 86086300000.0, 0.0;
0.0, 0.0, 0.0, 0.0, 0.0, 146286000.0];
Real Ctest = Utilities.findC(bodyShape.frame_a.r_0[1]);
Real K_cat[:,:] = Utilities.findK(restMat);
equation
connect(freeMotion.frame_b, bodyShape.frame_a) annotation (Line(
points={{-30,70},{-20,70},{-20,0},{-10,0}},
color={95,95,95},
thickness=0.5,
smooth=Smooth.None));
connect(world.frame_b, freeMotion.frame_a) annotation (Line(
points={{-60,70},{-50,70}},
color={95,95,95},
thickness=0.5,
smooth=Smooth.None));
annotation (uses(Modelica(version="3.2")), Diagram(coordinateSystem(
preserveAspectRatio=false, extent={{-100,-100},{100,100}}), graphics));
end SimplerModel;
function findK
function findK
import Modelica_LinearSystems2;
input Real[6,6] restoring;
Real cyl_mass = 8.21e6;
Real[6,6] mass = [1.253e7, 0,0,0,-2.99e8,0;
0,1.253e7,0,2.99e8,0,0;
0,0,1.6746e6,0,0,0;
0,2.99e8,0,9.549e9,0,0;
-2.99e8,0,0,0,9.549e9,0;
0,0,0,0,0,3.4728e7];
Real[6,6] damping = [1e5,0,0,0,0,0;
0,1e5,0,0,0,0;
0,0,1.3e5,0,0,0;
0,0,0,0,0,0;
0,0,0,0,0,0;
0,0,0,0,0,1.3e7];
Real Ipitroll = 384770000;
Real Iyaw = 291440000;
protected
Real[6,6] addMassMat = [0,0,0,0,0,0;
0,0,0,0,0,0;
0,0,cyl_mass,0,0,0;
0,0,0,Ipitroll,0,0;
0,0,0,0,Ipitroll,0;
0,0,0,0,0,Iyaw];
Real[6,6] massMat = Modelica.Math.Matrices.inv(mass + addMassMat);
Real[4, 4] A_cat = cat(1, cat(2,zeros(2,2), identity(2)), cat(2, -restoring[4:5,:]*massMat[:,4:5],-damping[4:5,:]*massMat[:,4:5]));
Real[4, 2] B_cat = cat(1, cat(1,zeros(2,2), 23/cyl_mass*identity(2)));
Real[2, 4] C_cat = cat(2, identity(2), zeros(2,2));
Real[2, 2] D_cat = zeros(2, 2);
Real[4,4] Q = [1e8,0,0,0;
0,1e8,0,0;
0,0,1e-8,0;
0,0,0,1e-8];
Real[2,2] R = [1e-9,0;
0,1e-9];
output Real K_cat[6,6];
algorithm
K_cat := Modelica_LinearSystems2.StateSpace.Design.lqr(Modelica_LinearSystems2.StateSpace(A_cat,B_cat,C_cat,D_cat), Q, R);
end findK;
function findC
function findC
input Real x;
output Real C;
//Real tether_l = 151.61;
//Real slope_ForceVsHeave = 3.1928e8;
//Real intercept_ForceVsHeave = 0;
//Real heave = tether_l - sqrt(tether_l^2 - x^2);
algorithm
//if abs(x) == 0.0 then
//C := 0;
//else C := 0;
//end if;
C:=0;
end findC;
Thanks a lot! :)
Unsupported: In function Modelica_LinearSystems2.Math.Matrices.dare
variable AT was declared with dimension ":"
means that you have to declare the dimension of your inputs, like:
...
input Integer n;
input Real[n] C;
...
because this, if compiled, will lead into an error:
...
input Real[:] C;
...
I think that one problem in your if-statement is that
if abs(x) == 0.0 then
should be replaced with
Modelica.Math.isEqual(abs(x),0,1e-15)
because you cannot compare the equality of two real numbers in Modelica.
I hope this helps,
Marco
I think Marco is right, that the problem is that the functions you are using contain variables of unknown dimensions and Dymola cannot handle this in a model. For example the dare function has:
Real AT[:, :]=transpose(A);
Try rewriting the code so that all the :'s are replaced with sizes, you may have to create functions in some cases to calculate what these sizes are going to be.
What version of Dymola are you using? I put the code, as is, into Dymola 2014 and it returned a long list of "variable ? was declared with dimension ":"."
Also I think all Real variables in functions should be protected.
Hopefully fixing this will sort out the problem.
This is the code after modifying according to the two answers (declare sizes of all matrices, protect Reals in functions, change if condition):
model SimplerModel
import OnWind.Components.Substructure.Utilities;
Modelica.Mechanics.MultiBody.Joints.FreeMotion freeMotion(
useQuaternions=false,
angles_fixed=true,
r_rel_a(start={0.5,0,0}, fixed=true),
v_rel_a(start={0,0,0}, fixed=true),
a_rel_a(start={0,0,0}),
angles_start={0,0,0},
w_rel_a_fixed=true,
w_rel_a_start={0,0,0},
z_rel_a_fixed=false)
annotation (Placement(transformation(extent={{-50,60},{-30,80}})));
Modelica.Mechanics.MultiBody.Parts.BodyShape bodyShape
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
inner Modelica.Mechanics.MultiBody.World world
annotation (Placement(transformation(extent={{-80,60},{-60,80}})));
//input Integer hi = 1;
Real[6,6] restMat=
[276533.0, 0.0, 0.0, 0.0, 0.0, 0.0;
0.0, 276533.0, 0.0, 0.0, 0.0, 0.0;
Ctest, 0.0, 319160000.0, 0.0, 0.0, 0.0;
0.0, 0.0, 0.0, 86086300000.0, 0.0, 0.0;
0.0, 0.0, 0.0, 0.0, 86086300000.0, 0.0;
0.0, 0.0, 0.0, 0.0, 0.0, 146286000.0];
Real Ctest = Utilities.findC(bodyShape.frame_b.r_0[1]);
Real K_cat[2,4] = Utilities.findK(restMat);
equation
connect(freeMotion.frame_b, bodyShape.frame_a) annotation (Line(
points={{-30,70},{-20,70},{-20,0},{-10,0}},
color={95,95,95},
thickness=0.5,
smooth=Smooth.None));
connect(world.frame_b, freeMotion.frame_a) annotation (Line(
points={{-60,70},{-50,70}},
color={95,95,95},
thickness=0.5,
smooth=Smooth.None));
annotation (uses(Modelica(version="3.2")), Diagram(coordinateSystem(
preserveAspectRatio=false, extent={{-100,-100},{100,100}}), graphics));
end SimplerModel;
function findK
function findK
import Modelica_LinearSystems2;
input Real[6,6] restoring;
protected
Real cyl_mass = 8.21e6;
Real[6,6] mass = [1.253e7, 0,0,0,-2.99e8,0;
0,1.253e7,0,2.99e8,0,0;
0,0,1.6746e6,0,0,0;
0,2.99e8,0,9.549e9,0,0;
-2.99e8,0,0,0,9.549e9,0;
0,0,0,0,0,3.4728e7];
Real[6,6] damping = [1e5,0,0,0,0,0;
0,1e5,0,0,0,0;
0,0,1.3e5,0,0,0;
0,0,0,0,0,0;
0,0,0,0,0,0;
0,0,0,0,0,1.3e7];
Real Ipitroll = 384770000;
Real Iyaw = 291440000;
Real[6,6] addMassMat = [0,0,0,0,0,0;
0,0,0,0,0,0;
0,0,cyl_mass,0,0,0;
0,0,0,Ipitroll,0,0;
0,0,0,0,Ipitroll,0;
0,0,0,0,0,Iyaw];
Real[6,6] massMat = Modelica.Math.Matrices.inv(mass + addMassMat);
Real[4, 4] A_cat = cat(1, cat(2,zeros(2,2), identity(2)), cat(2, -restoring[4:5,:]*massMat[:,4:5],-damping[4:5,:]*massMat[:,4:5]));
Real[4, 2] B_cat = cat(1, cat(1,zeros(2,2), 23/cyl_mass*identity(2)));
Real[2, 4] C_cat = cat(2, identity(2), zeros(2,2));
Real[2, 2] D_cat = zeros(2, 2);
Real[4,4] Q = [1e8,0,0,0;
0,1e8,0,0;
0,0,1e-8,0;
0,0,0,1e-8];
Real[2,2] R = [1e-9,0;
0,1e-9];
output Real K_cat[2,4];
algorithm
K_cat := Modelica_LinearSystems2.StateSpace.Design.lqr(Modelica_LinearSystems2.StateSpace(A_cat,B_cat,C_cat,D_cat), Q, R);
end findK;
function findC
function findC
input Real x;
output Real C;
//Real tether_l = 151.61;
algorithm
C:=0;
/* if Modelica.Math.isEqual(abs(x),0,1e-15) then
C := 0;
else C := 0;
end if;
*/
end findC;
This should run as-is. But I've commented out necessary parts of function findC in order to make it work.
In findC, uncommenting either the declaration of unused variable tether_l (which is needed in my actual code) or the if statement (also needed in my code, but written here as a trivial statement just for this simpler example) will cause it to fail.
Just to summarize, Dymola produces a long list of "Unsupported: In function __ variable __ was declared with dimension ":"". But all of these variables are actually Dymola declared in Dymola functions. Some changes cause it to work, but these changes are unrelated to the matrices.
Would appreciate any ideas or advice! :)
Thanks
Related
Problem:
My goal is to write a code, that rotates the root joint of a bvh, θ degrees around global y axis3, and keeps values in the range of -180 to 180 (just like MotionBuilder does). I have tried to rotate a joint using euler, quaternions, matrices (considering the rotational order of a bvh) but I haven't yet figured out how to get the correct values. MotionBuilder calculates the values x,y,z so they are valid for the bvh file. I would like to write a code that calculates the rotation x,y,z for a joint, just like in MotionBuilder.
Example:
Initial: Root rotation: [x= -169.56, y=15.97, z=39.57]
After manually rotating about 45 degrees: Root rotation: [x=-117.81, y=49.37, z=70.15]
global y axis:
To rotate a node around the world Y axis any number of degrees the following works (https://en.wikipedia.org/wiki/Rotation_matrix):
import math
from pyfbsdk import *
angle = 45.0
radians = math.radians(angle)
root_matrix = FBMatrix()
root.GetMatrix(root_matrix, FBModelTransformationType.kModelRotation, True)
transformation_matrix = FBMatrix([
math.cos(radians), 0.0, math.sin(radians), 0.0,
0.0, 1.0, 0.0, 0.0,
-math.sin(radians), 0.0, math.cos(radians), 0.0,
0.0, 0.0, 0.0, 1.0
])
result_matrix = root_matrix * transformation_matrix
root.SetMatrix(result_matrix , FBModelTransformationType.kModelRotation, True)
If there are any Pre-Rotations on the root node the process is more complex and you can try setting the Rotations using the SetVector with the LRMToDof method.
result_vector = FBVector3d()
root.LRMToDof(result_vector, result_matrix)
root.SetVector(result_vector, FBModelTransformationType.kModelRotation, True)
I have to minimize a quite complicate function. For the minimization I use the NonLinearProgram from the Extreme Optimization Library. Since there´s no way to find a global minimum, I use different startpoints and choose, then the "best minimum". My problem is there can be some startpoints, which evaluatin can take a very long time. Is there some general way in F# or some special method in Extreme Optimization, to stop the evaluation let´s say after 10 min and just give a list with [nan; nan; nan; nan; nan; nan] back?
let funcFindPara (startpoint:float list) func =
let nlp = new NonlinearProgram(6)
// add the function
nlp.ObjectiveFunction <- (fun x -> func x.[0] x.[1] x.[2] x.[3] x.[4] x.[5])
// add lineare constraints
nlp.AddLinearConstraint("a + d > 0", Vector.Create(1.0, 0.0, 0.0, 1.0, 0.0, 0.0), 1.0e-5, infinity) |> ignore
nlp.AddLinearConstraint("c > 0", Vector.Create(0.0, 0.0, 1.0, 0.0, 0.0, 0.0), 1.0e-5, infinity) |> ignore
nlp.AddLinearConstraint("d > 0", Vector.Create(0.0, 0.0, 0.0, 1.0, 0.0, 0.0), 1.0e-5, infinity) |> ignore
nlp.AddLinearConstraint("gamma > 0", Vector.Create(0.0, 0.0, 0.0, 0.0, 1.0, 0.0), 1.0e-5, infinity) |> ignore
nlp.AddLinearConstraint("0 < rho_infty <= 1", Vector.Create(0.0, 0.0, 0.0, 0.0, 0.0, 1.0), 1.0e-5, 1.0) |> ignore
// add nonlinear constrains
// gamma <= -ln(rho_infty)
nlp.AddNonlinearConstraint((fun (x : Vector) -> x.[4] + log(x.[5])), ConstraintType.LessThanOrEqual, 0.0, (fun (x : Vector) -> fun (y : Vector) ->
y.[0] <- 0.0
y.[1] <- 0.0
y.[2] <- 0.0
y.[3] <- 0.0
y.[4] <- 1.0
y.[5] <- 1.0 / x.[5]
y
)
) |> ignore
// add starting point
nlp.InitialGuess <- Vector.Create(startpoint.[0], startpoint.[1], startpoint.[2], startpoint.[3], startpoint.[4], startpoint.[5])
// solve
let solution = nlp.Solve()
// return list with parameters
List.init 6 (fun index -> solution.[index])
You could wrap the function with async { } and pass that to RunSynchronously along with a timeout:
let withTimeout f timeout defaultValue =
try Async.RunSynchronously((async { return f() }), timeout)
with :? System.TimeoutException -> defaultValue
let longFn() =
System.Threading.Thread.Sleep(5000)
[1.0; 2.0; 3.0]
//Usage
withTimeout longFn 2000 [nan; nan; nan]
I asked this question before about how to pass a data array to a fragment shader for coloring a terrain, and it was suggested I could use a texture's RGBA values.
I'm now stuck trying to work out how I would also use the yzw values. This is my fragment shader code:
vec4 data = texture2D(texture, vec2(verpos.x / 32.0, verpos.z / 32.0));
float blockID = data.x;
vec4 color;
if (blockID == 1.0) {
color = vec4(0.28, 0.52, 0.05, 1.0);
}
else if (blockID == 2.0) {
color = vec4(0.25, 0.46, 0.05, 1.0);
}
else if (blockID == 3.0) {
color = vec4(0.27, 0.49, 0.05, 1.0);
}
gl_FragColor = color;
This works fine, however as you can see it's only using the float from the x-coordinate. If it was also using the yzw coordinates the texture size could be reduced to 16x16 instead of 32x32 (four times smaller).
The aim of this is to create a voxel-type terrain, where each 'block' is 1x1 in space coordinates and is colored based on the blockID. Looks like this:
Outside of GLSL this would be simple, however with no ability to store which blocks have been computed I'm finding this difficult. No doubt, I'm over thinking things and it can be done with some simple math.
EDIT:
Code based on Wagner Patriota's answer:
vec2 pixel_of_target = vec2( verpos.xz * 32.0 - 0.5 ); // Assuming verpos.xz == uv_of_target ?
// For some reason mod() doesn't support integers so I have to convert it using int()
int X = int(mod(pixel_of_target.y, 2.0) * 2.0 + mod(pixel_of_target.x, 2.0));
// Gives the error "Index expression must be constant"
float blockID = data[ X ];
About the error, I asked a question about that before which actually led to me asking this one. :P
Any ideas? Thanks! :)
The idea is to replace:
float blockID = data.x;
By
float blockID = data[ X ];
Where X is a integer that allows you to pick the R, G, B or A from your 16x16 data image.
The thing is how to calculate X in function of your UV?
Ok, you have a target image (32x32) and the data image (16x16). So let's do:
ivec pixel_of_target = ivec( uv_of_target * 32.0 - vec2( 0.5 ) ); // a trick!
Multiplying your UV with the texture dimesions (32 in this case) you find the exact pixel. The -0.5 is necessary because you are trying "to find a pixel from a texture". And of course the texture has interpolated values between the "center of the pixels". You need the exact center of the pixel...
Your pixel_of_target is an ivec (integers) and you can identify exactly where you are drawing! So the thing now is to identify (based on the pixel you are drawing) which channel you should get from the 16x16 texture.
int X = ( pixel_of_target.y % 2 ) * 2 + pixel_of_target.x % 2;
float blockID = data[ X ]; // party on!
This expression above allows you to pick up the correct index X based on the target pixel! On your "data texture" 16x16 map your (R,G,B,A) to (top-left, top-right, bottom-left, bottom-right) of every group of 4 pixels on your target (or maybe upside-down if you prefer... you can figure it out)
UPDATE:
Because you are using WebGL, some details should be changed. I did this and it worked.
vec2 pixel_of_target = vTextureCoord * 32.0 + vec2( 0.5 ); // the signal changed!
int _x = int( pixel_of_target.x );
int _y = int( pixel_of_target.y );
int X = mod( _y, 2 ) * 2 + mod( _x, 2 );
I used this for my test:
if ( X == 0 )
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
else if ( X == 1 )
gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
else if ( X == 2 )
gl_FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
else if ( X == 3 )
gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );
My image worked perfectly fine:
Here i zommed with Photoshop to see the deatails of the pixels.
PS1: Because I am not familiar with WebGL, I could not run WebGL in Chrome, I tried with Firefox, and I didn't find the mod() function either... So I did:
int mod( int a, int b )
{
return a - int( floor( float( a ) / float( b ) ) * float( b ) );
}
PS2: I don't know why I had to sum vec2( 0.5 ) instead of subtract. WebGL is a little bit different. It probably has this shift. I don't know... It just works.
Is there an easy way to add shadows in opengl-es 1.x? Or only in 2.0?
For projecting a shadow on a plane there's a simple way (not very efficient, but simple).
This function is not mine, I forget were I found it. What it does is create a matrix projection that maps everything you draw onto a single plane.
static inline void glShadowProjection(float * l, float * e, float * n)
{
float d, c;
float mat[16];
// These are c and d (corresponding to the tutorial)
d = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
c = e[0]*n[0] + e[1]*n[1] + e[2]*n[2] - d;
// Create the matrix. OpenGL uses column by column
// ordering
mat[0] = l[0]*n[0]+c;
mat[4] = n[1]*l[0];
mat[8] = n[2]*l[0];
mat[12] = -l[0]*c-l[0]*d;
mat[1] = n[0]*l[1];
mat[5] = l[1]*n[1]+c;
mat[9] = n[2]*l[1];
mat[13] = -l[1]*c-l[1]*d;
mat[2] = n[0]*l[2];
mat[6] = n[1]*l[2];
mat[10] = l[2]*n[2]+c;
mat[14] = -l[2]*c-l[2]*d;
mat[3] = n[0];
mat[7] = n[1];
mat[11] = n[2];
mat[15] = -d;
// Finally multiply the matrices together *plonk*
glMultMatrixf(mat);
}
Use it like this:
Draw your object.
glDrawArrays(GL_TRIANGLES, 0, machadoNumVerts); // Machado
Suply it with a light source position, a plane where the shadow will be projected and the normal.
float lightPosition[] = {383.0, 461.0, 500.0, 0.0}
float n[] = { 0.0, 0.0, -1.0 }; // Normal vector for the plane
float e[] = { 0.0, 0.0, beltOrigin+1 }; // Point of the plane
glShadowProjection(lightPosition,e,n);
Ok, shadow matrix is applied.
Change the drawing color to something that fits.
glColor4f(0.3, 0.3, 0.3, 0.9);
Draw your object again.
glDrawArrays(GL_TRIANGLES, 0, machadoNumVerts); // Machado
That is why this is not efficient, the more complex the object the more useless triangles you waste just for a shadow.
Also remember that every manipulation you made to the unshadowed object needs to be done after the shadow matrix is applied.
For more complex stuff the subject is a bit broad, and depends a lot on your scene and complexity.
Projective texture mapped shadows like they were done with OpenGL-1.2 without shaders are possible. Look for older shadow mapping tutorials, written between 1999 and 2002.
If...
vec3 myVec3 = vec3(1.0, 0.0, 0.5); // myVec3 = {1.0, 0.0, 0.5}
vec3 temp = vec3(myVec3); // temp = myVec3
vec2 myVec2 = vec2(myVec3); // myVec2 = {myVec3.x, myVec3.y}
myVec4 = vec4(myVec2, temp, 0.0); // myVec4 = {myVec2.x, myVec2.y, temp.x, 0.0}
Then what does the following represent?
myVec4 = vec4(temp, myVec2, 0.0); // myVec4 =
Thanks .
If temp is indeed a vec3 as you’ve defined, both of the constructors for myVec4 are illegal, as both contain enough components in the first two arguments to initialize the entire vec4.
The way I would figure stuff like that out, assuming it compiles and runs, it to use the debugger or printf to see what you get.
On my xode 3.2.x - It does not compile. In fact vec2 myVec2 = vec2(myVec3); also does not compile.
Also: last line has an error which makes sense when you read it.
code.mm:73:0 code.mm:73: error: no matching function for call to
'Vector4<float>::Vector4(vec3&, vec2&, double)'
I have always found the constructor rules for C++ to be pretty complex. Let the compiler tell it like it is.