I tried to connect a 2-dimensional component array to a 1-dimensional component array including 1-dimensional connectors, but when checking the model, there is an error showing unmatched dimensions.
But I could connect a 1-dimensional component array to a component including 1-dimensional connectors,
So Why can't this work for multi-dimensional situations?
Did I do it wrong?
I checked the code, it seems I can't use
connect(tubeWall.port_b,surface.q_port);
but if I use the following code, it works fine.
for i in 1:x loop
for j in 1:y loop
connect(tubeWall[i].port_b[j], surface[i,j].q_port);
end for;
end for;
I did more test, here is the test code which worked fine:
model Unnamed
gain_1[3] gain_1_1
Modelica.Blocks.Sources.Sine[3,3] sine
Modelica.Blocks.Math.Cos[3,3] cos
equation
connect(sine.y, gain_1_1.u);
connect(gain_1_1.y, cos.u);
end Unnamed;
model gain_1
Modelica.Blocks.Math.Gain[3] gain
Modelica.Blocks.Interfaces.RealOutput[3] y
Modelica.Blocks.Interfaces.RealInput[3] u
equation
connect(gain.y, y)
connect(u, gain.u)
end gain_1;
Here is the screenshot of the connections:
So it seems the idea is right, but I am not sure why it doesn't work in my model. Hope someone could give a hint or direction of the unmatched error in my model.
Quoting Fritzon's Principles of object-oriented modeling and simulation with Modelica 3.3:
The connect contruct can be used to directly connect arrays of
connectors. For such array connections the following holds:
The array dimensions of the connected arrays of connectors must match
Each corresponding pair of elements is connected as a pair of scalar connectors
That is, referring to connect(tubeWall.port_b,surface.q_port);
it does not know which dimension of surface[:,:] goes to tubeWall[:] and which to port_b[:]
the for loop works, because you are taking over the task of connecting the pair of elements as scalar connectors
My suggestion for your modeling task is that you create an interface block to put between surface and tubeWall, in which you implement the element-wise connections the way they should be. The connection between surface and interface might then look like:
connect(surface, interface.surfacePort);
I played around to see if I can figure it out. Here three points that might bring you closer to a canonical answer on why there's a different behavior between physical connections (thermal, in your case) and signal connections (Real input/output, in your case):
Real input/output are causal, and declared differently than physical connectors
connector RealInput = input Real "'input Real' as connector" annotation (...);
connector PhysConnector
Real pt;
flow Real flw;
annotation (...);
end PhysConnector;
Real input/output look more like functions than connectors. I suppose the rule The array dimensions of the connected arrays of connectors must match does not apply/is not enforced for them. I can think of different reasons for this; two of them could be:
There's a general accepted framework to deal with tables, the same way the majority of us agree that looking at a geographical map the top-left corner is north-west. So the connections are sorted automatically according to the sequence: 1st dim, 2nd dim, 3rd dim,... Multidimensional physical connections on the other hand might represent all sorts of scenarios. Better leave the model designer the responsibility to build it up correctly
Real input/output generate one assignment instead of a set of equations, therefore they don't mess up too much with the sorting algorithms when figuring out the causality of the system
I tried eventually to test a standard connector with only a potential variable, to see if the problem was due to the two equations generated when also a flow variable is present. The flat Modelica shows there's only one equation generated (as expected), but still the connection matrix[:,:],array[:].array[:] is not allowed.
package MultidimConnections
connector RealConnector
Real r;
annotation(Icon(coordinateSystem(preserveAspectRatio=false)),Diagram(coordinateSystem(preserveAspectRatio=false)));
end RealConnector;
partial model RealInterface
RealConnector realConnector annotation(Placement(transformation(extent={{90,-10},{110,10}})));
annotation(Icon(coordinateSystem(preserveAspectRatio=false),graphics={Rectangle(extent={{-100,100},{100,-100}},lineColor={28,108,200},fillColor={170,213,255},fillPattern=FillPattern.None)}),Diagram(coordinateSystem(preserveAspectRatio=false)));
end RealInterface;
model Source
extends RealInterface;
parameter Real k = 0;
equation
k = realConnector.r;
annotation(Icon(coordinateSystem(preserveAspectRatio=false),graphics={Rectangle(extent={{-80,80},{80,-60}},lineColor={28,108,200},fillColor={151,226,75},fillPattern=FillPattern.Solid), Text(extent={{-100,-60},{100,-100}},lineColor={28,108,200},fillColor={151,226,75},fillPattern=FillPattern.Solid,textString="%name")}),Diagram(coordinateSystem(preserveAspectRatio=false)));
end Source;
model User
extends RealInterface;
Real double;
equation
double = 2*realConnector.r;
annotation(Icon(coordinateSystem(preserveAspectRatio=false), graphics={Rectangle(extent={{-80,80},{80,-60}},lineColor={28,108,200},fillColor={85,170,255},fillPattern=FillPattern.Solid), Text(extent={{-100,-60},{100,-100}},lineColor={28,108,200},fillColor={85,170,255},fillPattern=FillPattern.Solid,textString="%name")}),Diagram(coordinateSystem(preserveAspectRatio=false)));
end User;
model User_multi
MultidimConnections.User user annotation(Placement(transformation(extent={{-10,40},{10,60}})));
MultidimConnections.User user1 annotation(Placement(transformation(extent={{-10,-10},{10,10}})));
MultidimConnections.User user2 annotation(Placement(transformation(extent={{-10,-60},{10,-40}})));
RealConnector realConnector[3] annotation(Placement(transformation(extent={{110,-10},{90,10}})));
equation
connect(user.realConnector, realConnector[1]) annotation(Line(points={{10,50},{98,50},{98,-6.66667},{100,-6.66667}}, color={0,0,0}));
connect(user1.realConnector, realConnector[2]) annotation(Line(points={{10,0},{98,0},{98,4.44089e-16},{100,4.44089e-16}}, color={0,0,0}));
connect(user2.realConnector, realConnector[3]) annotation(Line(points={{10,-50},{98,-50},{98,6.66667},{100,6.66667}}, color={0,0,0}));
annotation(Icon(coordinateSystem(preserveAspectRatio=false), graphics={Rectangle(extent={{-80,80},{80,40}},lineColor={28,108,200},fillColor={85,170,255},fillPattern=FillPattern.Solid),Text(extent={{-100,-60},{100,-100}},lineColor={28,108,200},fillColor={85,170,255},fillPattern=FillPattern.Solid,textString="%name"),Rectangle(extent={{-80,28},{80,-12}},lineColor={28,108,200},fillColor={85,170,255},fillPattern=FillPattern.Solid),Rectangle(extent={{-80,-20},{80,-60}},lineColor={28,108,200},fillColor={85,170,255},fillPattern=FillPattern.Solid),Rectangle(extent={{-100,100},{100,-102}}, lineColor={28,108,200})}),Diagram(coordinateSystem(preserveAspectRatio=false)));
end User_multi;
model TestCustomReal
extends Modelica.Icons.Example;
Source source(k=1) annotation(Placement(transformation(extent={{-60,40},{-40,60}})));
User user annotation(Placement(transformation(extent={{60,40},{40,60}})));
User_multi user_multi annotation(Placement(transformation(extent={{60,-10},{40,10}})));
Source source_arr[3](k=1) annotation(Placement(transformation(extent={{-60,-10},{-40,10}})));
User_multi user_multi_array[3] annotation(Placement(transformation(extent={{60,-60},{40,-40}})));
Source source_mat[3,3](k=1) annotation(Placement(transformation(extent={{-60,-60},{-40,-40}})));
equation
connect(source.realConnector, user.realConnector) annotation(Line(points={{-40,50},{40,50}}, color={0,0,0}));
connect(source_arr.realConnector, user_multi.realConnector) annotation(Line(points={{-40,0},{40,0}}, color={0,0,0}));
connect(source_mat.realConnector, user_multi_array.realConnector) annotation(Line(points={{-40,-50},{40,-50}}, color={0,0,0}));
end TestCustomReal;
annotation(uses(Modelica(version="3.2.3")));
end MultidimConnections;
The connect construct works only if the array dimensions match.
You could provide indices on the create connection window, to make the connection right between tubeWall and surface. which is exactly what the code is doing.
The model Unnammed works because gain_1_1.u is a connector with sizes [3,3]. If you change the size of the instance gain_1, you will see the difference.
Therefore you can either connect same size arrays or explicitly mention the indices during the connection.
Hope this helps.
first a little background. I'm a psychology student so my background in coding isn't on par with you guys :-)
My problem is as follow and the most important observation is that curve fitting with 2 different programs gives completly different results for my parameters, altough my graphs stay the same. The main program we have used to fit my longitudinal data is kaleidagraph and this should be seen as kinda the 'golden standard', the program I'm trying to modify is matlab.
I was trying to be smart and wrote some code (a lot at least for me) and the goal of that code was the following:
1. Taking an individual longitudinal datafile
2. curve fitting this data on a non-parametric model using lsqcurvefit
3. obtaining figures and the points where f' and f'' are zero
This all worked well (woohoo :-)) but when I started comparing the function parameters both programs generate there is a huge difference. The kaleidagraph program stays close to it's original starting values. Matlab wanders off and sometimes gets larger by a factor 1000. The graphs stay however more or less the same in both situations and both fit the data well. However it would be lovely if I would know how to make the matlab curve fitting more 'conservative' and more located near it's original starting values.
validFitPersons = true(nbValidPersons,1);
for i=1:nbValidPersons
personalData = data{validPersons(i),3};
personalData = personalData(personalData(:,1)>=minAge,:);
% Fit a specific model for all valid persons
try
opts = optimoptions(#lsqcurvefit, 'Algorithm', 'levenberg-marquardt');
[personalParams,personalRes,personalResidual] = lsqcurvefit(heightModel,initialValues,personalData(:,1),personalData(:,2),[],[],opts);
catch
x=1;
end
Above is a the part of the code i've written to fit the datafiles into a specific model.
Below is an example of a non-parametric model i use with its function parameters.
elseif strcmpi(model,'jpa2')
% y = a.*(1-1/(1+(b_1(t+e))^c_1+(b_2(t+e))^c_2+(b_3(t+e))^c_3))
heightModel = #(params,ages) abs(params(1).*(1-1./(1+(params(2).* (ages+params(8) )).^params(5) +(params(3).* (ages+params(8) )).^params(6) +(params(4) .*(ages+params(8) )).^params(7) )));
modelStrings = {'a','b1','b2','b3','c1','c2','c3','e'};
% Define initial values
if strcmpi('male',gender)
initialValues = [176.76 0.339 0.1199 0.0764 0.42287 2.818 18.52 0.4363];
else
initialValues = [161.92 0.4173 0.1354 0.090 0.540 2.87 14.281 0.3701];
end
I've tried to mimick the curve fitting process in kaleidagraph as good as possible. There I've found they use the levenberg-marquardt algorithm which I've selected. However results still vary and I don't have any more clues about how I can change this.
Some extra adjustments:
The idea for this code was the following:
I'm trying to compare different fitting models (they are designed for this purpose). So what I do is I have 5 models with different parameters and different starting values ( the second part of my code) and next I have the general curve fitting file. Since there are different models it would be interesting if I could put restrictions into how far my starting values could wander off.
Anyone any idea how this could be done?
Anybody willing to help a psychology student?
Cheers
This is a common issue when dealing with non-linear models.
If I were, you, I would try to check if you can remove some parameters from the model in order to simplify it.
If you really want to keep your solution not too far from the initial point, you can use upper bounds and lower bounds for each variable:
x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub)
defines a set of lower and upper bounds on the design variables in x so that the solution is always in the range lb ≤ x ≤ ub.
Cheers
You state:
I'm trying to compare different fitting models (they are designed for
this purpose). So what I do is I have 5 models with different
parameters and different starting values ( the second part of my code)
and next I have the general curve fitting file.
You will presumably compare the statistics from fits with different models, to see whether reductions in the fitting error are unlikely to be due to chance. You may want to rely on that comparison to pick the model that not only fits your data suitably but is also simplest (which is often referred to as the principle of parsimony).
The problem is really with the model you have shown resulting in correlated parameters and therefore overfitting, as mentioned by #David. Again, this should be resolved when you compare different models and find that some do just as well (statistically speaking) even though they involve fewer parameters.
edit
To drive the point home regarding the problem with the choice of model, here are (1) results of a trial fit using simulated data (2) the correlation matrix of the parameters in graphical form:
Note that absolute values of the correlation close to 1 indicate strongly correlated parameters, which is highly undesirable. Note also that the trend in the data is practically linear over a long portion of the dataset, which implies that 2 parameters might suffice over that stretch, so using 8 parameters to describe it seems like overkill.
Rheological models are usually build using three (or four) basics elements, which are :
The spring (existing in Modelica.Mechanics.Translational.Components for example). Its equation is f = c * (s_rel - s_rel0);
The damper (dashpot) (also existing in Modelica.Mechanics.Translational.Components). Its equation is f = d * v_rel; for a linear damper, an could be easily modified to model a non-linear damper : f = d * v_rel^(1/n);
The slider, not existing (as far as I know) in this library... It's equation is abs(f)<= flim. Unfortunately, I don't really understand how I could write the corresponding Modelica model...
I think this model should extend Modelica.Mechanics.Translational.Interfaces.PartialCompliant, but the problem is that f (the force measured between flange_b and flange_a) should be modified only when it's greater than flim...
If the slider extends PartialCompliant, it means that it already follows the equations flange_b.f = f; and flange_a.f = -f;
Adding the equation f = if abs(f)>flim then sign(f)*flim else f; gives me an error "An independent subset of the model has imbalanced number of equations and variables", which I couldn't really explain, even if I understand that if abs(f)<=flim, the equation f = f is useless...
Actually, the slider element doesn't generate a new force (just like the spring does, depending on its strain, or just like the damper does, depending on its strain rate). The force is an input for the slider element, which is sometime modified (when this force becomes greater than the limit allowed by the element). That's why I don't really understand if I should define this force as an input or an output....
If you have any suggestion, I would greatly appreciate it ! Thanks
After the first two comments, I decided to add a picture that, I hope, will help you to understand the behaviour I'm trying to model.
On the left, you can see the four elements used to develop rheological models :
a : the spring
b : the linear damper (dashpot)
c : the non-linear damper
d : the slider
On the right, you can see the behaviour I'm trying to reproduce : a and b are two associations with springs and c and d are respectively the expected stress / strain curves. I'm trying to model the same behaviour, except that I'm thinking in terms of force and not stress. As i said in the comment to Marco's answer, the curve a reminds me the behaviour of a diode :
if the force applied to the component is less than the sliding limit, there is no relative displacement between the two flanges
if the force becomes greater than the sliding limit, the force transmitted by the system equals the limit and there is relative displacement between flanges
I can't be sure, but I suspect what you are really trying to model here is Coulomb friction (i.e. a constant force that always opposes the direction of motion). If so, there is already a component in the Modelica Standard Library, called MassWithStopAndFriction, that models that (and several other flavors of friction). The wrinkle is that it is bundled with inertia.
If you don't want the inertia effect it might be possible to set the inertia to zero. I suspect that could cause a singularity. One way you might be able to avoid the singularity is to "evaluate" the parameter (at least that is what it is called in Dymola when you set the Evaluate flat to be true in the command line). No promises whether that will work since it is model and tool dependent whether such a simplification can be properly handled.
If Coulomb friction is what you want and you really don't want inertia and the approach above doesn't work, let me know and I think I can create a simple model that will work (so long as you don't have inertia).
A few considerations:
- The force is not an input and neither an output, but it is just a relation that you add into the component in order to define how the force will be propagated between the two translational flanges of the component. When you deal with acausal connectors I think it is better to think about the degrees of freedom of your component instead of inputs and outputs. In this case you have two connectors and independently at which one of the two frames you will recieve informations about the force, the equation you implement will define how that information will be propagated to the other frame.
- I tested this:
model slider
extends
Modelica.Mechanics.Translational.Interfaces.PartialCompliantWithRelativeStates;
parameter Real flim = 1;
equation
f = if abs(f)>flim then sign(f)*flim else f;
end slider;
on Dymola and it works. It is correct modelica code so it should be work also in OpenModelica, I can't think of a reason why it should be seen as an unbalance mathematical model.
I hope this helps,
Marco