Main Content

Results for

Have you ever wondered what it takes to send live audio from one computer to another? While we use apps like Discord and Zoom every day, the core technology behind real-time voice communication is a fascinating blend of audio processing and networking. Building a simple walkie-talkie is a perfect project for demystifying these concepts, and you can do it all within the powerful environment of MATLAB.
This article will guide you through creating a functional, real-time, push-to-talk walkie-talkie. We won't be building a replacement for a commercial radio, but we will create a powerful educational tool that demonstrates the fundamentals of digital signal processing and network communication.
The Purpose: Why Build This?
The goal isn't just to talk to a colleague across the office; it's to learn by doing. By building this project, you will:
Understand Audio I/O: Learn how MATLAB interacts with your computer’s microphone and speakers.
Grasp Network Communication: See how to send data packets over a local network using the UDP protocol.
Solve Real-Time Challenges: Confront and solve issues like latency, choppy audio, and continuous data streaming.
The Core Components
Our walkie-talkie will consist of two main scripts:
Sender.m: This script will run on the transmitting computer. It listens to the microphone when a key is pressed, sending the audio data in small chunks over the network.
Receiver.m: This script runs on the receiving computer. It continuously listens for incoming data packets and plays them through the speakers as they arrive.
Step 1: Getting Audio In and Out
Before we touch networking, let's make sure we can capture and play audio. MATLAB's built-in audiorecorder and audioplayer objects make this simple.
Problem Encountered: How do you even access the microphone?
Solution: The audiorecorder object gives us straightforward control.
code
% --- Test Audio Capture and Playback ---
Fs = 8000; % Sample rate in Hz
nBits = 16; % Number of bits per sample
nChannels = 1; % Mono audio
% Create a recorder object
recObj = audiorecorder(Fs, nBits, nChannels);
disp('Start speaking for 3 seconds.');
recordblocking(recObj, 3); % Record for 3 seconds
disp('End of Recording.');
% Get the audio data
audioData = getaudiodata(recObj);
% Play it back
playObj = audioplayer(audioData, Fs);
play(playObj);
Running this script confirms that your microphone and speakers are correctly configured and accessible by MATLAB.
Step 2: Sending Voice Over the Network
Now, we need to send the audioData to another computer. For real-time applications like this, the UDP (User Datagram Protocol) is the ideal choice. It’s a "fire-and-forget" protocol that prioritizes speed over perfect reliability. Losing a tiny packet of audio is better than waiting for it to be re-sent, which would cause noticeable delays (latency).
Problem Encountered: How do you send data continuously without overwhelming the network or the receiver?
Solution: We'll send the audio in small, manageable chunks inside a loop. We need to create a UDP Port object to handle the communication.
Here's the basic structure for the Sender.m script:
code
% --- Sender.m ---
% Define network parameters
remoteIP = '192.168.1.101'; % <--- CHANGE THIS to the receiver's IP
remotePort = 3000;
localPort = 3001;
% Create UDP Port object
udpSender = udpport("LocalPort", localPort, "EnablePortSharing", true);
% Configure audio recorder
Fs = 8000;
nBits = 16;
nChannels = 1;
recObj = audiorecorder(Fs, nBits, nChannels);
disp('Press any key to start transmitting. Press Ctrl+C to stop.');
pause; % Wait for user to press a key
% Start the Push-to-Talk loop
disp('Transmitting... (Hold Ctrl+C to exit)');
while true
recordblocking(recObj, 0.1); % Record a 0.1-second chunk
audioChunk = getaudiodata(recObj);
% Send the audio chunk over UDP
write(udpSender, audioChunk, "double", remoteIP, remotePort);
end
And here is the corresponding Receiver.m script:
code
Matlab
% --- Receiver.m ---
% Define network parameters
localPort = 3000;
% Create UDP Port object
udpReceiver = udpport("LocalPort", localPort, "EnablePortSharing", true, "Timeout", 30);
% Configure audio player
Fs = 8000;
playerObj = audioplayer(zeros(Fs*0.1, 1), Fs); % Pre-buffer
disp('Listening for incoming audio...');
% Start the listening loop
while true
% Wait for and receive data
[audioChunk, ~, ~] = read(udpReceiver, Fs*0.1, "double");
if ~isempty(audioChunk)
% Play the received audio chunk
play(playerObj, audioChunk);
else
disp('No data received. Still listening...');
end
end
Step 3: Solving Real-World Hurdles
Running the code above might work, but you'll quickly notice some issues.
Problem 1: Choppy Audio and High Latency
The audio might sound robotic or delayed. This is because of the buffer size and the processing time. Sending tiny chunks frequently can cause overhead, while sending large chunks causes delay.
Solution: The key is to find a balance.
Tune the Chunk Size: The 0.1 second chunk size in the sender (recordblocking(recObj, 0.1)) is a good starting point. Experiment with values between 0.05 and 0.2. Smaller values reduce latency but increase network traffic.
Use a Buffered Player: Instead of creating a new audioplayer for every chunk, we create one at the start and feed it new data. Our receiver code already does this, which is more efficient.
Problem 2: No Real "Push-to-Talk"
Our sender script starts transmitting and doesn't stop. A real walkie-talkie only transmits when a button is held down.
Solution: Simulating this in a script requires a more advanced technique, ideally using a MATLAB App Designer GUI. However, we can create a simple command-window version using a figure's KeyPressFcn.
Here is an improved concept for the Sender that simulates radio push-to-talk, e.g. https://www.retevis.com/blog/ptt-push-to-talk-walkie-talkies-guide
% --- Advanced_Sender.m ---
function PushToTalkSender()
% -- Configuration --
remoteIP = '192.168.1.101'; % <--- CHANGE THIS
remotePort = 3000;
localPort = 3001;
Fs = 8000;
% -- Setup --
udpSender = udpport("LocalPort", localPort);
recObj = audiorecorder(Fs, 16, 1);
% -- GUI for key press detection --
fig = uifigure('Name', 'Push-to-Talk (Hold ''t'')', 'Position', [100 100 300 100]);
fig.KeyPressFcn = @KeyPress;
fig.KeyReleaseFcn = @KeyRelease;
isTransmitting = false; % Flag to control transmission
disp('Focus on the figure window. Hold the ''t'' key to transmit.');
% --- Main Loop ---
while ishandle(fig)
if isTransmitting
% Non-blocking record and send would be ideal,
% but for simplicity we use short blocking chunks.
recordblocking(recObj, 0.1);
audioChunk = getaudiodata(recObj);
write(udpSender, audioChunk, "double", remoteIP, remotePort);
disp('Transmitting...');
else
pause(0.1); % Don't burn CPU when idle
end
drawnow; % Update figure window
end
% --- Callback Functions ---
function KeyPress(~, event)
if strcmp(event.Key, 't')
isTransmitting = true;
end
end
function KeyRelease(~, event)
if strcmp(event.Key, 't')
isTransmitting = false;
disp('Transmission stopped.');
end
end
end
Conclusion and Next Steps
You've now built the foundation of a real-time voice communication tool in MATLAB! You've learned how to capture audio, send it over a network using UDP, and handle some of the fundamental challenges of real-time streaming.
This project is the perfect starting point for more advanced explorations:
Build a Full GUI: Use App Designer to create a user-friendly interface with a proper push-to-talk radio button.
Implement Noise Reduction: Apply a filter (e.g., a simple low-pass or a more advanced spectral subtraction algorithm) to the audioChunk before sending it.
Add Channels: Modify the code to use different UDP ports, allowing users to select a "channel" to talk on.
In a previous discussion,
we looked at a variety of infallible tests for primality, but all of them were too slow to be viable for large numbers. In fact, all of the methods discussed there will fail miserably for even moderately large numbers, those with just a few dozen decimal digits. That does not even begin to push into the realm of large numbers. In turn, that forces us into a different realm of tests - tests which are usually and even almost always correct, but can sometimes incorrectly predict primality.
In this discussion, I will be trying to convince you that the Fermat test for primality can be a quite good test when the number is sufficiently large. Except of course, when it is really bad. Even so, the Fermat test for primality is both a useful tool as well as a necessary underpinning for several other better tests.
The Fermat test for primality relies on Fermat's little theorem, a perhaps under-appreciated tool. Even the name implies it is of little interest. I'm not taking about the famous last theorem, only proven in recent years, but his little theorem.
If you want to look over some nice ways to prove the little theorem, take a read in this link:
I will readily admit that long ago, when I learned about the little theorem in a nearly forgotten class, I thought it was interesting, but why would I care? Not until I learned more mathematics and saw Fermat’s little theorem appearing in different places did I begin to appreciate it. Fermat tells us that, IF P is a prime, AND w is co-prime with P (so the two are relatively prime, sharing no common factors except 1), then it must be true that
mod(w^(P-1),P) == 1
Try it out. Does it work? Be careful though as too large of an exponent will cause problems in double precision, and that is not difficult to do. As a test case that will not overwhelm doubles, note that 13 is prime, and 3 shares no common factors with 13, so we satisfy the requirements for Fermat's little theorem.
mod(3^12,13)
ans = 1
We can even verify that any co-prime of 13 will yield the same result.
mod((1:12).^12,13)
ans = 1×12
1 1 1 1 1 1 1 1 1 1 1 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Indeed it worked, suggesting what we knew all along, that 13 is prime. The little Fermat test for primality of the number P uses a converse form of Fermat's little theorem, thus given a co-prime number w known as the witness, is that if
mod(w^(P-1),P)==1
then we have evidence that P is indeed prime. This is not conclusive evidence, but still it is evidence. It is not conclusive because the converse of a true statement is not always true.
The analogy I like here is if we lived in a universe where all crows are black. (I'll ask you to pretend this is true. In fact, some crows have a mutation, making them essentially albino crows. For the purposes of this thought experiment, pretend this cannot happen.) Now, suppose I show you a picture of a bird which happens to be black. Do you know the bird to be a crow? Of course not, as the bird may be a raven, or a redwing blackbird (until you see the splash of red on the wing), a common grackle, a European starling in summer plumage, a condor, etc. But having seen black plumage, it is now more likely the bird is indeed a crow. I would call this a moderately weak evidentiary test for crow-ness.
Little Fermat may seem to be of little value when testing for primality for two reasons. First, computing the remainder would seem to be highly CPU intensive for large P. In the example above, I had only to compute 3^12=531441, which is not that large. But for numbers with many thousands or millions of digits, directly raising even a number as small as 2 to that power will overwhelm any computer. Secondly, if we do that computation, little Fermat does not conclusively prove P to be prime.
Our savior in one respect is the powermod tool. And that helps greatly, since we can compute the remainder in a reasonable time. A powermod call is quite fast even for huge powers. (I won't get into how powermod works here, since that alone is probably worth a discussion. I could though, if I see some interest because there are some very pretty variations of the powermod algorithm. I hope to show you one of them when I discuss the Fibonacci test for primality in a future post.) Trying the little Fermat test using powermod on a number with 1207 decimal digits, I’ll first do a time check.
P = 4000*sym(2)^3999 - 1;
timeit(@() powermod(2,P-1,P))
ans = 0.0224
As you can see, powermod really is pretty fast. Compared to an isprime test on that number it would show a significant difference.
I have said before that little Fermat is not a conclusive test. In fact, a good trick is to perform a second little Fermat test, using a different witness. If the second test also indicates primality, then we have additional evidence that P is in fact prime.
w = [2 3]; % Two parallel witnesses
powermod(w,P-1,P)
This value for P is indeed prime, and little Fermat suggests it is, doubly suggestive in that test since I actually performed two parallel tests. Here however, we need to understand when it will fail, and how often it will fail.
If we perform a little Fermat test for primality, we will never see false negatives, that is, if any test with any witness ever indicates a number is composite, then it is certainly composite. (The contrapositive of a true statement is always true.) The alternate class of failure is the false positive, where little Fermat indicates a number is prime when it was actually composite.
If P is composite, and w co-prime with P, we call P a Fermat pseudo-prime for the witness w if we see a remainder of 1 when P was in fact composite. When that happens, the witness (w) is called a Fermat liar for the primality of P. (A list of some Fermat pseudo-primes where 2 is a Fermat liar can be found in sequence A001567 of the OEIS.)
In the case of 4000*2^3999-1, I claimed the number to be in fact prime, and it was identified so (as PROBABLY prime by little Fermat. Next, consider another number from that same family. I’ll perform three parallel tests on it, with witnesses 2, 3, and 5. This will suggest the value of doing parallel tests on a number to reduce the failure rate from little Fermat.
P2 = 1024*sym(2)^1023 - 1;
w = [2; 3; 5];
gcd(w,P2)
F2 = powermod(w,P2-1,P2)
logical(F2 == 1)
ans = 3×1 logical array
1 0 0
As you can see, P2 is co-prime with all of 2, 3 and 5, but 2 is a Fermat liar, whilst 3 and 5 are Fermat truth tellers, identifying P2 as certainly composite. So the little Fermat test can definitely fail for SOME witnesses, since we see a disagreement. However, an interesting fact about P2 above is it is also a Mersenne number with prime exponent, thus it can be written as 2^1033-1, where 1033 is prime. I can go into more detail about this case later, but we can show that 2 is always a Fermat liar for composite Mersenne numbers when the exponent is itself prime. I’ll try to leave more detail on this matter in a future discussion, or perhaps a comment.
Next, consider the composite integer 51=3*17. As the product of two primes, it is clearly not itself prime.
P51 = 51;
w0 = 2:P51-2;
w = w0(gcd(w0,P51) == 1)
w = 1×30
2 4 5 7 8 10 11 13 14 16 19 20 22 23 25 26 28 29 31 32 35 37 38 40 41 43 44 46 47 49
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Note that I did not include 1 or 50 in that set, since 1 raised to any power is 1, and 50 is congruent to -1, mod 51. -1 raised to any even power is also always 1, and 51-1 is an even number. And so when we are working modulo 51, both 1 and 50 are not useful witnesses in terms of the little Fermat test.
R = powermod(w,P-1,P)
w(R == 1)
ans = 1×30
2 4 5 7 8 10 11 13 14 16 19 20 22 23 25 26 28 29 31 32 35 37 38 40 41 43 44 46 47 49
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
This teaches us that when 51 is tested for primality using the little Fermat test, there are 2 distinct witnesses w (16 and 35) we could have chosen which would have been Fermat liars, but all 28 other potential co-prime witnesses would have been truth tellers, accurately showing 51 to be composite. Proportionally, little Fermat will have been correct roughly 93% of the time, since only 2 of these 30 possible tests returned a false positive. (I’ll add that for any modulus P, if w<P is not co-prime with the modulus, then the computation mod(w^(P-1),P) will always return a non-unit result, and therefore we can theoretically use any integer w from the set 2:P-2 as a witness. However if w is co-prime with P then P is clearly not prime, and the entire problem becomes a little less interesting. As such, I will only consider co-prime witnesses for this discussion.) Regardless, that would make the little Fermat test for P=51 even more often correct, since it returns the correct result of composite for 46 out of the 48 possible witnesses 2:49. Does this mean Little Fermat is indeed the basis for a good test to rely on to learn if a number is prime? Well, yes. And no.
Little Fermat forms a very good test most of the time, but reliance is a strong word. This means we need to explore the little Fermat test in more depth, focusing on Fermat liars and the case of false positives. To offer some appreciation of the false positive rate, offline, I have tested all composite integers between 4 and 10000, for all their possible co-prime witnesses.
load FermatLiarsData
In that .mat file, I've saved three vectors, X, witnessCount, and liarCount. X is there just to use for plotting purposes and is NaN for all non-composite entries.
whos X witnessCount liarCount
Name Size Bytes Class Attributes X 1x10000 80000 double liarCount 1x10000 80000 double witnessCount 1x10000 80000 double
The vector witnessCount is the number of valid witnesses for the corresponding number in X. Corresponding to that is the vector liarCount, which is the number of Fermat liars I found for each composite in X.
How many Fermat test useful witnesses are there for any integer X? This is just 2 less than the number of coprimes of X. The number of coprimes is given by the Euler totient function, commonly called phi(X). (I’ll be going into more depth on the totient in the next chapter of this series, because the Euler totient is a crucial part of understanding how all of this works.)
The witness count is phi(X)-2. Why subtract 2? 1 can never be a witness, but 1 is technically coprime to everything. The same applies to X-1 (which is congruent to -1 mod X.) As such, there are phi(X)-2 coprimes to consider. (I've posted a function called totient on the FEX, but it is easily computed if you know the factorization of X. Or for small numbers, you can just use GCD to identify all co-primes, and count them.)
plot(X,witnessCount,'.')
From that plot, you can learn a few interesting things. (As a mathematician, this is what I love the most, thus to look at whay may be the simplest, most boring plot, and try to find something of value, something I had never thought of before.) For example, we know that when X is prime, then everything from the set 2:X-2 is a valid witness. So the upper boundary on that plot will be the line y==x. As well, there are a few numbers where the order of the set of witnesses will be close to the maximum possible. For example, 961=31*31, has 928 valid witnesses. That makes some sense, as 961 is the square of a prime (31), so we know 961 is divisible only by 31. Only multiples of 31 will not be coprime with 961.
But how about the lower boundary? The least number of valid witnesses will always come from highly composite numbers, because they will share common factors with almost everything. For example 30 = 2*3*5, or 210=2*3*5*7.
witnessCount([30 210 420])
ans = 1×3
6 46 94
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
A good discussion about the lower bound for that plot can be found here:
What really matters to us though, is the fraction of the useful witnesses for a little Fermat test that yield a false positive.
plot(X,liarCount./witnessCount,'b.')
Cind = liarCount == witnessCount;
hold on
plot(X(Cind),1,'ro')
ylabel('Liar fraction')
xlabel('X')
title('Fermat pseudo-prime strength')
hold off
A look at this plot shows seven circles in red, corresponding to X from the list {561, 1105, 1729, 2465, 2821, 6601, 8911} which are collectively known as Carmichael numbers. These are numbers where all witnesses return a false positive. Carmichael numbers are themselves fairly rare. You can find a list of them as sequence A002997 in the OEIS. And for those of you who have never wandered around the OEIS, please take this opportunity to do so now. The OEIS stands for Online Encyclopedia of Integer Sequences. It contains a wealth of interesting knowledge about integers and integer sequences.)
There are a few other interesting numbers we can find in that plot, like 91 and 703, where roughly 50% of the valid witnesses yield false positives. Of the complete set, which numbers did return at least a 25% false positive rate for primality? These numbers would be known as strong pseudo-primes for the little Fermat test, because they are pseudo-primes for at least 25% of the potential witnesses. These strong pseudo-primes have some interesting similarities to the Carmichael numbers. (My next post will go into more depth on Carmichael numbers and strong pseudo-primes. At the moment, I am merely interested in looking at the how often the little Fermat test fails overall.)
find(liarCount./witnessCount> 0.25)
ans = 1×29
15 45 65 91 105 133 231 341 481 561 645 703 1105 1541 1729 1891 2465 2701 2821 3201 4033 4371 5461 5565 6533 6601 7107 8321 8911
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
You should notice the spacing between successive strong Fermat pseudo-primes is growing slowly, with a spacing of roughly 800 on average in the vicinity of 10000. If I step out beyond by a factor of 10, the next strong Fermat pseudo-primes after 1e5 are {101101, 104653, 107185, 109061, 111361, 114589, 115921 126217, 126673}, so that average spacing is definitely growing.
Given that set, now we can look at the prime factorizations of each of those strong pseudo-primes. Can we learn something about them?
arrayfun(@factor,find(liarCount./witnessCount> 0.25),'UniformOutput',false)
ans = 1×29 cell array
Columns 1 through 13 {[3 5]} {[3 3 5]} {[5 13]} {[7 13]} {[3 5 7]} {[7 19]} {[3 7 11]} {[11 31]} {[13 37]} {[3 11 17]} {[3 5 43]} {[19 37]} {[5 13 17]} Columns 14 through 25 {[23 67]} {[7 13 19]} {[31 61]} {[5 17 29]} {[37 73]} {[7 13 31]} {[3 11 97]} {[37 109]} {[3 31 47]} {[43 127]} {[3 5 7 53]} {[47 139]} Columns 26 through 29 {[7 23 41]} {[3 23 103]} {[53 157]} {[7 19 67]}
Perhaps the most glaring thing I see in that set of factors is almost all of those strong Fermat pseudo-primes are square free. That is, in that list, only 45=3*3*5 had any replicated factor at all. That property of being square free is something we will see is necessary to be a Carmichael number, but it also suggests that a simple roughness test applied in advance would have eliminated almost all of those strong pseudo-primes as obviously not prime, even at a very low level of roughness.
In fact, for most composite integers, most witnesses do indeed return a negative, indicating the number is not prime, and therefore composite. Little Fermat does not commonly tell falsehoods, even though it can do so.
semilogy(X,movmedian(liarCount./witnessCount,20,'omitnan'),'b-')
title('False positive fraction for composites')
yline(0.0003,'r')
We can learn from this last plot that as the number to be tested grows large, the median false positive rate for little Fermat, even for X as low as only 10000, is roughly 0.0003. (It continues to decrease for larger X too. In fact, I’ve read that when X is on the order of 2^256, the relative fraction of Fermat liars is on the order of 1 in 1e12, and it continues to decrease as X grows in magnitude. In my eyes, that seems pretty good for an imperfect test. Not perfect, but not bad when paired with roughness and perhaps a second little Fermat test using a different witness, and we will start to see tests which bear a higher degree of strength.)
I’ll stop at this point in this post because the post is getting lengthy. In my next post, I’d like to visit some questions about what are Carmichael numbers, about whether some witnesses are better than others, and if there are any numbers which lack any Fermat liars. However, in order to dive more deeply, I will need to explain how/why/when the little Fermat test works, and what causes Fermat liars. Stay tuned, because this starts to get interesting.
Software‑defined vehicles are becoming reality—and this #3 ranked session shows how. In this keynote, Daniel Scurtu (NXP) demonstrates how MathWorks and NXP are working together to accelerate system‑level embedded development.
🔋 Using a vehicle electrification demo that runs across multiple NXP processors, you’ll see:
  • Model‑Based Design workflows from concept to deployment
  • Intelligent battery management and motor control
  • Automatic code generation and hardware deployment
  • ☁️ Real‑time cloud analytics and over‑the‑air updates
🛠️ Featuring MATLAB and Simulink products alongside NXP tools like Model-based Design Toolbox (MBDT), S32 Design Studio IDE, and Real-Time Drivers (RTD), this session highlights an end‑to‑end approach that reduces complexity and speeds the transition to software‑defined vehicles.
👉 Watch the session on demand and catch what you missed
What’s New in MATLAB and Simulink in 2025
If you missed this session live, this is one of those “everyone’s talking about it” updates you’ll want to catch up on. 👀
This session is packed with the kinds of enhancements that quietly (and not so quietly) change how you work every day.
Here’s why it earned a spot in our Top 4:
  • A redesigned MATLAB desktop with customizable sidebars and light/dark themes—built to adapt to how you work
  • New side panels for coding and development tasks, plus more control over organizing and customizing figures
  • MATLAB Copilot, a generative AI assistant optimized for MATLAB to help you explore ideas, learn techniques, and boost productivity directly in the desktop
  • Simulink workflow improvements like a redesigned Simulink scope, more detailed info in quick insert, and automatic signal line straightening
  • Enhanced Python integration across MATLAB and Simulink
  • New AI deployment options optimized for Qualcomm and Infineon hardware targets
If staying current with MATLAB and Simulink is part of your role—or your edge—this session is a must‑watch. Missing it means missing context for features that will shape how you work in 2026 and beyond.
🎥 Watch the recording and see what’s new.
💬 Discussion topic:
Which single update from this release do you think will most improve your day‑to‑day workflow, and why?
🤖 What does it take to make robotic motion feel… human?
In this session, Tetsushi Sotowa shares how NSK is combining advanced control techniques with deep learning to enable human‑like grasping in electric grippers
You’ll see a real‑world case study featuring:
  • Bilateral and force control systems developed in‑house
  • MATLAB and Simulink–based control workflows
  • Deep learning integration using Deep Learning Toolbox
  • A practical path from mechatronics research to intelligent actuation
The result: an AI‑enhanced actuator capable of more natural, responsive grasping—bringing robotics one step closer to human motion.
👉 Interested in AI‑driven robotics and advanced control? Check out the session now from MATLAB EXPO 2025.
Missed a crowd‑favorite session feautring Marko Gecic at Infineon and Lucas Garcia at MathWorks?
This talk shows how to verify and test AI for real‑time, safety‑critical systems using an AI virtual sensor that estimates motor rotor position on an Infineon AURIX TC4x microcontroller. Built with MATLAB and Simulink, the demo covers training, verification, and real‑time control across a wide range of operating conditions.
You’ll see practical techniques to test robustness, measure sensitivity to input perturbations, and detect out‑of‑distribution behavior—critical steps for meeting standards like ISO 26262 and ISO 8800. The session also highlights how Model‑Based Design leverages AURIX TC4x features such as the PPU and CDSP to deploy AI with confidence.
Featuring: Dr. Arthur Clavière, Collins Aerospace
How can we be confident that a machine learning model will behave safely on data it’s never seen—especially in avionics? In this session, Dr. Arthur Clavière introduces a formal methods approach to verifying maching learning generalization. The talk highlights how formal verification can be apploied toneural networks in safety-critical avionics systems.
💬 Discussion question:
Where do you see formal verification having the biggest impact on deploying ML in safety‑critical systems—and what challenges still stand in the way?
Join the conversation below 👇
🚀 Unlock Smarter Control Design with AI
What if AI could help you design better controllers—faster and with confidence?
In this session, Naren Srivaths Raman and Arkadiy Turevskiy (MathWorks) show how control engineers are using MATLAB and Simulink to integrate AI into real-world control design and implementation.
You’ll see how AI is being applied to:
🧠 Advanced plant modeling using nonlinear system identification and reduced order modeling
📡 Virtual sensors and anomaly detection to estimate hard-to-measure signals
🎯 Datadriven control design, including nonlinear MPC with neural statespace models and reinforcement learning
Productivity gains with generative AI, powered by MATLAB Copilot
At #9 in our MATLAB EXPO 2025 countdown: From Tinkerer to Developer—A Journey in Modern Engineering Software Development
A big thank‑you to Greg Diehl at NAVAIR and Michelle Allard at MathWorks, the team behind this session, for sharing their multi‑year evolution from rapid‑fire experimenting to disciplined, scalable software development.
If you’ve ever wondered what it really takes to move MATLAB code from “it works!” to “it’s ready for production,” this talk captures that transition. The team highlights how improved testing practices, better structure, and close collaboration with MathWorks experts helped them mature their workflows and tackle challenges around maintainability and code quality.
Curious about the pivotal moments that helped them level up their engineering software practices?
Over the past few days I noticed a minor change on the MATLAB File Exchange:
For a FEX repository, if you click the 'Files' tab you now get a file-tree–style online manager layout with an 'Open in new tab' hyperlink near the top-left. This is very useful:
If you want to share that specific page externally (e.g., on GitHub), you can simply copy that hyperlink. For .mlx files it provides a perfect preview. I'd love to hear your thoughts.
EXAMPLE:
🤗🤗🤗
Couldn’t catch everything at MATLAB EXPO 2025? You’re not alone. Across keynotes and track talks, there were too many gems for one sitting. For the next 9 weeks, we’ll reveal the "Top 10" sessions attended (workshops excluded)—one per week—so you can binge the best and compare notes with peers.
Starting at #10: Simulation-Driven Development of Autonomous UAVs Using MATLAB
A huge thanks to Dr. Shital S. Chiddarwar from Visvesvaraya National Institute of Technology Nagpur who delivered this presentation online at MATLAB EXPO 2025. Are you curious how this workflow accelerates development and boosts reliability?
I recently created a short 5-minute video covering 10 tips for students learning MATLAB. I hope this helps!
You may have come across code that looks like that in some languages:
stubFor(get(urlPathEqualTo("/quotes"))
.withHeader("Accept", equalTo("application/json"))
.withQueryParam("s", equalTo(monitoredStock))
.willReturn(aResponse())
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\\"symbol\\": \\"XYZ\\", \\"bid\\": 20.2, " + "\\"ask\\": 20.6}")))
That’s Java. Even if you can’t fully decipher it, you can get a rough idea of what it is supposed to do, build a rather complex API query.
Or you may be familiar with the following similar and frequent syntax in Python:
import seaborn as sns
sns.load_dataset('tips').sample(10, random_state=42).groupby('day').mean()
Here’s is how it works: multiple method calls are linked together in a single statement, spanning over one or several lines, usually because each method returns the same object or another object that supports further calls.
That technique is called method chaining and is popular in Object-Oriented Programming.
A few years ago, I looked for a way to write code like that in MATLAB too. And the answer is that it can be done in MATLAB as well, whevener you write your own class!
Implementing a method that can be chained is simply a matter of writing a method that returns the object itself.
In this article, I would like to show how to do it and what we can gain from such a syntax.
Example
A few years ago, I first sought how to implement that technique for a simulation launcher that had lots of parameters (far too many):
lauchSimulation(2014:2020, true, 'template', 'TmplProd', 'Priority', '+1', 'Memory', '+6000')
As you can see, that function takes 2 required inputs, and 3 named parameters (whose names aren’t even consistent, with ‘Priority’ and ‘Memory’ starting with an uppercase letter when ‘template’ doesn’t).
(The original function had many more parameters that I omit for the sake of brevity. You may also know of such functions in your own code that take a dozen parameters which you can remember the exact order.)
I thought it would be nice to replace that with:
SimulationLauncher() ...
.onYears(2014:2020) ...
.onDistributedCluster() ... % = equivalent of the previous "true"
.withTemplate('TmplProd') ...
.withPriority('+1') ...
.withReservedMemory('+6000') ...
.launch();
The first 6 lines create an object of class SimulationLauncher, calls several methods on that object to set the parameters, and lastly the method launch() is called, when all desired parameters have been set.
To make it cleared, the syntax previously shown could also be rewritten as:
launcher = SimulationLauncher();
launcher = launcher.onYears(2014:2020);
launcher = launcher.onDistributedCluster();
launcher = launcher.withTemplate('TmplProd');
launcher = launcher.withPriority('+1');
launcher = launcher.withReservedMemory('+6000');
launcher.launch();
Before we dive into how to implement that code, let’s examine the advantages and drawbacks of that syntax.

Benefits and drawbacks

Because I have extended the chained methods over several lines, it makes it easier to comment out or uncomment any one desired option, should the need arise. Furthermore, we need not bother any more with the order in which we set the parameters, whereas the usual syntax required that we memorize or check the documentation carefully for the order of the inputs.
More generally, chaining methods has the following benefits and a few drawbacks:
Benefits:
  • Conciseness: Code becomes shorter and easier to write, by reducing visual noise compared to repeating the object name.
  • Readability: Chained methods create a fluent, human-readable structure that makes intent clear.
  • Reduced Temporary Variables: There's no need to create intermediary variables, as the methods directly operate on the object.
Drawbacks:
  • Debugging Difficulty: If one method in a chain fails, it can be harder to isolate the issue. It effectively prevents setting breakpoints, inspecting intermediate values, and identifying which method failed.
  • Readability Issues: Overly long and dense method chains can become hard to follow, reducing clarity.
  • Side Effects: Methods that modify objects in place can lead to unintended side effects when used in long chains.

Implementation

In the SimulationLauncher class, the method lauch performs the main operation, while the other methods just serve as parameter setters. They take the object as input and return the object itself, after modifying it, so that other methods can be chained.
classdef SimulationLauncher
properties (GetAccess = private, SetAccess = private)
years_
isDistributed_ = false;
template_ = 'TestTemplate';
priority_ = '+2';
memory_ = '+5000';
end
methods
function varargout = launch(obj)
% perform whatever needs to be launched
% using the values of the properties stored in the object:
% obj.years_
% obj.template_
% etc.
end
function obj = onYears(obj, years)
assert(isnumeric(years))
obj.years_ = years;
end
function obj = onDistributedCluster(obj)
obj.isDistributed_ = true;
end
function obj = withTemplate(obj, template)
obj.template_ = template;
end
function obj = withPriority(obj, priority)
obj.priority_ = priority;
end
function obj = withMemory( obj, memory)
obj.memory_ = memory;
end
end
end
As you can see, each method can be in charge of verifying the correctness of its input, independantly. And what they do is just store the value of parameter inside the object. The class can define default values in the properties block.
You can configure different launchers from the same initial object, such as:
launcher = SimulationLauncher();
launcher = launcher.onYears(2014:2020);
launcher1 = launcher ...
.onDistributedCluster() ...
.withReservedMemory('+6000');
launcher2 = launcher ...
.withTemplate('TmplProd') ...
.withPriority('+1') ...
.withReservedMemory('+7000');
If you call the same method several times, only the last recorded value of the parameter will be taken into acount:
launcher = SimulationLauncher();
launcher = launcher ...
.withReservedMemory('+6000') ...
.onDistributedCluster() ...
.onYears(2014:2020) ...
.withReservedMemory('+7000') ...
.withReservedMemory('+8000');
% The value of "memory" will be '+8000'.
If the logic is still not clear to you, I advise you play a bit with the debugger to better understand what’s going on!

Conclusion

I love how the method chaining technique hides the minute detail that we don’t want to bother with when trying to understand what a piece of code does.
I hope this simple example has shown you how to apply it to write and organise your code in a more readable and convenient way.
Let me know if you have other questions, comments or suggestions. I may post other examples of that technique for other useful uses that I encountered in my experience.
If you use tables extensively to perform data analysis, you may at some point have wanted to add new functionalities suited to your specific applications. One straightforward idea is to create a new class that subclasses the built-in table class. You would then benefit from all inherited existing methods.
Unfortunately, as has been observed, that is not possible because the table class is Sealed.
One workaround is to create a new class that wraps a table as a Property, and re-implement all the methods that you need and are already defined for table. The is not too difficult, except for the subsref method, for which I’ll provide the code below.
Class definition
Defining a wrapper of the table class is quite straightforward. In this example, I call the class “Report” because that is what I intend to use the class for, to compute and store reports. The constructor just takes a table as input:
classdef Rapport
methods
function obj = Report(t)
if isa(t, 'Report')
obj = t;
else
obj.t_ = t;
end
end
end
properties (GetAccess = private, SetAccess = private)
t_ table = table();
end
end
I designed the constructor so that it converts a table into a Report object, but also so that if we accidentally provide it with a Report object instead of a table, it will not generate an error.
Reproducing the behaviour of the table class
Implementing the existing methods of the table class for the Report class if pretty easy in most cases.
I made use of a method called “table” in order to be able to get the data back in table format instead of a Report, instead of accessing the property t_ of the object. That method can also be useful whenever you wish to use the methods or functions already existing for tables (such as writetable, rowfun, groupsummary…).
classdef Rapport
...
methods
function t = table(obj)
t = obj.t_;
end
function r = eq(obj1,obj2)
r = isequaln(table(obj1), table(obj2));
end
function ind = size(obj, varargin)
ind = size(table(obj), varargin{:});
end
function ind = height(obj, varargin)
ind = height(table(obj), varargin{:});
end
function ind = width(obj, varargin)
ind = width(table(obj), varargin{:});
end
function ind = end(A,k,n)
% ind = end(A.t_,k,n);
sz = size(table(A));
if k < n
ind = sz(k);
else
ind = prod(sz(k:end));
end
end
end
end
In the case of horzcat (same principle for vertcat), it is just a matter of converting back and forth between the table and Report classes:
classdef Rapport
...
methods
function r = horzcat(obj1,varargin)
listT = cell(1, nargin);
listT{1} = table(obj1);
for k = 1:numel(varargin)
kth = varargin{k};
if isa(kth, 'Report')
listT{k+1} = table(kth);
elseif isa(kth, 'table')
listT{k+1} = kth;
else
error('Input must be a table or a Report');
end
end
res = horzcat(listT{:});
r = Report(res);
end
end
end
Adding a new method
The plus operator already exists for the table class and works when the table contains all numeric values. It sums columns as long as the tables have the same length.
Something I think would be nice would be to be able to write t1 + t2, and that would perform an outerjoin operation between the tables and any sizes having similar indexing columns.
That would be so concise, and that's what we’re going to implement for the Report class as an example. That is called “plus operator overloading”. Of course, you could imagine that the “+” operator is used to compute something else, for example adding columns together with regard to the keys index. That depends on your needs.
Here’s a unittest example:
classdef ReportTest < matlab.unittest.TestCase
methods (Test)
function testPlusOperatorOverload(testCase)
t1 = array2table( ...
{ 'Smith', 'Male' ...
; 'JACKSON', 'Male' ...
; 'Williams', 'Female' ...
} , 'VariableNames', {'LastName' 'Gender'} ...
);
t2 = array2table( ...
{ 'Smith', 13 ...
; 'Williams', 6 ...
; 'JACKSON', 4 ...
}, 'VariableNames', {'LastName' 'Age'} ...
);
r1 = Report(t1);
r2 = Report(t2);
tRes = r1 + r2;
tExpected = Report( array2table( ...
{ 'JACKSON' , 'Male', 4 ...
; 'Smith' , 'Male', 13 ...
; 'Williams', 'Female', 6 ...
} , 'VariableNames', {'LastName' 'Gender' 'Age'} ...
) );
testCase.verifyEqual(tRes, tExpected);
end
end
end
And here’s how I’d implement the plus operator in the Report class definition, so that it also works if I add a table and a Report:
classdef Rapport
...
methods
function r = plus(obj1,obj2)
table1 = table(obj1);
table2 = table(obj2);
result = outerjoin(table1, table2 ...
, 'Type', 'full', 'MergeKeys', true);
r = reportingits.dom.Rapport(result);
end
end
end
The case of the subsref method
If we wish to access the elements of an instance the same way we would with regular tables, whether with parentheses, curly braces or directly with the name of the column, we need to implement the subsref and subsasgn methods. The second one, subsasgn is pretty easy, but subsref is a bit tricky, because we need to detect whether we’re directing towards existing methods or not.
Here’s the code:
classdef Rapport
...
methods
function A = subsasgn(A,S,B)
A.t_ = subsasgn(A.t_,S,B);
end
function B = subsref(A,S)
isTableMethod = @(m) ismember(m, methods('table'));
isReportMethod = @(m) ismember(m, methods('Report'));
switch true
case strcmp(S(1).type, '.') && isReportMethod(S(1).subs)
methodName = S(1).subs;
B = A.(methodName)(S(2).subs{:});
if numel(S) > 2
B = subsref(B, S(3:end));
end
case strcmp(S(1).type, '.') && isTableMethod (S(1).subs)
methodName = S(1).subs;
if ~isReportMethod(methodName)
error('The method "%s" needs to be implemented!', methodName)
end
otherwise
B = subsref(table(A),S(1));
if istable(B)
B = Report(B);
end
if numel(S) > 1
B = subsref(B, S(2:end));
end
end
end
end
end
Conclusion
I believe that the table class is Sealed because is case new methods are introduced in MATLAB in the future, the subclass might not be compatible if we created any or generate unexpected complexity.
The table class is a really powerful feature.
I hope this example has shown you how it is possible to extend the use of tables by adding new functionalities and maybe given you some ideas to simplify some usages. I’ve only happened to find it useful in very restricted cases, but was still happy to be able to do so.
In case you need to add other methods of the table class, you can see the list simply by calling methods(’table’).
Feel free to share your thoughts or any questions you might have! Maybe you’ll decide that doing so is a bad idea in the end and opt for another solution.
Missed a session or want to revisit your favorites? Now’s your chance!
Explore 42 sessions packed with insights, including:
4 inspiring keynotes
22 Customer success stories
5 Partner innovations
11 MathWorks-led technical talks
Each session comes with video recordings and downloadable slides, so you can learn at your own pace.
Thank you to everyone who attended the workshop A Hands-On Introduction to Reinforcement Learning! Now that you all have had some time to digest the content, I wanted to create a thread where you could ask any further questions, share insights, or discuss how you're applying the concepts to your work. Please feel free to share your thoughts in the thread below! And for your reference, I have attached a PDF version of the workshop presentation slides to this post.
If you were interested in joining the RL workshop but weren't able to attend live (maybe because you were in one of our other fantastic workshops instead!), you can find the workshop hands-on material in this shared MATLAB Drive folder. To access the exercises, simply download the MATLAB Project Archive (.mlproj) file or copy it to your MATLAB Drive, extract the files, and open the project (.prj). Each exercise has its own live script (.mlx file) which contains all the instructions and individual steps for each exercise. Happy (reinforcement) learning!
Is it possible to get the slides from the Hands-On-Workshops?
I can't find them in the proceedings. I'm particularly interested in the Reinforcement Learning workshop, but unfortunately I couldn't participate.
Thanks in advance!
Great material, examples and skillfully guided. And, of course, very useful.
Thanks!
Hi, what’s the best way to learn MATLAB, Simulink, and Simscape? Do you recommend a learning path? I work in the Electrical & Electronics area for automotive systems.
Don’t miss out on two incredible keynotes that will shape the future of engineering and innovation:
1️What’s New in MATLAB and Simulink in 2025
Get an inside look at the latest features designed to supercharge your workflows:
  • A redesigned MATLAB desktop with customizable sidebars, light/dark themes, and new panels for coding tasks
  • MATLAB Copilot – your AI-powered assistant for learning, idea generation, and productivity
  • Simulink upgrades, including an enhanced quick insert tool, auto-straightening signal lines, and new methods for Python integration
  • New options to deploy AI models on Qualcomm and Infineon hardware
2️Accelerating Software-Defined Vehicles with Model-Based Design
See how MathWorks + NXP are transforming embedded system development for next-gen vehicles:
  • Vehicle electrification example powered by MATLAB, Simulink, and NXP tools
  • End-to-end workflow: modeling → validation → code generation → hardware deployment → real-time cloud monitoring
📅 When: November 13
💡Why Join? Stay ahead with cutting-edge tools, workflows, and insights from industry leaders.
👉 Register now and be part of the future of engineering!