Why does C code generated from Stateflow logic with 'duration' operator have conversion to real_T (double) in it?

4 views (last 30 days)
Using 'duration' in the Stateflow logic results in (real_T) conversion in the generated code.
The C code should be used in embedded environment with single precision.
Is it possible to use the 'duration' operator and get generated code without the conversion to double?
The Stateflow logic:
up = duration(Measurements_input.curr_battery_prim.value>FLOATING_STATE_UPPER_LIMIT, sec) > CHARGING_STATE_SWITCHING_TIME;
The generated code:
661 /* During 'Floating': '<S2>:112' */
662 if ((real_T)(rtDW.chartAbsoluteTimeCounter -
663 rtDW.durationLastReferenceTick_1) >
664 CHARGING_STATE_SWITCHING_TIME * 200.0F) {
665 /* Transition: '<S2>:152' */
666 rtDW.is_NormalOperation = IN_Charging;
667
668 /* Entry 'Charging': '<S2>:113' */
669 }
Thanks,

Answers (1)

Andy Bartlett
Andy Bartlett on 9 Aug 2021
Edited: Andy Bartlett on 2 Sep 2021
Tunable Pararmeters with Duration appears to be a Limitation for Singles only designs
In the model above, tuneParam1, tuneParam2, and tuneParam3 are Simulink.Parameters of type single and are tunable (StorageClass = ExportGlobal). The input u, output y, and constants c1, c2 are also single.
When running Model Advisor check for strict-single precision, the use of doubles is detected.
Using Embedded Coder to generate C code does show the use of doubles related to the duration calculation.
I did not succeed in getting rid of the doubles for the tunable parameter case. I'll ask inside the MathWorks if there is a way to eliminate doubles that I missed. If not, we'll look toward enhance this.
If not a tunable parameter, then the following should work
Declaration is Probably the Easy Solution
I suspect that your are getting a double precision comparision operation because your model has (implicitly or explicitly) declared CHARGING_STATE_SWITCHING_TIME as double.
I also suspect that CHARGING_STATE_SWITCHING_TIME is declared in a way that Coders do not see it as constant value that can be folded into other computations. If it was constant-foldable, then CHARGING_STATE_SWITCHING_TIME * 200.0F would be replaced with a literal value like 1.234.
I suspect the easiest solution will be to find where CHARGING_STATE_SWITCHING_TIME is declared and change that declaration to single. If you'd like the value to be constant folded, then consider also declaring it as a constant.
Relational Operators that mix base MATLAB types
I did some investigations on handling of relational operators.
Relational operators that mix single precision and double precision usually lead to generated code involving doubles. This is to be expected because MATLAB is designed to give the full-precision ideal answer for relational operations on any combination of base MATLAB types (double, single, logical, uint8, ... int64). A relational operation with a single variable and a double constant also currently generate code involving floating-point doubles. MathWorks is investigating optimizing these cases to avoid use of doubles in a future release.
Stateflow Duration is Usually Highly Optimized
I also did some investigations on Stateflow's handling of duration with R2021a. I found that Stateflow tended to highly optimize the handling.
As an example consider this chart where u is single and the sample time is 2^-10 seconds.
Notice the expression
duration(<snip>) > 0.37
Since, the sample time is 2^-10, duration will be greater than 0.37 when 0.37/2^-10 = 378.88 clock ticks have elapsed. Stateflow generated the following integer code to handle the comparison of duration with 0.37
EmbedSFDuration.durationLastReferenceTick_1_o > 379
Not only did this not use floating-point double, it did not use floating-point at all. Just integers. That will generally be faster.
Why didn't this excellent level of optimization kick in for your model? As mentioned above, I suspect the right hand side is double and can't be constant folded, hence reduced optimization. Also, note I tested with R2021a which might be more optimizated than the release you used.
Now as expected from the previous section, this chart did generate use of doubles for the other two relation operators.
condIsTrue = (EmbedSFDuration_U.u1 >= 0.41);
EmbedSFDuration_U.u1 < 0.3
Explicitly Cast Constants as Needed
To avoid the double precision relational operators, one solution is to explicitly type the constants when using MATLAB including Stateflow MATLAB Action Language. The following chart where u and y are single is an example with explicit casting of constants used in relational operators.
This generates the following C code for the relational operators and avoids doubles.
condIsTrue = (EmbedSFDuration_U.u3 >= 0.41F);
EmbedSFDuration_U.u3 < 0.3F
You may be wondering about the other constants -0.05 and 0.15 that are implicitly declared as double. The assignment operator is a different story. Assignment of literal values will trigger constant folding and the use of doubles will be eliminated.
EmbedSFDuration_Y.y2 = -0.05F;
<snip>
EmbedSFDuration_Y.y2 = 0.15F;
As noted above, MathWorks is looking to provide a similar level of constant folding for relational operators that mix doubles and singles in a future release. If you think this should be a high priority, please drop us a note or leave a comment below. Please tell us the company you work for when communicating that need. Thanks.
Tip: Context Sensitive Constants for Stateflow C Action Language
If you are using the traditional Stateflow C Action Language, you can use a special syntax for context sensitive constants.
u < 0.3c % Stateflow C Action Language feature context sensitive constant
The little 'c' at the end says the literal value 0.3 does NOT have a declared type. Instead, you want Stateflow to figure out a type that is numerically useful and efficient in generated code. In this case, using the type of u for 0.3 would be desirable.
Tip: Cast-Like for MATLAB Comparisons
If you are using MATLAB, including Stateflow's MATLAB Action Language and MATLAB Function block, and you do not want to explicitly set the type of the constant, you can use cast-like.
u < cast(0.3,'like',u) % MATLAB cast like
This will force the value 0.3 to be cast to the same type as u. This will work for any type including base MATLAB and fixed-point types. This use of cast-like makes the relational operation code fully polymorphic and can thus be reused in many situations.
  2 Comments
Todd Nordby
Todd Nordby on 1 Sep 2021
Edited: Todd Nordby on 1 Sep 2021
I have the same issue and I think you are missing an important aspect. Certainly for me, and I'm guessing the original poster, the comparison threshold is intended to be a tunable Parameter. If CHARGING_STATE_SWITCHING_TIME is configured as tunable Parameter none of the solutions provided remove the double operation.
Andy Bartlett
Andy Bartlett on 2 Sep 2021
Ah, the C coding part of my brain sees all caps and thinks constant by convention.
Tunable parameters are a different story. I investigated them and revised the answer provided.

Sign in to comment.

Categories

Find more on Simulink Coder in Help Center and File Exchange

Products


Release

R2020a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!