ans =
Hello and a warm welcome to all! We're thrilled to have you visit our community. MATLAB Central is a place for learning, sharing, and connecting with others who share your passion for MATLAB and Simulink. To ensure you have the best experience, here are some tips to get you started:
- Read the Community Guidelines: Understanding our community standards is crucial. Please take a moment to familiarize yourself with them. Keep in mind that posts not adhering to these guidelines may be flagged by moderators or other community members.
- Ask Technical Questions at MATLAB Answers: If you have questions related to MathWorks products, head over to MATLAB Answers (new question form - Ask the community). It's the go-to spot for technical inquiries, with responses often provided within an hour, depending on the complexity of the question and volunteer availability. To increase your chances of a speedy reply, check out our tips on how to craft a good question (link to post on asking good questions).
- Choosing the Right Channel: We offer a variety of discussion channels tailored to different contexts. Select the one that best fits your post. If you're unsure, the General channel is always a safe bet. If you feel there's a need for a new channel, we encourage you to suggest it in the Ideas channel.
- Reporting Issues: If you encounter posts that violate our guidelines, please use the 🚩Flag/Report feature (found in the 3-dot menu) to bring them to our attention.
- Quality Control: We strive to maintain a high standard of discussion. Accounts that post spam or too much nonsense may be subject to moderation, which can include temporary suspensions or permanent bans.
- Share Your Ideas: Your feedback is invaluable. If you have suggestions on how we can improve the community or MathWorks products, the Ideas channel is the perfect place to voice your thoughts.
Enjoy yourself and have fun! We're committed to fostering a supportive and educational environment. Dive into discussions, share your expertise, and grow your knowledge. We're excited to see what you'll contribute to the community!
Hi everyone, I am from India ..Suggest some drone for deploying code from Matlab.
T < 2 years
39%
2 years < T < 5 years
25%
5 years < T < 10 years
16%
10 years < T < 20 years
10%
T > 20 years
10%
774 votes
About a year ago, I made a rubix cube solver with the goal of solving a cube faster than I could in real life. It was a fun and educating project, and while it is a long way from optimal, I finished with satisfying results.
How the solver is made is a story for another time, but I always wanted to have a 3D illustration of how the moves are performed to reach the solved state. Lacking the motivation at the time, the illustrative part was forgotten... Untill a couple of weeks ago when I found out about the MATLAB Shorts Mini Hack. It was the perfect motivation to finish up!
This post will detail my entry and remixes (you should check them out before reading!) in this years mini hack. I am not a man to spare any detail, and I've recently saved up a bunch of characters from being limited to 2000, so it may be a bit wordy, but I'll try to keep it entertaining. How it works, lessons learned, sidetracks, pitfalls found, and everything in between is detailed here. So feel free to peruse the sections and pick the ones that sound interesting!
How can I make it move?
Intuativly one would use standard rubix notation to determine the moves, but due to the character limitation and me wanting the ability to rotate the middle rows and the cube as a whole I decided against this.
At the tippy top, there is an 3xn character array, MS, containing the movement sequence of the cube. The three rows contains:
- The axis to rotate around. - Defined by character x, y, z, or p (none of them).
- The row to rotate. - Defined by character 1, 2, 3, or 4 (all of them)
- The direction of the rotation. - Defined by character n, or p (negative or positive)
The rows are ordered from largest to smallest coordinate value along the axis of rotation. If a pause is selected, the program does not really care which character is chosen for the row and direction.
"But how many moves can I make within the time?" As many, or few, as you want.
Well... As long as you want 96 or less moves that is. The function alters the angular speed of the rotations to fit them all within the 96 frame window. But since we iterate through the cube (more on that later) we need to ensure that a move has completely finished before starting another move, or the cube will start looking like a contortionist.
If there is remaining time before the 96 frames are up (due to the timing of the angular speed), the cube politely pauses and waits for the last coule of frames to pass.
The hardest part is finding a sequence short enough to not look like the cube is flailing wildly during its 4 seconds of fame, but long enough to make some interesting pattern like the tetris shuffle in my original entry! Preferably while still being a perfect loop.
I would go on about good seamless loop mechanics, but Vasilis Bellos already made the great post "Creating seamless loop animations by zooming in" last week so I'll just sum it up to make sure to end right before the place you start.
Easy, right? Now go make your own!
Tip: Use the camera rotation to your advantage! Wanting to showcase all sides of the Mathworks cube for as long as possible, I needed a short movement sequence which gives lower angular speed. I cut out two moves from the sequence by making the camera rotate 180 degrees to finish my perfect loop at a different set of coordinates from where I started!
How did you make the cube so beautiful (MathWorks motive)?
A lot of credit should go to Tomoaki Takagi and his entry. I am a sucker for utilizing things for purposes they were not intended to be used for, and he did just that.
We are not allowed to upload images or data in the contest. But we are allowed to optionally upload some background audio for the video. The key is to realise that this audio is stored in the same place as the contest entry. Meaning we can access the "audio.wav" file we just uploaded to the contest.
An audio file is really just a long row of values between -1 and 1. So... if one were to take a picture of every side of a MathWorks cube laying around on the desk, splice the images into 54 seperate textures, scale the intensities between 0 and 1, reshape them to a row, and save it as an .wav file using the audiowrite() function... One would have a bit too much free time, but also a terrible sounding audio file with image data encoded.
There is one small problem however. As you might have noticed, the audio of most entries sound... rough. This is because of an file compression (or something of the like) applied to files over a certain length when you upload them to the contest. This also applies to audio files filled with image data that does not take particularly well to getting squeezed.
The solution? Compress it yourself (carefully)! Again I looked at Tomoaki's entry, to see what length worked for him. His entry contained a 150x150x3 image upscaled by a factor 4. His image is not exactly sharp, and with 54 different textures needed for a cube, each side would be... about 3x3x3. While a bit poetic, we can not bring such dishonour to such a beautiful object! Luckily Tomoaki had not used the entire audio file for image storage. And he used mono sound (1 audio channel) for his entry and .wav files support stereo sound (2 aoudio channels) meaning I could utilize twice as much space netting me a neat, decent resolution of 28x28 pixels per face!
Don't forget to overwrite the audio on the last frame using audiowrite() however! Most people don't appreciate the sound of images. You should explore Tomoaki's entry for more information on this. The entry is short and easy to understand.
Summary: The audio file uploaded can be used to store image data instead of sound data. Just be careful about file length and size as compression won't treat you kindly!
How did you build the cube?
Excellent question, my dear watsson. Surfaces. Lots and lots of surfaces. This part is takes the most computation time. If anyone has some forbidden knowledge I don't know about here, feel free to correct and enlighten me!
We want to be able to assign each face of the cube a seperate texture, and to be able to move each face seperately without it morphing itself or other parts of the cube. Because of this, they can't be part of a meshgrid connecting each other. Instead we have to construct each surface individually. This takes a second, but is much better in my latest version (See more in the I crave speed section). Which in my earlier entries was a big deal because I was yet to learn about our lord and saviour, persistent variables through Timothy's beautiful entry: Refraction.
One could think a rubix cube has 54 faces, 9 on each side, but alas that is but an illusion. A rubix cube is infact 27 (26 if not counting the center) smaller cubes in a trench coat. Each with 6 sides. (As illustrated by William Dean's entry Is this cheating? posted while I'm writing this, thanks for the assist!).
Patch objects are all good and well when creating faces if you only want colors, which is the case in my first submission. But MATLAB surface objects are also 3D and have a property that allows them to be textured which we use in the later versions.
Thinking about the trench coat covered cubes, we can tell that on a physical cube we have 6 planes in each coordinate direction. 2 for each row of cubes. The faces pointing outward are textured and the faces pointing inward are typically black. That is how we will model our cube as well.
The above image shows how the cube looks during the process of building each face. You may think to yourself "Why do you only have 4 planes in a direction? Do we really need all 6 that you mentioned?" Yes. and if you could enhance and zoom the image like the movies, you would see a tiny gap between the "2" black central planes (this is a surprise tool that will help us later!). The 6 planes are necessary to cover up the cube's hollow interior from multiple viewing angles so we can not compromise it down to 4. Imagine flippnig the cube in the first image of this section and looking into the cube. If we had 4 planes, we would be able to see through the cube from one of the angles.
Summary: We imagine the cube as 3x3x3 smaller cubes. We build each side, inwards pointing or not. We make each face of these smaller cubes seperately using surface() to avoid morphing behavior and to allow the surfaces to be textured individually.
How does it move?
The trick is all about coordinates. Firstly, to make the cube move we need a couple of things:
- Some indicator of how and what to move (a movement sequence, MS)
- The speed at which it should move
- A way to separate what verticies should and should not move
- An operation to transform the coordinates of said verticies so they move
- And of course we need to update the existing data and plot.
We are already familliar with the movement sequence from the first section, so I will spare you the repetition.
The speed of rotation is fairly simple, we have a number of moves defined in MS, and a number of frames to play with, 96. Simply find how many frames we can afford to allocate each move, and since each "rotation" of the cube is a quarter turn () we get . Pretty straight forward.
Now we need to know which verticies should and should not move. Here we use our surprise tool from the previous section! When building the cube, we add a slight offset separating the central planes. We can use this coordinate shift to separate the different planes from eachother. This would not be entierly possible if the central planes shared coordinates.
As an example, let's say the movement sequence dictates that we should rotate around x and we should choose the first row. Since the cube is centered around 0 and the planes have coordinates:
in all directions where δ is the small offset, we can easily seperate the first row by checking which faces have x coordinates higher than 0.5 in all 4 verticies. Simmilarly we check for 4 verticies in between ±0.5 for the 2nd row and values lower than -0.5 for the 3rd row. For rotating the entire cube, we can just select all faces. This works for all coordinate axis due to the symmetry that occurs when being centered around 0.
Now we need an operation to transform the coordinates of the verticies. We want to rotate some 3D coordinates around a specified coordinate axis. Sounds like the perfect job of a rotational matrix for me. This is why you stay in school kids.
In case someone has never heard of a rotation matrix before, on the assumption that anyone using Matrix Laboratory is probably familliar with matrix math and basic linear algebra I'll keep this short. Basically, there are some standard matrices that will rotate a point [x,y,z] arount the origin of an axis. such that
=
Where the subscripts r denotes the rotated coordinates and ax the axis to rotate around.
These matricies are as follows:
Where θ is the angle with which you rotate the point. In our case the Angular speed.
Now, I define my own rotation matrices. This is because of one of three reasons:
- MATLAB does not have rotation function which rotates a point around a specified axis (this would baffle me)
- I am blind and could not see the correct function in the documentation (plausible)
- I am illiterate and can not read the documentation (improbable)
So we have everything we need! We just update the coordinate data of the affected surface objects, slap down a drawnow command for good measure, and call it an iteration!
But I'd like to shine light on something that is both feature and flaw before we move on. 24 frames per second looks decent enough, but trained eyes can tell it is a bit choppy. Especially when things move fast. So we would like our movement as slow as possible. "Then why does the angular speed as defined above not always utilize all 96 frames to finish the movement sequence?" Because to a trained eye, what looks even more choppy is a rotation not finishing before another starts as the image shows below with a frame by frame on this effect.
By matching the angular speed to an integer number of frames (by using floor()) for each rotation, we will always complete the entire rotation before starting the next move.This is good because of the reason mentioned above (it looks better), but also because we will base the next rotation on the coordinates of the current position. So it also saves us having to do some extra math to get everything aligned and in position to select the correct faces every time we swap move.
Summary: We use a combination between clever choice of coordinates and some standard rotational matricies to shift the relevant verticies as dictated by the movement sequence by an angle. Being carefull to make each rotation precisely end on an integer number of frames so that the same method works next time.
I crave speed!
Well buckle up then bucko! Best part about programming is that the instant after you spend time making something, you learn something that trivialises it. Persistent variables were that for me this project. My 3rd remix is all about making it faster (in the works as we speak)! You know what they say; "Make it work, make it good, make it fast".
My biggest qualm about my earlier versions was the execution speeds. Every call of drawframe, I would have to rebuild all my surface object to make the cube and re-iterate all the movement of the cube up untill the current frame to ensure the rotations of all verticies, and thus faces, are correct.
Defining a variable as persistent allocates it's memory in a way that it is not removed between function calls. Perfect for being limited by 96 calls to the same function that does not accept iterative input.
Without persistent variables, we needed to remake the surfaces each call to drawframe. Worse still; since we dont know the positions of the surfaces in the previous frame, we also had to re-iterate all the movement of the cube. You may ask yourself "why could you not just calculate the surface position based on the frame, angular speed of rotation and previous moves?". While the position of each face is possible to anticipate effectively with a look up table (which would not fit in the character limit but could have been snuck in with the image data), the rotation of each face is a bit more complex to keep track of. Not an issue with plain colors, but a challange when using textured faces.
Using persistent variables as in my latest version solves theese two issues and makes the code run silky smooth compared to earlier. It now
- Removes the most time consuming part (creating surfaces) 95 out of 96 times, and
- Removes the need of re-iterating through all movement to catch up with all the rotations previously made.
It does however remove a neat function of the code; frame independency. The competition calls drawframe 96 times with the numbers 1:96, so frame independency it is not an issue as the previous frame is always the previous frame. However, if we now were to call the drawframe function with the values 1, 5 ,and 96, we would not recieve frame number 1, 5, and 96 of the animation as we would have before. Now there is an implicit need to call the function in with the frames in order.
An interesting thought that occured to me was; "If I can store the surface object in a variable, why could i not just copy it to another variable and edit it's properties instead of making a gazillion calls to surface()?" Well, turns out that is not possible because the surface object as stored in the workspace is really more of a pointer to the memory storing the object in the figure window rather than the value in the memory itself. If you copy surface_1 to surface_2 and change surface_2: you get the same change in surface_1.
Also, you might think;
"EWWW... I see nested for loops."
Yep. Is creating the coordinates for the surfaces vectorizable? Absolutely. Not even that hard either. Use combinations() with the possible x, y, and z coordinates and you got yourself the coordinates to every vertice of the cube. Use some fancy logic to determine which vertice goes where and vóila: all verticies neatly ordered ready to be made into surface objects. You could probably even use meshgrid() instead if that is more to your liking. The issue lies in the "made into surface objects" part. As stated, the repeated surface call is still needed to obtain seperate parts of memory to store the surface objects. You would still need as many loop iterations, though not nested. So I decided to leave the nested loops, as a treat, because it made it easier to determine the order and orientations of the textures when encoding them into the audio. After all, efficient coding is not only about the execution speed of the code, it is also about the writing speed of the coder. Or as textbook authors would say: "This is left as an excercise to the reader".
"Are all the inner planes necessary?"
Almost. We need 6 planes for the cube to not look hollow, but since the entire inside plane is black could we not just make it one big surface? No. Different part of the planes move with different rotations, and so can eventually end up as a part of another plane. To avoid morphing, they can not be connected. Also if the planes were solid, we would rotate into still standing planes when a row is angled (kind of like the black parts of the contorted cube earlier). However, we technically do not need the center of the 27 cubes in any scenario, and we could write some logic to not include those specific faces. This was not done for character limitation purposes. I figured that the slight tank in speed would be outweighed by the clean looks and the potential that you, the reader, could achieve when remixing this entry with those sweet sweet roughly 30 extra characters.
"Wait, are you looping... backwards?"
Yes! Looping backwards is a pretty neat trick. In this application it is mainly used to save characters, but runs in roughly the same time as a typical explicit preallocation would.
It works bacause we allocate the first loop value in the last variable element. It is the same principle as writing:
a(5) = 5
As you can see MATLAB will allocate memory for a 5 element vector despite us only specifying one element. So if we start from the back, MATLAB will do the front for us!
And here you can see how it holds up to not preallocating/typical allocation. Plus it gives the same result!
% No preallocation
tic
for i=1:1:10000
x(i) = i;
end
toc
% Typical Preallocation
tic
y=zeros(10000,1);
for i=1:1:10000
y(i) = i;
end
toc
% Backwards looping
tic
for i=10000:-1:1
z(i) = i;
end
toc
% And produces the same results!
all(z==x)
Summary: Persistent variables are really neat They keep their values between calls to functions. In terms of this contest they remove the need to re-iterate things, or for you to keep the state of the last frame without the need for rebuilding it every time.
Surface objects in the workspace are really just pointers to the surface objects in the figure window. This means that we unforttunately must call surface() for each face we want to create.
While initiating the surfaces, I use nested loops. Unnesting these loops is very doable with combination() and left as an excercise to the reader. You will still need the same total number of loop iterations to create all the surface objects, and the loops make texturing more convinient.
All 6 planes are necessary, but the central face of each "inside" plane is redundant and could be skipped at the cost of some additional logic.
Looping backwards is a cool trick to make MATLAB perform the preallocation of memory for you when iterating through a variable.
You get a cube, and you get a cube, and...
As earlier stated, in the "I crave speed!" section my 3 entries happen to follow the "Make it, make it good, make it fast" rule. But I did not just want to upload something that did not add more than just having cleaner code. There is a whole artistic and visual part to it all. So I thought to myself, why not use the speed? Now that the thing is running smooth, why not just run it twice? So i did just that. Except, simmilar results could be achived with much less grief if I just... Made the illusion that I ran it several times in parallel. I wanted to show of the improved speed with making more cubes, but... Why not just copy the cube? So I did that insead!
The figure window i really just an interactive image. using getframe()and frame2im() we can quickly turn whatever is shown in the current figure into an image stored in a workspace variable. From here we just need to display that same image multiple times in a sort of array. repmat() in combination with imshow() could have been used here (and would probably have been a bit more flexible in deciding how the cubes are displayed) but I opted for storing the image in a cell array of desired size and using montage() instead.
Most people being character limited in this competition keep everyting to a minimum including the figure windows. Yet I have two of those in my last entry despite only one being shown. As stated in the previous section, surface objects in the workspace is really more of a pointer to the object in the figure, so to keep all my surfaces in between runs I need the figure window containing my surface objects undisturbed. which is why I place the montage in a seperate figure. and display that at the end instead.
An interesting feature *cough* bug *cough* is the swapping between the figure windows that appear in the video generated. This is because of using return as various points in the code in order to skip computations if the move is a 'pause'. The code then does not reach the point where the figure is swaped and montage is made. I thought this to be visually interesting and is therefore dubbing this bug a feature and leaving it in!
Summary:
Multiple cubes were achived by taking the 'image' displayed by the plot window and creating a montage with several of them in a seperate figure window. The swapping between the single and multiple cube view is made by selecting the active figure window before the end of the drawframe call!
Bye for now!
I have yapped on for far too long. Hope you learned something, and thank you all for the kind words and positive response to my entry. This project has been a blast!
Hi everyone, I wrote several fancy functions that may help your coding experience, since they are in very early developing stage, I will be thankful if anyone could try them and give some feedbacks. Currently I have following:
- fstr: a Python f-string like expression
- printf: an easy to use fprintf function, accepts multiple arguments with seperator, end string control.
I will bring more functions or packages like logger when I am available.
The code is open sourced at GitHub with simple examples: https://github.com/bentrainer/MMGA
初カキコ…ども… 俺みたいな中年で深夜にMATLAB見てる腐れ野郎、 他に、いますかっていねーか、はは
今日のSNSの会話 あの流行りの曲かっこいい とか あの 服ほしい とか ま、それが普通ですわな
かたや俺は電子の砂漠でfor文無くして、呟くんすわ
it'a true wolrd.狂ってる?それ、誉め 言葉ね。
好きなtoolbox Signal Processing Toolbox
尊敬する人間 Answersの海外ニキ(学校の課題質問はNO)
なんつってる間に4時っすよ(笑) あ~あ、休日の辛いとこね、これ
-----------
ディスカッションに記事を書いたら謎の力によって消えたっぽいので、性懲りもなくだらだら書いていこうと思います。前書いた内容忘れたからテキトーに書きます。
救いたいんですよ、Centralを(倒置法)
いっぬはMATLAB Answersに育てられてキャリアを積んできたんですよ。暇な時間を見つけてはAnswersで回答して承認欲求を満たしてきたんです。わかんない質問に対しては別の人が回答したのを学び、応用してバッジもらったりしちゃったりしてね。
そんな思い出の大事な1ピースを担うMATLAB Centralが、いま、苦境に立たされている。僕はMATLAB Centralを救いたい。
最悪、救うことが出来なくともCentralと一緒に死にたい。Centralがコミュニティを閉じるのに合わせて、僕の人生の幕も閉じたい。MATLABメンヘラと呼ばれても構わない。MATLABメンヘラこそ、MATLABに対する愛の証なのだ。MATLABメンヘラと呼ばれても、僕は強く生きる。むしろ、誇りに思うだろう。
こうしてMATLABメンヘラへの思いの丈を精一杯綴った今、僕はこう思う。
MATLABメンヘラって何?
なぜ苦境に立っているのか?
生成AIである。Hernia Babyは激怒した。必ず、かの「もうこれでいいじゃん」の王を除かなければならぬと決意した。Hernia BabyにはAIの仕組みがわからぬ。Hernia Babyは、会社の犬畜生である。マネージャが笛を吹き、エナドリと遊んで暮して来た。けれどもネットmemeに対しては、人一倍に敏感であった。
風の噂によるとMATLAB Answersの質問数も微妙に減少傾向にあるそうな。
確かにTwitter(現X)でもAnswers botの呟き減ったような…。
ゆ、許せんぞ生成AI…!
MATLAB Centralは日本では流行ってない?
そもそもCentralって日本じゃあまりアクセスされてないんじゃなイカ?
だってどうやってここにたどり着けばいいかわかんねえもん!(暴言)
MATLABのHPにはないから一回コミュニティのプロファイル入って…
やっと表示される。気づかんって!
MATLAB Centralは無料で学べる宝物庫
とはいえ本当にオススメなんです。
どんなのがあるかさらっと紹介していきます。
ここは短い文章で問題を解くコードを書き上げるところ。
多様な分野を実践的に学ぶことができるし、何より他人のコードも見ることができる。
たまにそんなのありかよ~って回答もあるけどいい訓練になる。
ただ英語の問題見たらさ~ 悪い やっぱつれぇわ…
我らがアイドルmichioニキやJiro氏が新機能について紹介なんかもしてくれてる。
なんだかんだTwitter(現X)で紹介しちゃってるから、見るのさぼったり…ゲフンゲフン!
定期的に開催される。
プライズも貰えたりするし、何よりめっちゃ面白い作品を皆が書いてくる。
p=pi;
l = 5e3;
m = 0:l;
[u,v]=meshgrid(10*m/l*p,2*m/l*p);
c=cos(v/2);
s=sin(v);
e=1-exp(u/(6*p));
surf(2*e.*cos(u).*c.^2,-e*2.*sin(u).*c.^2,1-exp(u/(3.75*p))-s+exp(u/(5.5*p)).*s,'FaceColor','#a47a43','EdgeAlpha',0.02)
axis equal off
A=7.3;
zlim([-A 0])
view([-12 23])
set(gcf,'Color','#d2b071')
過去の事は水に流してくれないか?
toolboxにない自作関数とかを無料で皆が公開してるところ。
MATLABのアドオンからだと関数をそのままインストール出来たりする。
だいたいの答えはここにある。質問する前にググれば出てくる。
躓いて調べると過去に書いてあった自分の回答に助けられたりもする。
for文で回答すると一定数の海外ニキたちが
と絡んでくる。
Answersがバキバキ回答する場であるのに対して、ここでは好きなことを呟いていいらしい。最近できたっぽい。全然知らんかった。海外では「こんな機能欲しくね?」とかけっこう人気っぽい。
日本人が書いてないから僕がこんなクソスレ書いてるわけ┐(´д`)┌ヤレヤレ
まとめ
いかがだったでしょうか?このようにCentralは学びとして非常に有効な場所なのであります。インプットもいいけど是非アウトプットしてみましょう。コミュニティはアカウントさえ持ってたら無料でやれるんでね。
皆はどうやってMATLAB/Simulinkを学んだか、良ければ返信でクソレスしてくれると嬉しいです。特にSimulinkはマジでな~んにもわからん。MathWorksさんode45とかソルバーの説明ここでしてくれ。
後、ディスカッション一時保存機能つけてほしい。
最後に
Centralより先に、俺を救え
参考:ミスタードーナツを救え
I have one question.
Would it be possible to purchase Matlab for our company and incorporate the functions provided by this software into our in-house developed software to offer it to customers? Is this kind of action permitted under the license terms? I would appreciate advice from someone knowledgeable on this matter.
This year's MATLAB Shorts Mini Hack contest has kicked off, and there are already lots of interesting entries. The contest features creating a 96-frame, 4-second animation, which is looped 3 times to compose a 12-second short movie. There is an option to add audio to enhance the animation, and it's restricted to a an upper limit of 2,000 characters to promote efficient coding.
Many of the contestants have already realized the potential for creating a seamless loop, which provides a smooth transition and avoids any discontinuities when the animation is repeated. There are several ways to achieve this. An efficient method for example is utilizing sinusoidal functions, which are periodic, meaning that they repeat themselves over time:
An intuitive example of a seamless loop is @Edgar Guevara's EKG pulse entry, which features an electrocardiogram signal on an oscilloscope. The animation is perfectly matched by the audio, as explained in their post.
Another, rather sophisticated approach is featured in @Tim's Moonrun animation in last year's contest. This seamless loop is achieved by cleverly manipulating the camera position and target over a periodic spatial domain, producing this stunning result:
This essentially tells us that for a seamless loop in the spatial domain, the first frame must match the last frame (with a single timestep difference to be more precise, more on that later). But surely this cannot be achieved by zooming in, unless you are simulating a fractal. Well, there are always workarounds.
One way to achieve this is by zooming into a section that contains the first frame of the animation. This is featured in my Winter Loop entry. This is a remix of @Oliver Jaros's Winter entry, which was selected as a one of the weekly winners in the nature & space category for Week 1. The code was modified to lower the character count, but all credits for the original idea and graphics go to them. I also drew inspiration from one of my favourite games of all time, Super Mario 64. Oliver's animation reminded me of the Cool, Cool Mountain level of the game. In the game, you can enter various levels by jumping into paintings serving as portals.
This inspired the idea of zooming into a rectangular photograph frame containing the first frame of the animation to facilitate restarting the loop. One could argue that it would probably take a crazy person to have a photo of their house framed inside their own house. Well, in this economy and with the current house prices, I don't think this scenario is too far-fetched:
The implementation for this in 2-D is rather simple. Essentially, a second axes is used as the photograph. This is an efficient way of neatly updating the graphics while zooming in. The way this was implemented is explained in the following code snippet, which is a slight modification of the code in the entry:
m = 96; % Number of frames
% Axes limits for the first frame
xm = [xm1,xm2];
ym = [ym1,ym2];
% Axes limits for the last frame (photograph frame edges)
xf = [xf1,xf2];
yf = [yf1,yf2];
% Zoom-in vectors
x1 = linspace(xm(1),xf(1),m+1); % Axes left edge to left photo frame edge
x2 = linspace(xm(2),xf(2),m+1); % Axes right edge to right photo frame edge
y1 = linspace(ym(1),yf(1),m+1); % Axes bottom edge to bottom photo frame edge
y2 = linspace(ym(2),yf(2),m+1); % Axes top edge to top photo frame edge
if f==1
axis([x1(f),x2(f),y1(f),y2(f)]); % Set main axes limits
ax2 = copyobj(gca,gcf); % Create axes for the photo frame containing the first frame graphics objects
end
axis([x1(f+1),x2(f+1),y1(f+1),y2(f+1)]); % Zoom in main axes
lims = axis; % Main axes updated limits
pos = get(gca,'Position'); % Main axes position
% This keeps the relative position of the 2 axes constant:
pos = [pos(1)+diff([lims(1),xf(1)])/diff(lims(1:2))*pos(3),...
pos(2)+diff([lims(3),yf(1)])/diff(lims(3:4))*pos(4),...
diff(xf)/diff(lims(1:2))*pos(3),...
diff(yf)/diff(lims(3:4))*pos(4)];
ax2.Position = pos; % Adjust the relative position
Let's break down the code to explain the process:
- m is the total number of frames in the animation, i.e. 96 frames.
- xm & ym are the main axes limits for frame 1.
- xf & yf are the main axes limits for frame 96, corresponding to the photograph frame's edges.
- x1, x2, y1 & y2 are the zoom-in vectors, linearly spaced from the left, right, bottom & top main axes edges to the corresponding photograph edges. You have probably noticed that these contain m+1=97 points, which is 1 more than the total number of frames. This is done so that the first frame of the animation and the contents of the photograph frame are offset by a single timestep, so that there are no overlapping frames when the animation is looped, thus creating a perfect, seamless loop. That means that the first frame of the animation will contain the main axes zoomed-in by a single timestep, while the last frame of the animation (i.e. the zoomed-in photograph frame) will contain the most zoomed-out version of the graphics. This neatly wraps the animation, and displays the full zoomed-out view when the video stops playing.
- The photograph frame axes are created when f==1 (after setting the initial axes limits) by using the immensely useful copyobj function. This one-liner creates axes containing all graphics objects for the first frame.
- Zooming in on the main axes is then achieved by adjusting the limits using axis([x1(f+1),x2(f+1),y1(f+1),y2(f+1)]). The main axes current limits and position are then saved using the variables lims and pos respectively, in order to adjust the position of the photograph frame axes.
- While zooming in, it's important that the relative position of the 2 axes is kept constant. This is achieved by simply adjusting the position of the photograph frame axes at every frame, by calculating their relative ratios using the abovementioned formula. The first 2 arguments correspond to the (normalized) x and y positions of the lower left corner of the axes, while the third and fourth arguments correspond to the (normalized) width and height respectively. While this formula will work for any position of the main axes, it's a good idea to set the position as set(gca,'Position',[0 0 1 1]) for this contest, in order to take full advantage of the whole allocated window for the animation.
- Finally, note that the graphics are updated for the main axes only, and the above process is repeated for each frame until fully zooming into the photograph frame's axes.
Some of the most curious minds might wonder that while this is well and all with using the second axes to simulate the photograph, what happens to the photograph inside the photograph (and so on...)? Well, the beauty of this method is that you can repeat this as many times as necessary (just apply the formula using the current position and limits of the second axes to adjust the position of the third axes and so on). Given the speed of the animation and the very small size of the photograph inside the photograph, it would be very unlikely that you would need more than 3 axes, but the process is always good to know.
This is the final result:
I hope you found these tips useful and I'm looking forward to seeing many creative seamless loop animations in the contest.
Inspired by the suggestion of Mr. Chen Lin (MathWorks), I am writing this post with a humble and friendly intent to share some fascinating insights and knowledge about the Schwarzschild radius. My entry, which is related to this post, is named: 'Into the Abyss - Schwarzschild Radius (a time lapse)'.
The Schwarzschild radius (or gravitational radius) defines the radius of the event horizon of a black hole, which is the boundary beyond which nothing, not even light, can escape the gravitational pull of the black hole. This concept comes from the Schwarzschild solution to Einstein’s field equations in general relativity. Black holes are regions of spacetime where gravitational collapse has caused matter to be concentrated within such a small volume that the escape velocity exceeds the speed of light.
This is a rudimentary scientific post, as the matter of Schwarzschild radius - it's true meaning and function, is a much, much, much-more complex "thing" (not known to us entierly, by the third degre of epistemological explanation(s)).
And, very important is to mention: I am NOT an expert - by any means, on this topic, just a very curious guy, in almost anything, that has to do with science.
Schwarzschild Radius (Gravitational Radius)
The Schwarzschild radius (Rₛ) is the critical radius at which an object of mass must be compressed to form a black hole, specifically, a non-rotating, uncharged black hole, known as a Schwarzschild black hole. The Schwarzschild radius is given by the formula: .
Where: .
Key Characteristics are, that for any mass, if that mass is compressed within a sphere with radius equal to , the gravitational field is so strong that not even light can escape, thus forming a black hole. The Schwarzschild radius is proportional to the mass. Larger masses have larger Schwarzschild radii.
Example:
For the Sun : .
So, if the Sun were compressed into a sphere with a radius of ~3 km, it would become a black hole!
Stellar-mass Black Holes form from the collapse of massive stars (roughly ). Their Schwarzschild radius ranges from a few kilometers to tens of kilometers.
Supermassive Black Holes found at the centers of galaxies, such as Sagittarius A in the Milky Way (), their Schwarzschild radii span from a few million to billions of kilometers!
Primordial or Micro Black Holes, are the hypothetical small black holes with masses much smaller than stellar masses, where the Schwarzschild radius could be extremely tiny.
A black hole, in general, is a solution to Einstein’s general theory of relativity where spacetime is curved to such an extent that nothing within a certain region, called the event horizon, can escape.
Types of Black Holes:
1. Schwarzschild (Non-rotating, Uncharged):
- This is the simplest type of black hole, described by the Schwarzschild solution.
- Its key feature is the singularity at the center, where the curvature of spacetime becomes infinite.
- No charge, no angular momentum (spin), and spherical symmetry.
2. Kerr (Rotating):
- Describes rotating black holes.
- Involves an additional parameter called angular momentum.
- Has an event horizon and an inner boundary, known as the ergosphere, where spacetime is dragged around by the black hole's rotation.
3. Reissner–Nordström (Charged, Non-rotating):
- A black hole with electric charge.
- A charged black hole has two event horizons (inner and outer) and a central singularity.
4. Kerr–Newman (Rotating and Charged):
- The most general solution, describing a black hole that has both charge and angular momentum.
Relationship Between Schwarzschild Radius and Black Holes
Formation of Black Holes: When a massive star exhausts its nuclear fuel, gravitational collapse can compress the core beyond the Schwarzschild radius, creating a black hole.
Event Horizon: The Schwarzschild radius marks the event horizon for a non-rotating black hole. This is the boundary beyond which no information or matter can escape the black hole.
Curvature of Spacetime: At distances closer than the Schwarzschild radius, spacetime curvature becomes so extreme that all paths, even those of light, are bent towards the black hole’s singularity.
BTW, the term singularity, scientificaly 😊, means that: we do not have a clue what is really happening right there...
Detailed Properties of Black Holes:
a. Singularity:
At the center of a black hole, within the Schwarzschild radius, lies the singularity, a point (or ring in the case of rotating black holes) where gravitational forces compress matter to infinite density and spacetime curvature becomes infinite. General relativity breaks down at the singularity, and a quantum theory of gravity is required for a complete understanding.
b. Event Horizon:
The event horizon is not a physical surface but a boundary where the escape velocity equals the speed of light. For an outside observer, objects falling into a black hole appear to slow down and fade away near the event horizon due to gravitational time dilation, a prediction of general relativity. From the perspective of the infalling object, however, it crosses the event horizon in finite time without noticing anything special at the moment of crossing.
c. Hawking Radiation: (In the post, I told that there is no radiation - to make it simple, although, there is a relatively newly-found (theoretically) radiation. Truth to be said, some physicists are still chalenging this notion, in some of it's parts...)
Quantum mechanical effects near the event horizon predict that black holes can emit radiation (Hawking radiation), a process through which black holes can lose mass and, over very long timescales, potentially evaporate completely. This process has a temperature inversely proportional to the black hole's mass, making large black holes emit extremely weak radiation. (Very trivialy speaking: the concept supposes that an anti-particle is drawn from the vakum and is anihilated with the black's hole matter (particle), and in the process, the black hole looses mass gradually and proportionally to the released energy - very slowly(!)).
This radiation is significant only for small black holes.
Gravitational Time Dilation (here, as well, things become 'super-weird'...)
Near the Schwarzschild radius, the intense gravitational field leads to time dilation. For an external observer far from the black hole, time appears to slow down for an object moving toward the event horizon. As it approaches the Schwarzschild radius, time dilation becomes so extreme that the object appears frozen in time at the horizon.
The time dilation factor is given by:
Eg. Approaching the Schwarzschild radius and theoretically remaining just outside of it for a few hours would correspond to the passage of approximately several decades on Earth due to relativistic time dilation.
Using relativistic equations, it's estimated that near the event horizon 2 hours (120 minutes) near the black hole Sagittarius A* (as already mentioned ~ 4 million ) - in the center of our galaxy Milky Way, could correspond to 83 years passing on Earth! However, this varies based on the precise distance from the event horizon (give or take, a decade 😬).
Information Paradox (definte answer on this question, 'hold's the keys of the universe' 😊, maybe...)
The black hole information paradox arises from the seeming contradiction between general relativity and quantum mechanics.
According to quantum mechanics, information cannot be destroyed, yet anything falling into a black hole seems to be lost beyond the event horizon. Hawking radiation, which allows a black hole to evaporate, does not appear to carry information about the matter that fell into the black hole, leading to ongoing debates and research into how information is preserved in the context of black holes, or not...!
Schwarzschild Radius is the key parameter defining the size of the event horizon of a non-rotating black hole. Black Holes are regions where the Schwarzschild radius constrains all physical phenomena due to extreme gravitational forces, forming event horizons and singularities. The interaction between general relativity and quantum mechanics in the context of black holes (e.g., Hawking radiation and the information paradox) remains one of the most intriguing areas in modern theoretical physics.
For detailed and further reading: https://www.sciencedirect.com/topics/physics-and-astronomy/hawking-radiation.
I hope you will find this post, and information provided, interesting.
Let's say you have a chance to ask the MATLAB leadership team any question. What would you ask them?
MAThematical LABor
6%
MAth Theory Linear AlgeBra
6%
MATrix LABoratory
88%
MATthew LAst Breakthrough
0%
17 votes
Here presented MATLAB code is designed to create a seamless loop animation that visualizes an isosurface derived from random data.
This entry, titled "The Scrambled Predator's Cube", builds upon my previous work and has been adapted to include dynamic elements.
In this explanation, I will break down the relatively short code, making it accessible whether you are a beginner in MATLAB or an experienced user. Let's go through the MATLAB code step by step to understand each line in detail.
Code Breakdown
d = rand(8,8,8);
Random Data Generation: This line creates a three-dimensional array d with dimensions 8×8×8 filled with random values. The rand function generates values uniformly distributed in the interval (0,1). This array serves as the input data for generating the isosurface.
iv = .5 + (f / 10000);
Isovalue Calculation: Here, the isovalue iv is computed based on the frame number f. The expression f / 10000 causes iv to increase very slowly as f increments. Starting from 0.50, this means that for every increment of f, iv changes slightly (specifically, by 0.0001). This gradual increase creates a smooth transition effect in the isosurface over time, making it look dynamic as the animation progresses.
h = patch(isosurface(d, iv), 'FaceColor', 'blue', 'EdgeColor', 'none');
Isosurface Creation: The isosurface function extracts a 3D surface from the data array d at the specified isovalue iv. The result is a patch object h that represents the isosurface in the 3D plot. The 'FaceColor', 'blue' argument sets the face color of the surface to blue, while 'EdgeColor', 'none' specifies that no edges should be drawn, giving the surface a solid appearance.
isonormals(d, h);
Surface Normals Calculation: This function calculates the normals at each vertex of the isosurface h, based on the data in d. Normals are vectors perpendicular to the surface at each point and are crucial for proper lighting calculations. By using isonormals, the appearance of depth and texture is enhanced, allowing the lighting to interact more realistically with the surface.
patch(isocaps(d, iv), 'FaceColor', 'interp', 'EdgeColor', 'none');
Isocaps Visualization: The isocaps function creates flat surfaces (caps) at the boundaries of the isosurface where the data values meet the isovalue iv. The resulting caps are then rendered as patches with 'FaceColor', 'interp', meaning the colors of the caps are interpolated based on the data values. The caps provide a more complete visual representation of the isosurface, improving its overall appearance.
colormap hsv;
Color Map Setup: This line sets the colormap of the current figure to HSV (Hue, Saturation, Value). The HSV colormap allows for a wide range of colors, which can enhance the visual appeal of the rendering by mapping different values in the data to different colors.
daspect([1, 1, 1]);
Aspect Ratio Setting: The daspect function sets the data aspect ratio of the plot to be equal in all three dimensions. This means that one unit in the x-direction is the same length as one unit in the y-direction and z-direction, ensuring that the visual representation of the 3D data is not distorted.
axis tight;
Tight Axis Setting: This command adjusts the limits of the axes so that they fit tightly around the data, removing any excess white space. It helps to focus the viewer's attention on the isosurface and related visual elements.
view(3);
3D View Configuration: The view(3) command sets the current view to a 3D perspective, allowing the viewer to see the structure of the isosurface from an angle that reveals its three-dimensional nature.
camlight right;
camlight left;
Lighting Effects: These commands add two light sources to the scene, positioned to the right and left of the view. The additional lighting enhances the shading and depth perception of the isosurface, making it appear more three-dimensional and visually appealing.
axis off;
Hide Axes: This command turns off the display of the axes in the plot. Removing the axes provides a cleaner visual representation, allowing the viewer to focus solely on the isosurface and its lighting effects without distraction from the grid lines or axis labels.
lighting phong;
Lighting Model: This line sets the lighting model to Phong. The Phong model is widely used in computer graphics as it provides smooth shading and realistic reflections. It calculates how light interacts with surfaces, enhancing the overall appearance by creating a more natural look.
This code creates a visually dynamic and appealing representation of an isosurface derived from random data. The gradual change in the isovalue allows for smooth transitions, while the combination of lighting, colors, and shading contributes to a rich 3D visualization. Each component plays a vital role in rendering the final output, showcasing advanced techniques in data visualization using MATLAB.
If you like them, please feel free to use them for free.
I'd like to share some tips about the 2024 mini hack contest, specifically related to audio:
- First (and most important), credit your source: unless you are composing your own audio, I think it's important to give credit to the original sources. It is a little sad to see several contributions with an empty line:
'Cite your audio source here (if applicable):'
- A great place to get royalty-free and high-quality music and audio (among other media) is https://pixabay.com. Be sure to check it out! I used one of their audio clips in my submission EKG pulse
- The right music can enhance the overall experience of your animation. Sometimes getting the animation to match the music beat can be hard. I suggest you try the other way around: get your music/sound effects to match the animation rhythm with a little editing. A free audio editor with many capabilities (more than enough for this contest, I think) is https://www.audacityteam.org/
- Choose a 4-second audio clip with a consistent tempo and seamless loop points, ensuring it complements your animation's mood and loops smoothly over 12 seconds without abrupt changes.
I think that when the right music is paired with the right animation, it can create a more impactful experience.
Well, this is my first time to participate in such community competitions and guess what, I've gone for 4 submissions so far (Feels Great!!)
So I wanna share some tricks that I followed for my first submission named Happy Shaping' ( Go Check it out!!):
1. Dynamic Background Color Change:
- Technique: The background color of the figure window is gradually changed using sine and cosine functions.
- Reason: These trigonometric functions (sin and cos) create smooth, oscillating transitions over time, which gives a fluid effect to the background's color shift.
- Implementation:
Color = [0.1 + 0.5*abs(sin(f/10)), 0.1 + 0.5*abs(cos(f/15)), 0.9 -
0.5*abs(sin(f/20))];
- Benefit: This introduces a smooth, visually appealing animation effect.
2. Smooth Object Motion Using Sine and Cosine:
- Technique: The position and shape of objects are based on trigonometric functions.
- Reason: Using sin(t) and cos(t) ensures that the movement is circular or elliptical, creating continuous and natural motion in animations.
- Implementation (for object position):
x = 10 * cos(t * 2 * pi) * (1 + 0.5 * sin(t * pi));
y = 10 * sin(t * 2 * pi) * (1 + 0.5 * cos(t * pi));
- Benefit: Circular and smooth motions are pleasing and easily controlled by tweaking the frequency and phase of sine/cosine functions.
3. Polygon Shape Changing Over Time:
- Technique: The number of sides of the polygon (sides) changes dynamically based on t.
- Reason: It creates variation in shape, maintaining user interest as the shape transitions from a triangle to a hexagon.
- Implementation:
sides = 3 + round(3 * abs(sin(t)));
- Benefit: This provides dynamic shape transitions over time, keeping the animation non-static.
4. Use of the fill Function for Color-Filled Shapes:
- Technique: The fill function is used to draw a polygon with smoothly changing colors.
- Reason: Filling polygons with varying colors based on time (t) allows for continuous color transitions, adding more complexity to the animation.
- Implementation:
fill(xp, yp, c, 'EdgeColor', 'none');
- Benefit: Combining both color changes and shape changes enhances the visual impact.
5. Consistent Use of hold on and hold off:
- Technique: hold on allows multiple graphic objects to be drawn on the same axes without clearing previous objects.
- Reason: This is crucial for drawing multiple elements (like polygons, circles, and lines) on the same figure.
- Benefit: It helps manage and layer different graphical elements effectively within the same frame.
6. Use of rectangle for a Smooth Ball Motion:
- Technique: The ball's motion is defined by rectangle with a Curvature of [1, 1] to make it circular.
- Reason: Using the rectangle function simplifies the process of drawing a filled circle, and controlling its position and size is intuitive.
- Benefit: It provides a straightforward way to animate circular objects within the plot.
7. Animating the Connection Line:
- Technique: A white dashed line (w--) is drawn between the polygon and the moving ball to show a connection between these objects.
- Reason: This adds interactivity to the scene, as it gives the impression that the polygon and the ball are related or connected in some way.
- Implementation:
plot([x bx], [y by], 'w--', 'LineWidth', 2);
- Benefit: A dynamic element that adds depth and narrative to the animation, guiding the viewer’s attention.
8. Frame Synchronization with Time (f and t):
- Technique: The variable f is used as a frame number, while t = f / 24 creates a link between frame and time.
- Reason: Ensuring smooth and continuous transitions in the animation over time is critical, so f acts as the control for time-based changes in shape, color, and position.
- Benefit: This makes it easy to manage frame rates and time-based updates for the animation.
Try to install MATLAB2024a on Ubuntu24.04. In the image below, the button indicated by the green arrow is clickable, while the button indicated by the red arrow are unclickable, and input field where text cannot be entered, preventing the installation.
syms u v
atan2alt(v,u)
function Z = atan2alt(V,U)
% extension of atan2(V,U) into the complex plane
Z = -1i*log((U+1i*V)./sqrt(U.^2+V.^2));
% check for purely real input. if so, zero out the imaginary part.
realInputs = (imag(U) == 0) & (imag(V) == 0);
Z(realInputs) = real(Z(realInputs));
end
As I am editing this post, I see the expected symbolic display in the nice form as have grown to love. However, when I save the post, it does not display. (In fact, it shows up here in the discussions post.) This seems to be a new problem, as I have not seen that failure mode in the past.
You can see the problem in this Answer forum response of mine, where it did fail.
After reading Rik's comment I looked for a list of Matlab releases and their corresponding features. Wiki: Matlab contains an exhaustive list, but what about having a lean version directly in the forum?
If this is useful, feel free to expand the list and to insert additions. Thank you.
What is the side-effect of counting the number of Deep Learning Toolbox™ updates in the last 5 years? The industry has slowly stabilised and matured, so updates have slowed down in the last 1 year, and there has been no exponential growth.Is it correct to assume that? Let's see what you think!
releaseNumNames = "R"+string(2019:2024)+["a";"b"];
releaseNumNames = releaseNumNames(:);
numReleaseNotes = [10,14,27,39,38,43,53,52,55,57,46,46];
exampleNums = [nan,nan,nan,nan,nan,nan,40,24,22,31,24,38];
bar(releaseNumNames,[numReleaseNotes;exampleNums]')
legend(["#release notes","#new/update examples"],Location="northwest")
title("Number of Deep Learning Toolbox™ update items in the last 5 years")
ylabel("#release notes")