Use M-code in Simulink model
Your MATLAB algorithm passes all tests. You drop it into a Simulink model, generate code, and suddenly it breaks — or worse, produces silently different results.
Published: 2026-02-25
Why Your MATLAB Code Breaks in Simulink (And How to Fix It for Real)
Introduction
You write an algorithm in MATLAB. It passes all your tests. You drop it into a Simulink model, generate code, and suddenly it breaks — or worse, produces silently different results. The rebuild-debug cycle begins.
This gap between MATLAB's flexible, interpreted environment and Simulink's rigid, compiled one is the core challenge of integrating MATLAB code into models. The solution isn't to abandon MATLAB or overcomplicate Simulink. It's to adopt a clean, repeatable architecture that separates core logic from model-specific glue, validates early with static checks, and unifies testing across environments.
💡 Key Takeaways
- Separate core algorithms from input validation, error handling, and
varargin/varargoutwrappers.- Use CC4M's Coder Compatibility configuration to catch unsupported functions before they break builds or result in runtime differences.
- Generate MEX files and ensure MATLAB and generated code behave identically.
Steps to integrate an algorithm into a model
Follow the steps below to keep your algorithm and its tests in M-files while calling the algorithm from Simulink. Steps 2–4 are best done in small iterations:
-
Run existing tests and confirm they pass. If no tests exist yet, write them first. The algorithm will likely need changes — validate each change incrementally. When you only have M-code in a model, the main difference is to make sure the algorithm tests run within MATLAB (instead of via a Simulink test harness).
-
Separate the algorithm from the model, as described in the Architecture section. Handle datastores correctly.
-
Separate input validation and error handling from the core algorithm. If the algorithm uses
try-catchblocks or callserror(), move that logic into a wrapper. Code generation does not support these constructs. Also realize that, because datatypes and sizes are fixed at compile time, the core algorithm does not need runtime validation of type and sizes. Variable-sized data is an exception — it still requires checks, but the code must handle issues gracefully, rather than callingerror(...). -
Move
varargin/varargouthandling into a wrapper. Variable argument counts and dynamic input types are not supported for code generation and must be handled in a wrapper layer.
-
-
Run CC4M with the Coder Compatibility configuration. Check the core algorithm for Coder compatibility. CC4M flags unsupported functions (which cause build errors) and functions with known limitations (which can cause build errors, runtime failures, or silent behavioral differences). Catching these issues early avoids repeated rebuild cycles.
CC4M also surfaces safety-related concerns such as incomplete
switch-casecoverage and floating-point equality comparisons. -
Update and run test classes.
- If a wrapper was created, split tests between the wrapper and the core algorithm.
- Use the correct datatypes — the same types used in the Simulink model.
- For structures on the input/output, create test data from Simulink bus definitions using
Simulink.Bus.createMATLABStruct.
Tip: Instead of relying on
coder.runTests, a custom build script for your MEX-files gives you finer control over the Coder configuration. You can then switch between the interpreted MATLAB implementation and the generated MEX-file using aTestParameter. This keeps a single test class for both. Alternatively, MATLAB provides thematlabtest.coder.TestCasesubclass; this class offers the dedicatedverifyExecutionMatchesMATLABmethod to automatically compare MEX output against the reference MATLAB implementation — no manual switching required.![]()
A test class with the algorithm implementations to test as TestParameter.
Why separate the algorithm?
Depending on model size and where algorithms are invoked, you can implement them using MATLAB Function blocks or MATLAB Functions within a Stateflow Chart. The Stateflow approach makes functions easy to reuse, both inside and outside the model. Embedding a MATLAB Function block inside a Simulink Function is another option, providing a callable function prototype (e.g., [c, d] = f(a,b)) alongside standard input and output ports. System objects are not discussed here.
Different patterns for including MATLAB code in a model.
- In a Chart
- In a MATLAB Function Block
- In a Triggered MATLAB Function Block
- A MATLAB Function Block in a Simulink Function Block
For computational algorithms, development typically starts in plain MATLAB scripts — one of MATLAB's core strengths. Rather than copy-pasting the algorithm into a block, call the existing .m file directly from the model. This eliminates duplicate maintenance and the risk of diverging versions.
Separating the algorithm from the Simulink model has clear trade-offs:
Benefits
- The algorithm is a standalone file in version control, making change history, diffs, and merges straightforward.
- Development and testing happen in plain MATLAB, independent of the Simulink model.
- The same algorithm can be reused across multiple models and in standalone MATLAB applications.
Drawbacks
- Simulink is strongly typed; MATLAB is not.
- Simulink signals are statically sized by default; MATLAB arrays are not.
- Generated code can exhibit documented behavioral differences from the base MATLAB implementation, beyond the expected minor variations from different floating-point math libraries.
These drawbacks can be mitigated by running the same tests against both the interpreted MATLAB code and the generated code. To generate code, the function must comply with the constraints documented in the MATLAB Coder documentation. Tools like CC4M can help identify compatibility issues early. Making M-code ready for code generation is a topic for another blog; here we focus on Simulink integration and verifying correct results.
Once the function is Coder-compatible, you can use MATLAB Coder to generate a MEX file from the algorithm and place it alongside the original .m file.
Tip: If your algorithm isn't yet Coder-compatible, you can use
coder.extrinsicto call the function at runtime without generating code for it. This lets you integrate and test the algorithm in your Simulink model while you work on making it Coder-compatible.
config = coder.config("mex");
codegen('-config', config, 'simpleAlgorithm', '-args', {0, 0, 0});
Using coder.runTest you can run the same tests against the MEX file without modifying the test code:
runtests('TestSimpleAlgorithm')
coder.runTest('TestSimpleAlgorithm', 'simpleAlgorithm')
Conclusion
Reusing MATLAB algorithms in Simulink is straightforward when you plan ahead. A clean architecture — with input validation and error handling separated from the core algorithm — enables reuse across models and toolchains. Combining static analysis with CC4M's Coder Compatibility configuration and generated-code testing with coder.runTest closes the gap between MATLAB's interpreted behavior and the compiled output, ensuring consistent results in both environments.