The problem
Low-cost microcontrollers used in two- and three-wheeler EV controllers and BMS boards often have no floating-point unit. Floating-point code still runs, but is emulated and slow. Converting the controller to fixed-point makes it fast, but every signal needs a word length and scaling that avoids overflow while keeping enough precision. Doing this systematically, with evidence that accuracy is preserved, is a valuable engineering skill.
Objectives
- Build and verify a floating-point reference controller with a plant model.
- Collect signal ranges and propose fixed-point data types with Fixed-Point Designer.
- Verify fixed-point behaviour against the floating-point reference.
- Measure execution time and memory on the STM32F103 in PIL.
- Study the effect of word length on accuracy and cost.
What you need
Tools and toolboxes
- Simulink — Controller, plant model and test harness.
- Fixed-Point Designer — Range collection, data type proposal with the Fixed-Point Tool, overflow detection and comparison with the float reference.
- Embedded Coder — Generating integer C code and running PIL with execution profiling.
- Embedded Coder Support Package for STMicroelectronics STM32 Processors — STM32 target and serial PIL; check STM32F1 support in your version, or use a custom PIL target.
- Simulink Test (optional) — Automating float versus fixed-point comparisons; Simulation Data Inspector comparisons are sufficient without it.
From the EV Embedded Development Kit
- STM32F103C8T6 microcontroller unit (Arm Cortex-M3)
- Serial UART interface
Software
- MATLAB R2023b or later
- Simulink
- Fixed-Point Designer
- Embedded Coder
- STM32CubeMX and STM32CubeIDE toolchain
Extra parts and data
None beyond the software above.
Key concepts
- Fixed-point representation
- A number stored as an integer with an implied binary point; for example a signed 16-bit value with 12 fraction bits covers about ±8 in steps of 1/4096.
- Range and precision
- Fewer fraction bits give more range but coarser steps; the right choice depends on the signal's actual minimum and maximum from simulation plus a safety margin.
- Overflow and saturation
- If a value exceeds its type's range it wraps or saturates. Wrapping in a controller can cause violent errors, so overflow must be detected and either prevented or saturated.
- Integrator precision
- Small increments added to a large integrator state can be lost if the state has too few fraction bits, causing steady-state error; integrators often need longer words.
Step-by-step guide
- 1
Build the floating-point reference
Model a PI current controller for an example 48 V brushed or BLDC drive at 10 kHz, with anti-windup, followed by an SOC- and temperature-based current-limit lookup. Close the loop with a simple RL plant and back-EMF. Use double in the reference. Run current-step, limit and saturation scenarios and save their outputs as the golden reference. Store the reference outputs as a MAT-file with the model version, so the same golden data is used for every later comparison.
Checkpoint: Reference simulation with current steps settling within the design time and limits applied correctly.
- 2
Define accuracy and cost targets
Set acceptance criteria before converting: maximum current error versus reference of, say, 0.5 per cent of full scale, no overflow in any test, and execution time below a fixed share of the 100 µs period on the STM32F103. Write these down, because they decide word lengths later and stop endless tuning. Express the accuracy target as both a maximum and an RMS error, and state the scenarios over which each is measured, so the targets cannot be met by choosing easy tests.
Checkpoint: A written set of numerical acceptance criteria.
- 3
Prepare the model for conversion
Separate the controller (to be converted) from the plant and test inputs (kept in floating-point) with Data Type Conversion blocks at the boundary. Replace blocks that do not support fixed-point well, and check lookup tables have sensible breakpoints. Run the Fixed-Point Tool's preparation checks and fix reported issues. Save a copy of the floating-point model under version control before conversion, so the reference can always be rerun and compared. Note any blocks you had to replace and why.
Checkpoint: The preparation checks report no blocking issues for the controller subsystem.
- 4
Collect ranges
In the Fixed-Point Tool, choose the controller as the system under design and collect ranges by simulating all test scenarios with instrumentation enabled. Include worst cases: maximum current step, saturation and limits at extreme SOC and temperature. Ranges from too few scenarios will give types that overflow later. Also add design minimum and maximum values on inputs where the physical range is known, such as current sensor limits, so proposed types cover the full physical range rather than only simulated values.
Checkpoint: Simulation minimum and maximum recorded for every signal in the controller.
- 5
Propose data types
Set a default word length, for example 16 bits, and a safety margin of around 20 per cent, then let the Fixed-Point Tool propose fraction lengths. Review the proposals: give integrator states 32 bits, and check products and sums. Apply the types. Write down any manual override and its reason. Check that products and accumulator types are wide enough, since a product of two 16-bit values needs up to 32 bits before it is scaled back down.
Checkpoint: A table of signals with proposed and final data types and any manual changes justified.
- 6
Verify against the reference
Run all scenarios with the fixed-point controller and compare with the golden reference in the Simulation Data Inspector or the Fixed-Point Tool's comparison view. Check maximum error, steady-state error and any overflow or saturation warnings. If an integrator shows steady-state error, increase its fraction bits. Also run scenarios that were not used for range collection, such as a different current profile, and check for overflow there, since this is the real test of the chosen types.
Checkpoint: Maximum error within the accuracy target and zero overflows across all scenarios.
- 7
Generate and inspect code
Generate code with Embedded Coder for the STM32 target. Open the code report and confirm that the controller uses only integer types, with shifts in place of scaling. Check for any remaining float operations or helper library calls. Record code and data size from the report or the linker map file. Note any division operations, which are slow on the Cortex-M3, and consider replacing them with multiplication by a precomputed reciprocal.
Checkpoint: Generated controller code with no floating-point operations and its flash and RAM use recorded.
- 8
Run PIL and profile
Run the fixed-point controller in PIL mode on the kit's STM32F103 over UART, with execution profiling on. Repeat with the floating-point controller in single precision for comparison. Compare PIL outputs with MIL outputs for both, and record average and maximum execution time for each. Run each configuration several times and report the maximum execution time, since the worst case matters more than the average for a fixed-rate control task. Note the compiler optimisation level used.
Checkpoint: A table showing execution time and memory for float and fixed-point, with PIL matching MIL for each.
- 9
Word-length study
Repeat conversion with default word lengths of 8, 16 and 32 bits (keeping 32-bit integrators). For each, record maximum error, overflows and execution time on target. Plot error against cycles. This shows where shorter words stop being worth it on a 32-bit core, where 16- and 32-bit operations often cost similar time. Explain the result with reference to the Cortex-M3 instruction set, where 32-bit integer multiply is a single-cycle instruction.
Checkpoint: An error-against-cycles plot with the three word lengths marked.
- 10
Report
Present the reference model, acceptance criteria, range collection, data types with justifications, verification, code inspection, PIL profiling and word-length study. Conclude with the recommended types for this controller on this MCU. State the limitations: simplified plant and PIL rather than closed-loop hardware tests. Include the final data-type table and the scenario list in an appendix, so the conversion can be repeated or extended to a different controller.
Checkpoint: A report with evidence that the acceptance criteria were met.
Testing & validation
- Fixed-point controller within accuracy target against the floating-point reference.
- No overflow in any test scenario, including worst cases.
- Generated code contains no floating-point operations.
- PIL outputs match MIL on the STM32F103.
- Execution time and memory compared for float and fixed-point.
Expected results
A fixed-point EV current controller with justified data types, verified against its floating-point reference, running on the STM32F103 of the DIYguru kit in PIL with measured speed-up and memory compared with floating-point code.
Research angle for your M.Tech thesis
Research questions: what is the trade-off between word length, control accuracy and execution cost for EV controllers on no-FPU microcontrollers, and how much simulation coverage is needed for range collection to avoid overflow? Metrics: maximum and RMS error against reference, overflow count under unseen scenarios, cycles per step, flash and RAM. Baselines: floating-point emulation and hand-written fixed-point. Testing data types on scenarios not used for range collection is the key validity check. A systematic study across several controllers with released models would be a sound conference paper.
Take it further
- Deploy the fixed-point controller on the kit with a small DC motor through the motor driver.
- Convert a Kalman-filter SOC estimator, which is harder because of covariance ranges.
- Use the Fixed-Point Tool's optimisation of word lengths against a tolerance.
- Compare with hand-written Q-format C code.
Viva and review questions
Why does the integrator need more bits?
Each step adds a small value to a potentially large state; with too few fraction bits those small increments round to zero and the integrator stops correcting steady-state error.
How did you make sure no overflow happens?
By collecting ranges over worst-case scenarios, adding a safety margin, checking for overflow in every test, and testing on scenarios not used for range collection.
Why is fixed-point faster on the STM32F103?
The Cortex-M3 has no FPU, so floating-point maths is done in software libraries, while fixed-point uses native integer multiply, add and shift instructions.
Learn it at DIYguru
These DIYguru courses and programmes teach what this project needs.
