Writing a lap time sim tool
Show older comments
I'm trying to write a lap time sim tool for race tracks. I have it in excel, so, most of the maths is done, except for the parts where excel cant work stuff out (as far as I know) like braking and acceleration zones but that can be worked on at a later date.
The main problem is that I need to allow the user to input section lengths: corners and straights, and preferably in order.
Part of the problem I have asked about before here: https://uk.mathworks.com/matlabcentral/answers/424503-how-to-make-a-scale-able-structure-array-with-variable-values
But, as people who have very kindly helped so far have pointed out, I need to explain the whole problem :)
So, as my Matlab and programming knowledge is limited, I'd like to know what approaches I can do for this, what functions would I need, and how would I need to use them. While it would be great for code to be provided, I dont want to ask other people to do the work for me, and I wont learn anything, but, I do learn best from examples so any similar examples I can expand on would be great.
There could be upto 100 or so sections of the track, for the straights it's a straight forward length and calculation. For corners, I need to determine the radius of that corner, so, need to be able to identify which section is which.
After that, I should have a resulting value (the top speed) for each section which I need to use in further calculations.
Any help would be appreciated.
4 Comments
Guillaume
on 22 Oct 2018
At which stage of the design are you at the moment?
If I were to design what you describe, I'd start with writing the simulation main function. This would take as input the track details, so something like:
function [someoutput, maybesomeotheroutput] = simulate(trackdetails, otherinput, somethingelsemaybe)
Have you got that yet and decided what type these input/output variables are going to be?
After that, I would design a user input function that makes it easy for the user to specify the track details. Probably, a GUI. That user input function would then call the simulation function that do the work an display the result.
Nick Deeley
on 22 Oct 2018
Guillaume
on 22 Oct 2018
Well, what inputs does your simulation need? You said the track details, that's one. What else?
Nick Deeley
on 22 Oct 2018
Answers (1)
Guillaume
on 22 Oct 2018
Probably, the first thing you need to settle on is what form your inputs will take. If I understand your requirements, I would have three inputs to the simulation function:
- track details. I would have that as a structure array with fields:
type: a scalar categorical with possible values: 'straight' or 'corner'
length: a scalar double
radius: a scalar double
inclination:? if that's needed, a scalar double
type may not even be needed since a corner with infinite radius is a straight.
- car details, a scalar structure (unless you simulate more than one car, in which case it's another structure array), with fields
friction
drag
frontalarea
mass
all scalar doubles
- environment, another scalar structure with fields
gravity
air density
humidity (?)
air temperature (?)
and the signature of your function would be:
function [someresult, maybesomeotherresult] = tracksimulation(track, car, environment)
%TRACKSIMULATION: Simulate the car racing along the specified track under given environment conditions
%with:
% track: and Nx1 structure with fields
% type: scalar categorical with possible values 'straight' or 'corner'
% ... you can write the rest
% first thing you should do when you start writing a function is document its inputs/outputs
You can even have a helper function to help you build that track structure:
function track = addsection(track, type, length, radius)
%ADDSECTION: add a section to the given track (or start the track)
%with:
% track: a previously constructed track structure or an empty array to start the track
% type: the type of section to add, char array with value: 'straight' (or 's') or 'corner' (or 'c')
% length: length of section to add, scalar double
% radius: radius of section to add, ignored and can be omitted if type is 'straight'.
if isempty(track)
track = structure('type', {}, 'length', {}, 'radius', {});
else
assert(isstruct(track) && all(ismember({'type', 'length', 'radius'}, fieldnames(track))), 'track input must be a structure with correct fields');
end
validateattributes(type, {'char', 'string'}, {'scalartext'}, 2)
if strcmp(type, 's'), type = 'straight'; elseif strcmp(type, 'c'), type = 'corner'; end
validateattributes(length, {'numeric'}, {'scalar', 'positive', 'finite'}, 3);
if nargin < 3
if strcmp(type, 'corner'), error('radius must be specified when type is ''corner''); end
radius = Inf;
else
validateattributes(radius, {'numeric'}, {'scalar', 'positive', 'finite'}, 4);
end
track = [track; struct('type', categorical({type}, {'straight', 'corner'}), 'length', length, 'radius', radius)];
end
11 Comments
Nick Deeley
on 22 Oct 2018
Nick Deeley
on 22 Oct 2018
matrix: a MxN anything
array: something of any dimension
double: standard numeric type.
I probably should have written scalar numeric instead of scalar double since the code I wrote accepts any numeric type (double, single, integer).
Nick Deeley
on 24 Oct 2018
Guillaume
on 24 Oct 2018
My advice is that for now you don't worry about the user interface and you work solely on the processing algorithm. In a well designed program, the processing and the UI are completely independent, so you can completely change one without affecting the other.
So for now, you need to decide what sort of data format works well for the simulation code. It will be the interface between the processing and the UI. Once that's settled and your processing code works, you can then decide on a what sort of UI you want so that it generates the correct format. It can be command line, it can be a GUI, you can read the input from a file. All of this can be done.
There are plenty of options for that data format. For the track, there's the structure I suggested initially. You could also use a table:
track = table([300;400;150;1000], 'sccs'.', [0;90;-30;0], 'VariableNames', {'length', 'type', 'radius'})
track.Properties.Description = 'Wiggles';
Or you can use your proposed structure. There's no need to have it a structure array if your simulation only needs one track, so it would be:
track.name = "Track Name";
track.length = 4200; %I would recommend you don't have that field
track.sections = {300, 's'; 400, 'c'; 150, 'c'; 1000, 's'};
I would not have an explicit length field as you run the risk that it may be different from the sum of the section lengths if you're not careful to keep the two in sync. It's trivially calculated anyway.
In each case, accesssing each section is simply an iteration over the rows of the structure/table/cell array.
Again, whatever data format you choose you can adapt a UI to it. A table may be the easiest to make a GUI for as it maps directly onto a UITable but whichever you chose doesn't really matter for the UI.
Nick Deeley
on 30 Oct 2018
Edited: Nick Deeley
on 30 Oct 2018
Guillaume
on 31 Oct 2018
First, you need to clarify which of the several storage schemes I proposed you're using.
for radius = TRACK(1).sections
The name of the iterating variable, radius, does not make sense. As it's a name you can call it what you want, but calling it radius is misleading. I would have:
for section = TRACK(1).sections
Note that sections needs to be a row vector for the above to works. Otherwise, it's:
for sectionidx = 1:numel(TRACK(1).sections
section = TRACK(1).sections(sectionidx);
I thought the radius would be stored in the section structure, so I'm not sure why you want to calculate it, and what from.
If section is a structure, then the code would continue with:
if section.type == 'c';
%calculate something
else
As it is, what you wrote doesn't make sense.
Nick Deeley
on 31 Oct 2018
Guillaume
on 31 Oct 2018
Again, before you write any code, you need to clarify which storage model you're using. What actual properties of the track you're storing? Is there one or can there be several tracks. Which attributes of the section did store, length obviously but it seems not radius, so perhaps angle as well?
If you don't have that clear, you can't really write the code. Once you've settled on what you need to store, whether you use a structure or table doesn't really matter, it will result in only minor differences to the code.
As for your other questions:
I made a mistake and forgot the closing ). As the error message tells you, check for mismatched delimiter. It should have been:
for sectionidx = 1:numel(TRACK(1).sections)
Of course, for the above I sort of followed your code. I'm not sure why you're indexing TRACK. I thought there would be only one track. And I don't know what you intend to store in the section field.
doc for numel (not nume1)
sectionidx is just a variable name for the iterating variable. People often use i which I think is not a good variable name. You could use sectionindex or sectioniter or sectioniterator. Whatever you want.
The code iterates over the sections of the track. I assume that's what you intended with your original code.
If we assume that a corner is a circular arc, then in order to calculate the radius, you need the length and the subtending angle.
Nick Deeley
on 5 Nov 2018
Guillaume
on 6 Nov 2018
Again, I'm really not clear on which data model you're using So, please clarify. What are the fields of your structures (TRACK and sections)? What are the possible values of each field?
Categories
Find more on Loops and Conditional Statements in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!