נכתב ע"י: רוני פאר ronip@systematics.co.il תאריך עדכון אחרון: 7.12.2010 מעודכן לגרסה: MATLAB 7.11 - R2010b קווים מנחים ליצירת קוד Cמתוך MATLAB קווים מנחים ליצירת קוד Cמתוך MATLAB הקדמה השימוש בתוכנת MATLABהרגיל את משתמשיה לעבוד בצורה חופשית -ללא דאגה להקצאות זיכרון ,ללא חשש להגדרת סוגי המשתנים ,והנאה רבה מהיכולת לביצוע פעולות על מטריצות בצורה פשוטה וקלה .עקב כך ,אלגוריתמאים ומתכננים מתחומי תעשייה שונים עושים שימוש רב ומתקדם בתוכנה זו. תיכנות בשפת ,Cמאידך ,הוא אופטימלי לתכנון מערכות זמן-אמת מבחינת ביצועים ,ניצול הזיכרון ועוצמת החישוב .קוד זה יכול לכלול גם שימוש ב ,Fixed Point-ומהנדסי חומרה ותוכנה עובדים שעות רבות על ניצול מקסימלי של רכיבים אלו ,בכדי להפיק מהם את המירב ולהשיג יתרון של ממש על פני המתחרים. כתוצאה מכך ,אחד מאתגרי הפיתוח הנפוצים בתעשיה הוא כיצד לבצע המרה מהירה ,יעילה ואוטומטית במידת האפשר -של תוכנית שנכתבה בסביבה החופשית של ,MATLABלסביבה בעלת האילוצים הקשים וצורת התכנות של שפת .C מטרת מסמך זה הינה להציג את אחד הפתרונות לאתגר זה :שימוש בפרדיגמת הEmbedded- ) MATLABאו (EML :ויצירת קוד Cבאמצעות .Real-Time Workshopע"י שימוש בדוגמא של פונקציה הכתובה ב ,MATLAB-מוסבר הליך המרת הקוד כך שיכיל עקרונות תכנות של שפת :Cהגדרות טיפוסי משתנים – לרבות ,Fixed Pointהקצאות זיכרון וביצוע אופטימיזציה לניצול זיכרון הרכיב וייעול הקוד עצמו .כמו כן ,משולבים ידע ופרקטיקות שנאספו מתחומי תעשייה רבים מרחבי העולם ומקנים לקורא תהליכים מומלצים לביצוע המרה אוטומטית של קוד MATLABל.C- יש לציין כי גם במודלים של Simulinkניתן לשלב פונקציות של .EMLבצורה שכזו ניתן לבנות סביבת בדיקות קלה ונוחה יותר ,או לשלב קוד EMLבתוך מודלים מערכתיים גדולים יותר שנבנו בעזרת .Simulink מסמך זה מסתמך בחלקו הגדול על מסמכי ה help-המסופקים עם תוכנת ,MATLABובא לתת מראי מקום חשובים מתוכם – מומלץ לקרוא מסמכים אלו. עמוד 2מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB תוכן העניינים .1 הגדרות כלליות 5...................................................................................................... 5.............................................................................................................. MATLAB .1.1 Embedded MATLAB .1.2או 5........................................................................... EML 5....................................................................................................................... RTW .1.3 6................................................................................................................ RTW-EC .1.4 6....................................................................................................................... MEX .1.5 .2 אבני דרך מרכזיות 7.................................................................................................. .2.1כתיבת קוד MATLABובדיקה התנהגותית של האלגוריתם7........................................... .2.2בדיקה האם הקוד שנכתב תואם ל7.......................................................................EML- .2.3התאמת הקוד למערכות זמן-אמת 8................................................................................. .2.4יצירת פונקציית MEXלצורך בדיקה פונקציונלית של הקוד 8............................................ .2.5יצירת קוד 9................................................................................................................... .3 בדיקה האם הקוד שנכתב תואם ל10 ............................................................... EML- .3.1טיפול והסרה של כל ה"הערות" שנתגלו ע"י שימוש ב10 ........................................ m-lint- .3.2שימוש בפרגמה 11 ............................................................................................ %#eml .4 התאמת הקוד למערכות זמן-אמת 14 .......................................................................... " .4.1טיפול" בפונקציות של MATLABבאמצעות 14 .................................... eml.extrinsic 4.2הגדרת טיפוסי משתנים 15 ............................................................................................... .4.3הגדרת פרמטרים בעלי גודל משתנה )16 .................................................. (Variable Size .4.4עבודה עם פרמטרים מסוג 18 ............................................................................... struct .4.5עבודה עם מטריצות "ריקות" 19 ...................................................................................... .4.6הגדרת משתנים בצורה מותנית 19 ................................................................................... .4.7הקצאת זיכרון מינימלית באמצעות 20 ..................................................... eml.nullcopy .4.8אינדקסים של וקטורים בעלי גודל משתנה 20 .................................................................... .4.9תמיכה במשתנים גלובליים 21 ........................................................................... global - .4.10שימוש ב21 ............................................................................................. streaming- .4.11בדיקה פונקציונלית 22 .................................................................................................. .5 יצירת פונקציית MEXלצורך בדיקה פונקציונלית של הקוד 24 ..................................... .5.1יצירת פונקציית 25 .............................................................................................. MEX .5.2בדיקה למול קוד המקור 26 ............................................................................................. .5.3בדיקת זמני ריצה של קוד ה MEX-והשוואה למקור 26 ..................................................... .6 יצירת קוד 27 ........................................................................................................... .6.1תוצרים שונים מהפקודה 27 ................................................................................... emlc .6.2התאמה אישית של הקוד הנוצר )דגלון 28 ................................................................... (–s עמוד 3מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .6.3שימוש בדו"ח יצירת הקוד 32 .......................................................................................... סיכום 33 ................................................................................................................. .7 עמוד 4מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .1הגדרות כלליות במסמך זה נעשה שימוש במספר ביטויים מעולם התוכן של משתמשי .MATLABמטרת חלק זה היא להבהיר מושגים אלו ,וליצור שפה משותפת אחידה: MATLAB .1.1 ה"סטנדרט" בתעשייה -התוכנה מבית היוצר של חברת ™ MathWorksאשר מאפשרת לבצע חישובים נומריים ,לנתח מידע ולהציגו בצורה גרפית ,לפתח ולבדוק אלגוריתמים סבוכים ופשוטים כאחד ,והבסיס לכל המוצרים הנלווים של - MathWorksהמוסיפים יכולות מתקדמות בתחום עיבוד התמונה ,עיבוד האות ,תכנון מערכות בקרה ,ועוד. MATLABהינה שפה עילית ,המאפשרת לבנות אלגוריתמים מורכבים ללא צורך לדאגה להקצאת זיכרון ,להגדרות משתנים ופעולות נוספות הנדרשות בשפות תכנות נמוכות יותר. Embedded MATLAB .1.2או EML כאשר אנו מעוניינים לעבור מעולם הפיתוח ב MATLAB®-למערכות זמן-אמת ,אנו צריכים לכתוב בפונקציות המתאימות למערכות אלו .אוסף הפונקציות הזה ,הנגזר מתוך MATLABעצמה – נקרא .Embedded MATLABהאיור הבא מדגים את עולם ה- ,Embeddedבהשוואה למקור. כפי שניתן לראות ,הפעולות שאינן נתמכות מחולקות ל 2-סוגים – ויזואליזציה והקצאת זיכרון דינמית .עם זאת ,חשוב לזכור שבמערכות זמן-אמת אמיתיות ,אין שימוש של ממש בפעולות אלו ,ולכן אין כאן פגיעה ברמת העבודה. RTW .1.3 על מנת לייצר קוד Cמתוך ,MATLABיש להתקין כלי נוסף ,הנקרא Real-Time ,Workshopאו בקיצור .RTWכלי זה מאפשר לייצר קוד Cגנרי ,שניתן להפעילו על כל מערכות המחשוב הקיימות כיום ) Linux ,MAC ,PCוכדומה( .הקוד הנוצר מיועד למערכות אלו ,שבעיקרן אינן מוגבלות מבחינת משאבים )למשל -תמיד ניתן להוסיף עוד זיכרון או לעבור ל 64-ביט( ,ועל כן הוא יעיל בצורה הולמת. עמוד 5מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB RTW-EC .1.4 למערכות זמן-אמת המוגבלות במשאבים )זיכרון ,זמני ריצה( קיים כלי נוסף ,אשר נקרא ,Real-Time Workshop – Embedded Coderאו בקצרה .RTW-ECכלי זה מאפשר לייצר קוד Cהמותאם למעבדים ספציפיים )אינטל ,מוטורולה ,מיקרוצ'יפAnalog ,TI , Devicesוכדומה( .הקוד שנוצר הוא יעיל ביותר ,ניתן לשלוט על מראהו ועל אופן השמתו במרחב הזיכרון של הרכיב ,ועוד. MEX .1.5 פונקציות ) MEXאו (MATLAB Executablesהן למעשה פונקציות שנכתבו בשפה השונה מ ,MATLAB-ושולבו בתוך .MATLABניתן לייבא קוד Cקיים ,קוד Fortranואפילו קוד .ADAהשימוש בפונקציות אלו זהה לשימוש בפונקציות ,MATLABוהן מאפשרות למשתמשי ה MATLAB-לנצל קוד קיים במקום לכותבו שוב. עמוד 6מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .2אבני דרך מרכזיות תהליך יצירת הקוד והמרת קוד ה MATLAB-לקוד Cמושתת על מספר שלבים מרכזיים ,אשר אופייניים גם לשלבי הפיתוח המקובלים בתעשיה .בפרק זה יפורטו השלבים המרכזיים ו הפעולות המרכזיות המבוצעות בשלבים אלו .בהמשך יפורטו שלבים אלו בצורה מעמיקה ורחבה יותר, וישולבו דוגמאות הלכה למעשה. להלן הסכימה הכללית של התהליך: .2.1כתיבת קוד MATLABובדיקה התנהגותית של האלגוריתם בשלב הראשון ,נכתב האלגוריתם הטהור ע"י המתכנן או האלגוריתמאי .אלגוריתם זה יכול לכלול פעולות הנוגעות לתחום עיבוד תמונה/וידאו ,עיבוד אותות ,מערכות בקרה ועוד, ויתכן כי המתכנן נעזר בפונקציות עזר מתוך ספריות המסופקות עם MATLABאו עם כלי ההרחבה הנשענים עליה. ברוב המקרים יבנה המתכנן סביבת בדיקות לאלגוריתם שלו ,באמצעותה יבדוק פרמטרים שונים ואליה יכניס כניסות שונות ויבחן את תוצאות האלגוריתם באמצעים ויזואליים )גרפים ,סקופים וכדומה( ,יקרא או יכתוב מידע מסביבת העבודה או מקבצים ,ויבצע השוואות לתיאוריה שאותה בחן. בסוף הליך זה נמצא בידי המתכנן קוד הכתוב בשפת MATLABאשר מממש את האלגוריתם בצורה המדוייקת ביותר .נהוג לקרוא לאלגוריתם זה ""Golden Reference או "אמת הסמך להשוואה" .בכל אחד מהשלבים הבאים ,נרצה לבחון את השינויים שנעשו למול המקור ,ולוודא כי פונקציית ה MATLAB-עדיין תואמת בפעולתה לGolden - .Reference חלק זה לא יפורט בהמשך ,ומסתמך על כך שהקורא מכיר את התכנות בMATLAB- ברמה בסיסית. .2.2בדיקה האם הקוד שנכתב תואם לEML- כפי שהוזכר קודם ,בכדי לייצר קוד Cמתוך ,MATLABראשית עלינו לוודא כי צורת הכתיבה שלנו ,והפונקציות שבהן השתמשנו נתמכות ל .EML-קיימות כ 300-פונקציות MATLABהנתמכות ל ,EML-עוד כ 100-פונקציות נוספות הקשורות ל Fixed Point-ועוד עמוד 7מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB כ 40-פונקציות הקשורות לכלי ה .Signal Processing-רשימת הפונקציות המלאה ניתן למצוא בקישור הבא )או ב help-של ,MATLABתחת :(Embedded MATLAB http://www.mathworks.com/access/helpdesk/help/toolbox/eml/ug/bq1h2z7-9.html הערה :יש לציין כי בגרסה R2010aפיתחה חברת MathWorksאת השימוש בSystem - ,Objectsאשר מרחיבים פונקציות אלו וכוללים פונקציות רבות מתחום עיבוד התמונה, עיבוד האות )והחל מ R2010b-התקשורת( – אשר עד כה נתמכו ליצירת קוד רק מתוך .Simulink כאמור ,על מנת לייצר קוד ,נדרש כי כל הפונקציות ייתמכו. על מנת לוודא התאמה זו ,יתכן ונידרש לכתוב מחדש חלק מהפונקציות שאנו משתמשים בהן .לצורך כך ,מומלץ כי ההמרה תיעשה ע"י המתכנן ,אשר מכיר את אופן הפעולה של הפונקציה ויודע במידת הצורך כיצד ניתן להמירה. .2.3התאמת הקוד למערכות זמן-אמת לאחר שבסעיף הקודם בדקנו כי כל ה"טקסט" הנמצא בתוך קוד ה MATLAB-תואם ל- ,EMLעלינו כעת לחבוש את כובע המתכנת ,ולדאוג לכך שהאלגוריתם לא רק יהיה כתוב ב ,EML-אלא גם יתאים מבחינת אופן הפעולה שלו למערכות זמן אמת – מערכות .Embeddedלמשל ,עלינו לוודא שהאלגוריתם מקבל כניסות שהן ב Stream-של מידע ,ולא כ Bulk-של מידע .לרוב מערכות זמן-האמת ישנה כניסה דיגיטלית אשר מסוגלת להעביר מידע ב"חבילות" )או (Packetsשל מידע ,ולא נעשה תרגום אוטומטי ל"תמונה" או ל"אות" או ל"חיישן" .לכן ,עלינו לדאוג לכך שהאלגוריתם הנדון יידע לאגור מידע שמגיע אליו בתצורה של חבילות מידע ,ולבצע את הפעולה שלשמה נועד רק כאשר קיבל מספיק מידע. בנוסף ,עלינו לוודא שהקוד יהיה יעיל וינצל כמה שפחות זיכרון או משאבי מערכת. בשלב זה גם לרוב נוסיף שימוש באותות בעלי גודל משתנה )או (Variable Sizeאשר מאפשרים לנו לעבוד עם כניסות שגודלן אינו קבוע בכל שלב ושלב של ריצת האלגוריתם. בשלב זה יש כמובן להחליט על ארכיטקטורת המעבד שאיתו נעבוד ,וכתוצאה מכך גודל המשתנים שאיתם נעבוד ) 16 ,8או 32ביט( .בעבודה עם MATLABניתן לבחור כל אחד מהגדלים הללו תוך כדי ריצה ,אך מערכות זמן אמת חייבות לדעת מראש מהם סוגי המשתנים. .2.4יצירת פונקציית MEXלצורך בדיקה פונקציונלית של הקוד בטרם נייצר קוד Cונטמיע אותו ברכיב החומרה שבחרנו ,נרצה לוודא כי הקוד שאנחנו כותבים מבצע את אותן הפעולות כמו ה .Golden Reference-לשם כך ,נייצר פונקציית .MEXפונקציות ) MEXאו (MATLAB Executableהן פונקציות שניתן להריץ אותן בסביבת ,MATLABאך הן למעשה קוד Cשעבר תהליך של קומפילציה – כלומר הרצה של קוד Cבתוך .MATLAB את פונקציית ה MEX-ניתן לשלב באותה סביבת בדיקות שבה נבדק האלגוריתם המקורי. את אותן הפעולות שבוצעו על קוד ה MATLAB-ניתן לבצע גם על פונקציה זו ,ולהשוות עמוד 8מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB בצורה מלאה ביניהן .כל שינוי בתוצאות המתקבלות מפונקציית ה MEX-מעיד על חוסר דיוק שהוכנס בהליך ההמרה ל .EML-המטרה היא לוודא שחוסר הדיוק הוא מספיק קטן בכדי שיהיה "זניח" .יש להבין כי חוסר דיוק זה נובע מהמעבר מעבודה בסביבת מחשוב של 64ביט )עם דיוק כפול( לסביבת עבודה הנמצאת לרוב ב 32-ביט )דיוק יחיד( .לכן – שגיאות קוונטיזציה צפויות להתקבל. בשלב זה יש גם להחליט על האם המעבד הסופי שאליו נייצר קוד הוא מסוג Floatאו .Fixedבמידה והוא מסוג – Floatנוכל להמשיך לשלב הבא .אחרת ,עלינו לעבור שלב נוסף של המרת האלגוריתם לעבודה ב .Fixed-הליך זה יכול להיות קל יותר ע"י שימוש בFixed - ,Point Toolboxולאחר סיומו מצריך בדיקה נוספת של פונקציית MEXלמול הGolden - ,Referenceבכדי לוודא שחוסר הדיוק הנובע מקוונטיזציה לא פגע באופן הפעולה של האלגוריתם. .2.5יצירת קוד לאחר שייצרנו פונקציית MEXובדקנו אותה למול ה ,Golden Reference-ניתן לייצר קוד .בשלב זה עלינו להגדיר לאיזה מעבד ברצוננו לייצר קוד ,כאשר הרשימה של המעבדים הנתמכים הינה ארוכה )ומתארכת עם השנים( .רשימה מלאה ניתן למצוא ב: http://www.mathworks.com/products/rtwembedded/supportedio.html יש להדגיש כי ישנן פעולות מתימטיות רבות אשר יש להן מימוש אופטימלי בהתאם לסוג החומרה ,ולכן מומלץ להגדיר מהי החומרה שעובדים איתה .מעבר להגדרות הבסיסיות האופייניות למעבדים )כמו ,Big/Little Endianגודל משתנים וכדומה( ,גם המימוש עצמו ייעשה בהתאם למעבד. במידה ועל מחשב יצירת הקוד מותקנים כלי יצירת קוד מתקדמים )כמו Embedded IDE Linkאו (Target Support Packageאזי ניתן לממש בצורה יעילה גם פונקציות מתקדמות יותר )כמו ,(FFTולהגיע למימוש חומרתי ברמת אסמבלי של פעולות בסיסיות אשר זמינות על הרכיב עצמו )כמו PIDעבור בקר מסדרת C2000של Texas Instrumentsאו ADC למעבדים של .(Analog Devices את הקוד שייצרנו ניתן לשלב בפרוייקט גדול יותר של Visual C++למשל ,או בפרוייקטים של מערכות זמן-אמת הקשורים ל IDE-של הסביבה איתה עובדים )כמו CCSשל Texas Instrumentsאו Visual DSP++של .(Analog Devicesאת הקוד הזה לא ניתן כמובן להחזיר לתוך MATLABולבדוק אותו שוב – שכן הארכיטקטורה איננה זהה לארכיטקטורה של המחשב עליו מותקן .MATLAB במידה ואנחנו עובדים עם ,Simulinkניתן לשלב את קוד ה EML-בתוך מודל רחב יותר, ולהמשיך בהליך הפיתוח כאשר האלגוריתם שנכתב הוא כעת בלוק אחד מתוך מערכת מלאה יותר ,לאחר שנבדק בצורה מלאה וידוע אופן פעולתו. ישנה כמובן אפשרות לשילוב קוד Cקיים ,שנכתב בעבר ,בתוך EMLאו בתוך ,Simulink ובמקרה זה סביבת הפיתוח של MATLABיכולה להיות סביבת האינטגרציה המלאה. עמוד 9מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .3בדיקה האם הקוד שנכתב תואם לEML- בתחילת שלב זה ,קיים אלגוריתם הכתוב בשפת ,MATLABואשר נבדק כי הוא מבצע את תפקידו בצורה תקינה .מטרת שלב זה היא ליצור קוד הכתוב ב .EML-לפני תחילת העבודה המפורטת בפרק זה ,מומלץ לשמור גרסה חדשה של הקובץ שעימו עובדים – בכדי לא לפגוע ב- .Golden Reference המלצה מס' 1 בטרם ביצוע שינויים כלשהם ,מומלץ לשמור את הקובץ בשם חדש ,על מנת שתמיד יהיה ניתן לחזור לשמירה האחרונה. לדוגמא :אם שם הפונקציה המקורית הוא ,myFunctionמומלץ לשמור את הגרסאות בסדר עולה ,כגון . myFunction_01 את השינויים שבוצעו מומלץ לתעד באמצעות הערות ,וניתן כמובן לשמור גרסאות שונות בכלי הVersion - Controlבמידה והוא בשימוש במערכותיכם .קראו על איך MATLABמחובר למערכות :VC http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_env/f7-5297.html או ב help-כמובן. .3.1טיפול והסרה של כל ה"הערות" שנתגלו ע"י שימוש בm-lint- החל מגרסה ,R2007aשולב בתוך ה editor-של MATLABכלי ה m-lint-אשר בודק את הקוד בצורה סטטית .תפקידו הוא לוודא כי הקוד שכתבנו אינו מכיל שגיאות ,ובמידה ושגינו ,יעיר לנו על "הערה" )הקוד בעייתי ,אך יכול לרוץ( או "שגיאה" )הקוד בעייתי ,ולא יכול לרוץ(. בטרם אנו ממשיכים הלאה ,מומלץ )וחובה( לוודא כי אין הערות/הודעות/שגיאות כלשהן אשר לא טופלו .במידת הצורך יש להשתמש ב "Suppress this Instance of … "-ע"י לחיצת כפתור ימני בעכבר על ההערה שהתגלתה .להלן דוגמא להערה על כך שמומלץ לסיים כל פקודה ב ";": עמוד 10מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .3.2שימוש בפרגמה %#eml כאשר נעבוד ב ,EML-ה m-lint-הוא בעל יכולות נוספות ,ויכול לבדוק נושאים הקשורים ל- .EMLלמשל -לבדוק שכל הפונקציות שאנו משתמשים בהן ,נתמכות ב .EML-על מנת להפעיל את ה m-lint-במצב זה ,יש להשתמש בפרגמה . %#emlאת הפרגמה ניתן למקם בכל מקום בתוך קובץ ה ,m-אך מומלץ לשים אותה לפני הגדרת הפונקציה .להלן דוגמא: לאחר שמיקמנו את הפרגמה במקומה ,על ה m-lint-להיות "ירוק" ,כלומר לא להכיל אף שגיאה )ראה תמונה(. להלן דוגמא לקוד שמכיל שגיאה שכזו .קוד זה משתמש בפונקציית ה edge-מתוך ספריית ה .Image Processing-פונקציה זו איננה נתמכת ב ,EML-ולכן מתקבלת שגיאה: עמוד 11מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB מהיכרות עם הקוד ,קובץ ה m-שנכתב אמור להשתמש בשיטת sobelשל פונקציה זו. אלגוריתם זה מבוסס על שימוש ב 2-פעולות של קונבולוציה ,ולכן אם נכתוב רק אותו כפונקציה ,הוא כן ייתמך והשגיאות כבר לא קיימות: באופן זה יש לוודא כי כל הפונקציות שאנו משתמשים בהן ייתמכו. דוגמא נוספת אשר עשויה להתקבל ,היא על ביצוע הקצאות דינמיות של זיכרון ,אשר אינן נתמכות .נסתכל לדוגמא על מקטע הקוד הבא ,אשר אמור לבצע העתקה פשוטה של זכרון בין 2משתנים .המשתנה CarbonCopyהוא לא בעל גודל מוגדר מראש ,ולכן מתקבלת הערה על כך שמשתנה זה חייב להיות מוגדר בזמן הקריאה לפונקציה: עמוד 12מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB מצב זה הינו מקובל ביותר בעבודה עם ,MATLABשכן מערכת ההפעלה של MATLAB המטפלת בנושא הקצאת הזיכרון ,תדאג בכל שלב ריצה של הלולאה להגדיל את המשתנה בהתאם .היא למעשה תעשה בכל שלב הקצאה מחודשת של זיכרון ,ותעתיק אליו את הערכים החדשים. פעולה זו כמובן איננה נתמכת ב ,EML-שכן בזמן הקריאה לפונקציה לא ידוע כמה פעמים תיקרא ,ולכן גודל המשתנה איננו מוגדר מראש .הקצאת זיכרון דינמית זו איננה נתמכת, מה גם שבמערכות זמן-אמת רבות לא היינו רוצים לקבל גדילה של משתנים בצורה לא מבוקרת. על מנת לטפל בבעיה זו ,יש לבצע הקצאה של גודל המשתנה בזמן הכניסה לפונקציה .דוגמא לכך מצויה בשורה 3של הקוד לעיל – ע"י שימוש בפקודה .zeros הערה: בהתאם ל 2-הדוגמאות שראינו לעיל ,ניתן להסיק כי ייתכן מצב שבו נכתוב חלק מהקוד מחדש ,ולא "נהנה" מהיתרונות שבעבודה עם .MATLABעם זאת ,ברגע שנבצע את השינויים ,אנו נקבל פעולה מהירה יותר גם של קוד ה ,MATLAB-שכן הוא ירוץ בצורה יעילה יותר -ההעתקות הרבות שלא יבוצעו ,ההימנעות מבדיקות "מיותרות" של פונקציות רובסטיות וכדומה -יחסכו זמן ריצה רב .משתמשים רבים שעברו מ MATLAB-לEML- דיווחו על חיסכון בזמני ריצה ברמה של אחוזים רבים ,ובמקרים קיצוניים עד כדי 90% מזמן הריצה )!(. המלצה מס' 2 מומלץ לפעול בהתאם להנחיות ה .m-lint-הנחיות אלו נובעות מסיבות של יעילות ,בדיקת אפשרות ליצירת קוד ,וכן הימנעות משגיאות מיותרות .קיימת אפשרות לביצוע תיקון אוטומטי לחלק מההערות. ניתן להפעיל את ה M-Lint-ולבחור בדיקות ספציפיות ע"י שינוי ה Preferences-של ה m-lint-באופן הבא )תחת סביבת העבודה של :(MATLAB File-> Preferences-> M-Lint-> Enable Integrated M-Lint Warnings and Error Messages עמוד 13מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .4התאמת הקוד למערכות זמן-אמת בשלב זה יש לחבוש את כובע המתכנת יותר מאשר את כובע האלגוריתמאי ב ,MATLAB-שכן כעת עלינו לחשוב על הקוד שהולך להיווצר ובאיזו מערכת הוא הולך להיות משולב. בקוד הנוצר ,נרצה למנוע שכפולים מיותרים של משתנים )על מנת לחסוך בזיכרון( ,להגדיר את טיפוסי המשתנים ואת גודלם המירבי בכדי להקצות זיכרון בצורה מתאימה ,ולטפל בפונקציות הדואגות לויזואליזציה של ,MATLABאו בקריאה לפונקציות שאינן נתמכות .כאן נטפל גם בממשקי הפונקציה ולכך שהיא צריכה לעבוד בסופו של דבר על מעבד בזמן-אמת. " .4.1טיפול" בפונקציות של MATLABבאמצעות eml.extrinsic תוכנת MATLABמכילה הרבה מאד פונקציות אשר אינן נתמכות ליצירת קוד .הדוגמא הכי פשוטה לפונקציה שכזו היא פונקציית ,plotאשר מדפיסה גרף בחלון חדש .פונקציה זו כמובן איננה רלוונטית בעיסוק במערכות זמן-אמת. על מנת שלא לשנות את כל הקוד מספר פעמים ,וליצור פונקציות נפרדות לריצה ב- MATLABופונקציות אחרות ליצירת קוד ,ניתן להגדיר פונקציות אלו כפונקציות "חיצוניות" )או .(extrinsicהגדרה זו בעלת 2משמעויות .1 :בזמן הרצת הפונקציה ב- – MATLABתתנהג באופן רגיל .2 .בזמן יצירת קוד – לא ייווצר קוד מפונקציה זו. להלן דוגמא לפונקציה שכזו: בדוגמא זו ניתן לראות הגדרת הפונקציות patchו axis-כ .extrinsic-כפי שניתן לראות הפונקציה הסופית נתמכת ב %#eml-ונתמכת גם ליצירת קוד כמובן. עמוד 14מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB המלצה מס' 3 בצעו הפרדה בתוך הפונקציות בין פעולות הקשורות לויזואליזציה לבין האלגוריתם המקורי. בדוגמא הקודמת הייתה הפרדה בין – create_plotפונקציה הדואגת להדפסת התוצאות לבין – Pythagorasהפונקציה אשר מבצעת את עיבוד הנתונים .בצורה כזו ייחסכו קריאות רבות, והקוד שנוצר יהיה "נקי" ויעיל יותר .בדוגמא שלעיל – כלל לא ייווצר קוד מהפונקציה השניה. .4.2הגדרת טיפוסי משתנים על מנת ליצור את טיפוסי המשתנים ,עלינו להצהיר עליהם .ניתן לעשות זאת ב 2-אופנים: .1שימוש בפקודה .assert .2שימוש במשתנה לדוגמא ,שמכיל את הגודל וטיפוס המשתנה. שימוש בפקודה assert הפקודה assertמחזירה ערך שלילי כאשר התנאי שהיא בודקת איננו מתקיים .למשל ,קטע הקוד הבא איננו נכון ולכן התוצאה היא שלילית: כאשר אנו משתמשים ב ,EML-לפונקציה זו ישנה חשיבות ראשונה במעלה ,שכן במהלך יצירת הקוד ,הקומפיילר בוחן את הערכים הנבדקים ע"י פונקציה זו ,ומשתמש בהם בכדי להגדיר את הפרמטרים השונים מבחינת טיפוס ומבחינת גודל. לדוגמא ,אם ברצוננו להגדיר פרמטר סקלרי ,X ,שיהיה מטיפוס uint16ובעל גודל מקסימלי של ,1,000נעשה זאת ע"י ההגדרה הבאה: ;))'assert(isa(X, 'uint16 ;)assert(X <= 1000 הפקודה isaבודקת את טיפוס הפרמטר ומשווה אותו ל uint16-במקרה זה. באופן דומה ,אם ברצוננו להגדיר פרמטר ,A ,כך שיהיה מטריצה בגודל ,10x20מטיפוס ,complexנעשה זאת באופן הבא: ;))assert(~isreal(A ;))]asser(all(size(A) == [10 20 הפקודה allבודקת כי בתוצאה המתקבלת מההשוואה ,כל הערכים הם "נכונים". עמוד 15מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB באופן זהה ,ניתן להשתמש בפקודה assertבכדי לוודא גדלי וטיפוסי פרמטרים סקלריים, מטריצות בעלות Nמימדים ,מערכים ) ,(structמשתני ) Fixed Pointעם הפקודה ,(isfi משתני כניסה לפונקציה ומשתנים שנעשה בהם שימוש בתוך הפונקציה. ==< משתני המוצא "יורשים" ערכים אלו מתוך נתוני המשתנים הבונים אותם – ולכן לא נדרש להגדירם. שימוש במשתנה לדוגמא השימוש במשתנים לדוגמא יכול להיעשות רק בזמן הליך יצירת הקוד עצמו ולא ניתן לשילוב בתוך הקוד .לצורך כך נעשה שימוש בדגלון –egבתוספת לפונקציה emlmex )יצירת (MEXאו ) emlcיצירת קוד :(C emlmex -eg {single(0)} myFunction emlc -eg {zeros(1,4,'uint16'),double(0)} myFunc 1. 2. בדוגמא הראשונה ,נאמר לקומפיילר שהפונקציה מצפה לקבל משתנה מטיפוס .single שימו לב כי ערך המספר עצמו – 0בדוגמא זו – כלל איננו משפיע על התוצאה ,אלא רק על טיפוס המשתנה. בדוגמא השניה ,נאמר לקומפיילר שהפונקציה מצפה לקבל 2פרמטרים .הראשון הוא מערך בגודל 1x4מטיפוס uint16והשני הוא מטיפוס .double השימוש במשתנים לדוגמא יכול להכיל רק את סוג המשתנים ,ולא הגודל המקסימלי שלהם .לכן הדרך הראשונה )ע"י שימוש ב (assert-היא מומלצת יותר. בשלב יצירת הקוד נדון בהרחבה בפקודות emlcו.emlmex- המלצה מס' 4 השתמש ב assert-בתוך קובץ האלגוריתם .בצורה זו יצירת הקוד איננה תלויה בקובץ הבנייה ובדוגמאות חיצוניות אשר עלולות להפריע להליך זה. ניתן לקרוא על פונקציות המסייעות לה ,כגון any ,isa, all, isfi :ו.isequal - .4.3הגדרת פרמטרים בעלי גודל משתנה )(Variable Size פרמטרים בעלי גודל משתנה הינם פרמטרים אשר גודלם יכול להשתנות במהלך ריצת הקוד. גודל זה חייב להיות תחום בגבול עליון כלשהו ,על מנת שבשלב יצירת הקוד ניתן יהיה להקצות מספיק זיכרון לעבודה עימם. השימוש בפרמטרים אלו הוא הכרח המציאות כאשר עובדים עם כניסות שגודלן יכול להשתנות – למשל גודל תמונה או אורך אות .שימוש אחר נפוץ הוא בפקודה – findאשר מחזירה תוצאות חיפוש על מערך בהתאם לקריטריון מסויים. קיימות מספר דרכים להגדרת פרמטרים כבעלי גודל משתנה: שימוש בeml.varsize- תחת EMLנוספה הפונקציה eml.varsizeאשר מאפשרת להגדיר בצורה ישירה כי פרמטר מסויים הוא בעל גודל משתנה .למשל הפקודה: ;)]eml.varsize('Y', [1 8 עמוד 16מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB מגדירה מטריצה ,Yבעלת 2מימדים מטיפוס ,doubleכאשר גודל המטריצה יכול להיות ,1x:8כלומר "אחד על )עד שמונה(" .הגודל השני של המטריצה יכול להשתנות בכל הטווח מ 0-ועד .8יש לשים לב כי פרמטרים בעלי גודל משתנה מקבלים את הסימון " ,":אשר מסמל את השינוי הצפוי בגודלם. בצורה דומה ,הפקודה הבאה: ;)]eml.varsize('myMatrix',[100 20000], [0 1 מגדירה את המטריצה myMatrixשגודלה המקסימלי הוא .100x20000עם זאת במקרה זה ,תוספת ההגדרה ] [0 1מוסיפה אילוץ שרק הגודל השני של המטריצה הוא משתנה, כלומר גודל המטריצה יהיה .100x:20000כלומר "מאה על )עד 20אלף(". ובכדי להגדיר structכבעל גודל משתנה: ;)d = struct('values', zeros(1,0), 'color', 0 ;)]data = repmat(d, [3 3 ;)'eml.varsize('data(:).values כאן מוגדר structבעל השם ,dataאשר כל שדות ה values-שלו הם בעלי גודל משתנה. הערה בנוגע ליצירת הקוד: קוד בעל פרמטרים בגודל משתנה ,מתוקף היותו כזה ,יהיה פחות יעיל .זאת עקב הבדיקות הנוספות שיש לבצע על הפרמטרים ,העברת משתנים שמייצגים את גודלו הנוכחי של הפרמטר ,ועוד .מומלץ להשתמש ביכולת זו רק כאשר אין כל פתרון אחר. הגדרת חסמים עליונים באמצעות שימוש בפרמטרים ניתן להגדיר פרמטרים בעלי גודל משתנה גם באמצעות חסימת גודלם המקסימלי באמצעות פרמטר נוסף .למשל הדוגמא הבאה: function y = dim_need_bound(n) %#eml ;)assert (n <= 5 ;)L= ones(n,n ;)M = zeros(n,n ;]M = [L; M ;y = M בדוגמא זו מוגדרים הפרמטרים Lו M-שהן מטריצות בעלות גודל של . :5x:5 במקרים רבים נראה את הסימון "? ,":אשר מייצג את הפרמטר שגודלו בזמן ריצה למעשה איננו חסום בגודל ,אלא רק בטיפוסו .הודעה זו לרוב תלווה בהודעת שגיאה ,שכן הגדרה זו איננה נתמכת ב.EML- הגדרת הפרמטר ע"י שימוש בפקודה emlcoder.egsובדוגמא כפי שראינו בפרק ,4.2ניתן להשתמש בפרמטר לדוגמא בשימוש עם emlmexאו .emlcניתן להשתמש בדרך זו גם בכדי להגדיר פרמטר כבעל גודל משתנה ,באופן הבא: })]emlmex myFcn -eg {emlcoder.egs(0,[2 4 בדוגמא זו מוגדר כי הפרמטר המסופק לפונקציה myFcnהינו מטריצה בעלת הגודל המשתנה , :2x:4והיא מטיפוס ,doubleבהתאם לדוגמא )]. (0, [2 4 עמוד 17מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB פתרון "אוטומטי" של הגדרת הפרמטר כבעל גודל משתנה נסתכל על הדוגמא הבאה: function y = var_by_multiassign(u) %#eml )if (u > 0 ;)y = ones(3,4,5 else ;)y = zeros(3,1 end בדוגמא זו מוגדר המשתנה Yכמטריצה בעלת הערכים ) .3x(nxmכלומר – המימד הראשון הוא תמיד ,3והערכים האחרים משתנים בהתאם לתנאי ה .if-על מנת לפתור בעיה זו ,נוקט הקומפיילר בגישה המתפשרת ומגדיר את Yכבעל המימדים .3x:4x:5 המלצה מס' 5 במידה והקוד אמור לקבל פרמטרים בעלי גודל משתנה ,מומלץ להגדיר אותם בצורה חד- ערכית בקוד עצמו ,ע"י השימוש ב eml.varsize-וב assert-בכדי לחסום את גודלם .בדרך זו לא תהיה תלות בקריאה חיצונית לפונקציה ויופחת הסיכוי לשגיאות. בגרסה R2010bנוספה היכולת לייצר באמצעות הקצאת זיכרון דינמי עבור פרמטרים שאינם חסומים בגודלם מלמעלה .קראו על יכולת חדשה זו ב help-או בקישור הבא: http://www.mathworks.com/help/toolbox/eml/ug/br7rggy.html#bspud0r .4.4עבודה עם פרמטרים מסוג struct במידה ובקוד משולבים טיפוסי פרמטרים מסוג ,structיש לפעול לפי ההנחיות הבאות: יש להגדיר structבצורה מלאה לפני השימוש באיבריו השונים לא ניתן לקרוא לאחד מאיברי ה ,struct-ולאחר מכן להגדיר איבר אחר .למשל: function y = Struct_01(x) %#eml ;y.f = x ;a = y.f * y.f ;y.h = exp(a) + y.f פעולה זו תחזיר שגיאה. על מנת להימנע מבעיה זו ,יש לאתחל את כל איברי המ struct-לפני השימוש בהם .בדוגמא לעיל ,ניתן להוסיף את השורה ;y.h = 0 לפני ביצוע הפעולה על .aכעת הפעולה כן תיתמך. יש להגדיר בצורה מפורשת את שדות ה struct-כמשתנים בתחילת הפרק דובר על השימוש בפקודה assertבכדי להגדיר גדלי משתנים וטיפוסים. בעבודה עם ,structיש לבצע זאת עבור כל אחד מהשדות השונים ,בצורה מפורשת .כלומר, במידה וישנו structבעל 2שדות - Values, Length :יש להגדיר את שניהם. עמוד 18מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB עם זאת ,במידה ונעזרים בפרמטר לדוגמא )ע"י שימוש ב ,("-eg"-אזי ה struct-המקורי מגדיר את כל השדות ,ואין צורך לעשות זאת שוב. שליטה על שם ה struct-בקוד הC- בתהליך המרת הקוד ,שמות ה struct-הם אקראיים .במידה וברצונך לשלוט על שמות אלו, יש להשתמש בפקודה eml.cstructnameבאופן הבא: %#eml )function y = topfun(x ;)'eml.cstructname(x, 'MyStruct ;y = x במידה וכבר קיים structב ,C-ואנו רוצים להשתמש בהגדרה הקיימת עבורו ,אזי נעשה שימוש בדגלון ' 'externבפקודה זו ,לפי הדוגמא הבאה: ;)'eml.cstructname(structVar, 'MyStruct', 'extern יש לשים לב כי במקרה זה ,נדרש כי MyStructיהיה מוגדר בקוד Cשנכתב או הוגדר במיקום אחר בקוד .ניתן כמובן להשתמש ב"קבצים החיצוניים" בשימוש בפקודה ,emlc עליה ידובר בשלב יצירת הקוד. .4.5עבודה עם מטריצות "ריקות" במקרים רבים נהוג לאתחל פרמטרים כבעלי ערך "ריק" )או "]["( ,ואז להגדיל את הפרמטר בתוך לולאות .בעבודה עם EMLיש להתייחס למטריצות ריקות בצורה שונה מהרגיל ,שכן היינו רוצים להגדיר אותן כבעלות גודל משתנה .במקרה זה ,במקום ההגדרה הבאה: function y = NullMatrix(x) %#eml ;][ = y )while (x > 0 ;x = sqrt(x) – 1 ;]y = [y x end יש כמובן להגדיר את yכפרמטר בעל גודל משתנה .אך במקרה זה יש להגדירו באופן הבא: ;)y = zeros(1, 0 ;]eml.varsize('y', [1 10 זאת ,כיוון שבכדי שפרמטר יוגדר כבעל גודל משתנה ,אחד מהגדלים שלו חייב להיות שונה מאפס .בהגדרה "] [ "– גודל המשתנה הוא ,0x0ולכן לא יהיה בעל גודל משתנה .ברגע שנוסיף את השימוש ב – zeros(1, 0)-הבעיה תיפתר. .4.6הגדרת משתנים בצורה מותנית השימוש ב EML-אינו מאפשר להגדיר משתנים בצורה התלויה בתנאי כלשהו .לדוגמא: function y = NullMatrix_02(x) %#eml )if (x > 0 ;y = 1 end )if (x < 0 עמוד 19מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB ;y = 2 end בפונקציה זו יתכן מצב שבו אף אחד מהתנאים לא יתקיים ,ולכן המשתנה yלעולם לא יוגדר EML .מחייב שכל הפרמטרים יאותחלו ויוגדרו ,ועל כן יש להוסיף אתחול למשתנה ,yלמשל הוספת y=0בתחילת הפונקציה. .4.7הקצאת זיכרון מינימלית באמצעות eml.nullcopy במקרים רבים נהוג לאתחל פרמטרים ע"י השימוש בפקודה ,zerosולאחר מכן לשנות את ערכם .מצב זה יכול להוביל להעתקות זיכרון רבות אשר עשויות להיות מיותרות ולארוך זמן רב. בעזרת השימוש בפונקציה ,eml.nullcopyניתן להגדיר את כמות הזיכרון הנדרשת ,אך לא לאתחל אותה בערך ראשוני .להלן דוגמא: %#eml function X = foo ;N = 5 ;))X = eml.nullcopy(zeros(1,N for i = 1:N if mod(i,2) == 0 ;X(i) = i else ;X(i) = 0 end end בדוגמא זו ,המשתנה Xמאותחל לגודל ראשוני של ] ,[1 5מטיפוס doubleאך ערכיו ניתנים לו רק בתוך לולאת ה.for- יש לשים לב כי בהקצאת זיכרון ,הערך המצוי בתא זה הוא אקראי ,ויש לוודא כי לא נעשה שימוש בערכים אלו לפני אתחולם .פעולה זו עשויה להוביל לתוצאות בלתי צפויות ובלתי רצויות. .4.8אינדקסים של וקטורים בעלי גודל משתנה בשימוש באינדקסים ב ,EML-יש לחסום את גודל הווקטור כך שיהיה סופי .לשם כך ,לא ניתן להשתמש בהגדרה הבאה: ;)myMatrix(n:n+L-1 מאחר והגדלים nו L-הם בעלי גודל משתנה ,האינדקסים של המטריצה אינם חסומים בצורה מפורשת .על כן ,יש להשתמש בהגדרה הבאה: ;))myMatrix(n+(0:L-1 אשר הינה זהה לחלוטין בתפקודה ,וכך גם האינדקסים חסומים בגודלם. המלצה מס' 6 בדקו את הפונקציות הבאות וכיצד הן יכולות לסייע בייעול הקוד: * eml.unroll * eml.inline עמוד 20מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .4.9תמיכה במשתנים גלובליים global - החל מגרסה ,R2010aנוספה התמיכה במשתנים גלובליים ,כלומר משתנים המזוהים בכל קבצי ה m-עימם עובדים .הגדרת משתנה שכזה מבוצעת באמצעות הפקודה :global )function y = use_globals(u %#eml % Turn off inlining to make % generated code easier to read ;)'eml.inline('never % Declare AR and B as global variables ;global AR ;global B ;)AR(1) = u + B(1 ;y = AR * 2 ;))yMatrix(n+(0:+L-1 כשננסה לייצר קוד או MEXמפונקציה זו ,הקומפיילר יזהה כי קיימים כאן פרמטרים גלובליים ,ויגדיר אותם בהתאם .אם נרצה להגדיר אותם באמצעות הדגלון ,-egנעשה זאת כך: … >> emlmex -o myGlobalMEXFunction -global {'AR',ones(4),'B',[1 2 3]} my_Global_UsingFunction .4.10שימוש בstreaming- ברוב מערכות זמן-האמת ,האלגוריתם נועד לבצע פעולה מסויימת על גודל מסויים של מידע .עם זאת ,המידע מגיע בתצורה של חבילות )או חלקי מידע( ,ולכן יש לאגור את המידע החלקי בכדי לבנות ממנו מידע בגודל הנדרש. לדוגמא ,עבור אלגוריתם שמבצע זיהוי שפות בתמונה ,יש לוודא כי התמונה מגיעה במלואה לאלגוריתם ,ורק לאחר מכן הוא מופעל .לשם כך יש לאסוף את המידע שמגיע בחבילות של 32ביט ,לשחזר את התמונה ממצב של שורה-שורה לרמה של תמונה בגודל אמיתי. לשם כך ,יש להשתמש בחוצץ )או ,(bufferאשר מסוגל לשמור מידע לאורך זמן ריצת הקוד, גם כאשר הפונקציה איננה פעילה .ב ,MATLAB-על מנת להגדיר משתנה בצורה כזו, משתמשים בהגדרת .persistentצורת פתרון זו קיימת גם ב ,EML-ואיננה מצריכה שינוי מסויים. להלן מקטע קוד לדוגמא להגדרת חוצצים בעלי השם fifoו:weights- %#eml )function [signal_out] = myFunction(signal_in, desired הגדרת הפרמטרים אתחול ראשוני } } ;persistent weights ;persistent fifo % Filter length: ;)L = uint32(32 % Adaptation step size: ;)mu = 4/(32*1024 % Signal length: ;)N = length(signal_in if length(desired) == N )if isempty(weights % Filter coefficients: ;)weights = zeros(L,1 % FIFO Shift Register: ;)fifo = zeros(L,1 עמוד 21מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB end % Pre-allocate output and error signals: ;)signal_out = zeros(N,1 ;)err = zeros(N,1 % Filter Update Loop: for n = 1:N עדכון בזמן ריצה ;)fifo(1:L-1) = fifo(2:L ;)fifo(L) = distorted(n ;signal_out(n) = weights' * fifo ; )err(n) = desired(n) - signal_out(n ;weights = weights + mu*err(n)*fifo end } else ;)'error('Lengths of input signals are not equal end end מקטע קוד זה נתמך ליצירת קוד ו ,EML-במגבלה הבאה: פרמטר שמוחזר מהפונקציה לא יכול להיות משתנה מסוג .persistentכלומר – הפרמטר fifoאו weightsלא יכול להיות מוצא מפורש של הפונקציה .במידה ונדרש לעשות זאת ,יש להגדיר פרמטר חדש שיכיל ערכים אלו .למשל ,הגדרת השורה הבאה: ;weights_out = weights ⇐ יש לשים לב ,כי במידה ונדרש לבצע Streamingלאלגוריתמים העוסקים בעיבוד אותות, עיבוד תמונה או מערכות תקשורת ,אזי החל מגרסה R2010aקיימות פונקציות אלו לשימוש המתכנן בצורה חופשית ,בכלים המוספים – Video and Image Processing Signal Processing Blockset ,Blocksetו.Communications Blockset- המלצה מס' 7 לאחר ביצוע השינויים ,ניתן להשוות בין קובץ המקור לקובץ עם השינויים מבחינת ה"טקסט", ע"י שימוש ב . Tools > Compare Against > Browse -בחלון ה editor-ייפתחו 2הקבצים וניתן יהיה להשוות ביניהם בצורה פשוטה. .4.11בדיקה פונקציונלית בפרק זה נעשו לא מעט שינויים בקובץ המקור ,וייתכן והוזרקו מספר שגיאות לאלגוריתם. על מנת לוודא שהקובץ החדש מבצע בדיוק את אותה הפעולה כמו הקובץ המקורי ,יש להשוות בין פעולתם. בדיקה זו ניתן לבצע בפשטות ע"י כתיבת test-scriptאשר יקח כניסות מסוג מסויים וישתמש בהן בכדי לקרוא לפונקציה המקורית ולפונקציה הנתמכת ב .EML-באמצעות MATLABככלי וריפיקציה נוכל לאגור את התוצאות מכל פונקציה ,ולהראות את הסטיות בצורה ויזואלית – במידה וישנן כאלו. מאחר והאלגוריתם החדש הוא זה שיועבר ליצירת קוד ,בדיקה זו הינה חשובה יותר, ואיננה בגדר "המלצה". יש לוודא כי הסטיות -במידה ונתגלו -הן מזעריות ,או כאלו שהן צפויות בשינוי בין המימושים – למשל שגיאות קוונטיזציה במעבר מ double-ל.uint8- עמוד 22מתוך 33 MATLAB מתוךC קווים מנחים ליצירת קוד מקטעי הקוד )הקוד המקורי2- המראה כיצד ניתן לקרוא לtest-script-להלן דוגמא ל :(EML-והקוד הנתמך ל %% Test Bench for LMS Filter Example % Version #2 -- EML Compliant vs. Baseline MATLAB Code %% Setting up: % Initialize: close all; clear all; clc; %% Creating Signals: % Load desired audio signal: data = load('handel.mat'); desired = data.y; Fs = data.Fs; % Length of desired signal: N = length(desired); % Maximum signal length: MaxLength = 128*1024; % samples % Filter length: L = 32; % Band-limited AWGN: load emldemo_lms_filter.mat; lambda = 1.0; whiteNoise = lambda*randn(N,1); noise = filter(b,1,whiteNoise); % Distorted signal: distorted = desired + noise; %% Apply Algorithm: % Golden reference: [gold.signal gold.error gold.impulse] = emldemo_lms_01(whiteNoise,distorted,L); % Algorithm under test: [test.signal test.error test.impulse] = emldemo_lms_02_mex(whiteNoise,distorted); %% Find differences: diff.signal = test.signal - gold.signal; diff.error = test.error - gold.error; diff.impulse = test.impulse - gold.impulse; %% Plot differences: figure; subplot(3,1,1); plot(diff.signal); title({'Algorithm Under Test versus Golden Reference' 'Output Signal'}); subplot(3,1,2); plot(diff.error); title('Error Signal'); subplot(3,1,3); stem(diff.impulse); title('Impulse Response'); 8 'המלצה מס : למשל. מומלץ לתת שמות התואמים לפעולת הקודscript או קבציm בשמירת קבצי .02 גרסה, – האלגוריתם הנדוןmyAlgorithm_02 .01 גרסה,myAlgorithm – קובץ המסייע לבניית קוד עבורmyAlgorithm_build_01 .03 גרסה, – קובץ המסייע לבדיקת האלגוריתםmyAlgorithm_Test_03 33 מתוך23 עמוד קווים מנחים ליצירת קוד Cמתוך MATLAB .5יצירת פונקציית MEXלצורך בדיקה פונקציונלית של הקוד כפי שנכתב קודם ,בטרם נייצר קוד Cבצורה סופית ,ונטמיע אותו ברכיב החומרה שבחרנו ,נרצה ראשית לוודא כי הקוד שנוצר מבצע את אותן הפעולות כמו ה.Golden Reference- הדרך לעשות זאת היא ע"י יצירת פונקציית .MEX פונקציות ) MEXאו (MATLAB Executableהן פונקציות שניתן להריץ אותן בסביבת ,MATLABאך הן למעשה קוד Cשעבר תהליך של קומפילציה – כלומר הרצה של קוד Cבתוך .MATLAB את פונקציית ה MEX-ניתן לשלב באותה סביבת בדיקות שבה נבדק האלגוריתם המקורי .את אותן הפעולות שבוצעו על קוד ה MATLAB-ניתן לבצע גם על פונקציה זו ,ולהשוות בצורה מלאה ביניהן .כל שינוי בתוצאות המתקבלות מפונקציית ה MEX-מעיד על חוסר דיוק שהוכנס בהליך ההמרה ל .EML-המטרה היא לוודא שחוסר הדיוק הוא מספיק קטן בכדי שיהיה "זניח". יש להבין כי חוסר דיוק זה נובע מהמעבר מעבודה בסביבת מחשוב של 64ביט )עם Double (Precisionלסביבת עבודה הנמצאת לרוב ב 32-ביט ) .(Single Precisionלכן – שגיאות קוונטיזציה צפויות להתקבל. בשלב זה יש גם להחליט האם על המעבד הסופי שעבורו נייצר קוד הוא מסוג Floatאו .Fixed במידה והוא מסוג – Floatנוכל להמשיך לשלב הבא .אחרת ,עלינו לעבור שלב נוסף של המרת האלגוריתם לעבודה ב .Fixed-הליך זה יכול להיות קצר ביותר ע"י שימוש בFixed Point - ,Toolboxולאחר סיומו מצריך בדיקה נוספת של פונקציית MEXלמול ה,Golden Reference- בכדי לוודא שחוסר הדיוק הנובע מקוונטיזציה לא פגע באופן הפעולה של האלגוריתם. עמוד 24מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .5.1יצירת פונקציית MEX על מנת לייצר פונקציית ,MEXיש לוודא כי על עמדת המשתמש מותקן ה Simulink-או ה- .Fixed Point Toolbox הפקודה שמייצרת mexמתוך EMLהיא ,emlmexושימוש לדוגמא: >> emlmex -report -eg { myExamplePARAMS } myEMLFunction דוגמא זו מייצרת קוד Cמתוך הפונקציה ,myEMLFunctionו"עוטפת" אותו במעטפת מתאימה לצורך הרצתו בתוך סביבת .MATLAB במידה וקיימת בעיה כלשהי – פונקציה שאיננה נתמכת למשל – תוצאת הריצה תהיה דו"ח שמציג מהי מהות השגיאה והצעה לפתרונה. יש לשים לב ,כי על מנת לייצר ,MEXיש להגדיר קומפיילר נתמך באמצעות הפקודה: >> mex -setup ובחירה של קומפיילר מתאים .למערכות 32ביט ,מסופק יחד עם MATLABקומפיילר שכזה .LCC ,למערכות 64ביט ,יש להתקין קומפיילר מתוך רשימה של קומפיילרים נתמכים .רשימה זו ניתן למצוא ב- . http://www.mathworks.com/support/compilers/R2010b/index.html לאחר סיום יצירת פונקציית ה ,MEX-נוצר קובץ חדש ,בעל השם ,myEMLFunctionובעל הסיומת ) .mexw32למערכת הפעלה חלונות 32 ,ביט( .סיומת זו תשתנה ממערכת הפעלה אחת לשניה) .עבור מערכת הפעלה 64 Linuxביט ,תתקבל הסיומת .(mexa64 המלצה מס' 9 ניתן לייבא לתוך סביבת MATLABהן קבצי Cוהן קבצי Fortranשנכתבו בעבר .לקריאה נוספת על יכולת זו ,אשר עשויה לחסוך זמן רב בתהליך הפיתוח ,ניתן לקרוא ב: >> doc mex הסיומת ,MEXהינה בעלת קדימות גבוהה יותר מבחינת .MATLABלכן ,אם קיימים 2 קבצים ,אחד בעל הסיומת ,.mוהשני בעל הסיומת ,.mexw32הקובץ השני ייקרא לפני הראשון .לכן ,כשמייצרים את פונקציית ה ,MEX-מומלץ לתת לה שם ייחודי בעזרת הדגלון , -oלמשל: emlmex -eg { myExamplePARAMS } myFunction –o myMEXFunction כעת הקובץ החדש יהיה בעל השם הייחודי , myMEXFunction.mexw32ולא ייקרא במקום הקוד המקורי. בפרק 6מוצגת היכולת לייצור קוד Cמתוך ,EMLע"י השימוש בפקודה .emlcבאמצעות פקודה זו ניתן לייצר גם קוד ,MEXבאופן הבא: emlc -eg { myExamplePARAMS } myFunction –o myMEXFunction או ע"י: emlc –T MEX -eg { myExamplePARAMS } myFunction –o myMEXFunction עמוד 25מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB תוצאת פקודה זו הינה גם כן קובץ ,.mexw32אך כזה שנוצר ע"י שימוש ב .RTW-מאחר וקוד זה יעיל יותר ,ייתכנו שינויים בזמני ריצה ו/או ביצועים אחרים בהשוואה בין 2תוצרים אלו. .5.2בדיקה למול קוד המקור בפרק 4.11בוצעה בדיקה של קוד ה EML-למול קוד ה .MATLAB-ניתן להשתמש באותה סביבת הבדיקות על מנת לבדוק כי גם פונקציית ה MEX-מחזירה בדיוק את אותן התוצאות כמו ה .EML-בבדיקה זו ,אנו בודקים את קוד ה C-בצורה פונקציונלית ,כי הוא מבצע בדיוק את מה שציפינו ממנו. כאשר מיוצר קוד מתוך ה ,EML-מבוצעות מספר פעולות של אופטימיזציה ושל התאמת הקוד לפעולה יעילה יותר .לכן ,עלולה להתקבל התנהגות השונה מזו שציפינו .התנהגות זו, במידה ותתקבל ,תתרחש בסבירות גבוהה במקרי קצה של גדלי הנתונים השונים. .5.3בדיקת זמני ריצה של קוד ה MEX-והשוואה למקור אנשים רבים ברחבי העולם טוענים כי קוד Cרץ בצורה מהירה יותר מאשר .MATLAB עקב כך ,הציפייה היא שקוד MEXירוץ מהר יותר מאשר קוד המקור ,ולכן מושקע מעמץ בהאצת פעולת MATLABע"י המרת חלקים מהקוד ל.MEX- ככלל – הנחה זו אינה מתקיימת תמיד – ממספר סיבות: MATLABהינה שפה אשר עובדת כ - Interpreter-כלומר לוקחת את הקוד שנכתב, ומריצה אותו שלב אחר שלב -תוך קריאה לפונקציות המתאימות .בשנים האחרונות, השקיעה חברת MathWorksמשאבים רבים במטרה להאיץ את .MATLABזאת – ע"י מימוש מחדש של חלק גדול מאד מהפונקציות הבסיסיות והמתקדמות ,שימוש בספריות – (Basic Linear Algebra Subroutines) BLASמימוש מהיר יותר של פעולות מתמטיות, וכן שימוש נרחב יותר ויותר בפעולות – MultiThreadedכלומר מימוש מקבילי של הפונקציות. בעקבות עבודה נרחבת זו ,ניתן כיום לראות שיפורים משמעותיים בעבודה בגרסה חדשה של MATLABלעומת גרסאות ותיקות יותר .באחד המקרים בתעשיה ,נתגלה שיפור של כ 65%-בזמן הרצת הקוד ,מתוקף המעבר מגרסה R2006bלגרסה .R2009b המסקנה היא שגם אם נשלב פונקציות Cלתוך ,MATLABונריץ את כולן יחדיו – כנראה שעדיין MATLABתוכל לרוץ מהר יותר. חשוב לציין כאן כי כל השוואה בין זמני הריצה של קוד ה MATLAB-לקוד הממומש כ- MEXהיא גם חסרת תועלת – במידה וייוצר קוד ,Cהרי הוא יופעל על גבי מערכת הפעלה אחרת ,ישולב עם קוד נוסף ,או יועבר למעבד השונה מהמעבד עליו מותקנת .MATLABעל כן ,כל עוד לא נבחן את הקוד על מקומו הסופי – לא נדע בדיוק את מהירות הריצה שלו. ואף על פי כן – אם נבדוק את השינויים בזמני הרצת הקוד – למשל ,אם נשפר את קוד ה- EMLוקוד ה MEX-יואץ פי – 2אזי כנראה שגם על מעבד המטרה הקוד יעבוד מהר יותר. עמוד 26מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .6יצירת קוד מבחינה היסטורית ,טכנולוגיית יצירת הקוד של MathWorksפותחה על מנת להאיץ סימולציות של מאות ואלפי בלוקים בתוך .Simulinkלכן ,בכדי לייצר קוד מתוך ,MATLABנדרש רישיון זמין ל Simulink-ול.RTW- בפרק זה נדגים כיצד ניתן לייצר קוד מתוך MATLABעבור .EML יש לציין כי ניתן לשלב קוד EMLבתוך בלוקים של Embedded MATLAB Function Blocks כחלק מ .Simulink-טכנולוגיית יצירת הקוד מתוך Simulinkקיימת זמן רב יותר ,ולכן קיימות אפשרויות רבות יותר דרך הממשק הגרפי של .Simulinkבסביבת Simulinkניתן ,למשל ,להגדיר את חלוקת מרחבי הזיכרון למעבד המטרה. עם זאת ,גרסה R2010bשל MATLABמהווה קפיצת מדרגה בטכנולוגיה זו ,וכמעט כל האפשרויות זמינות גם ליצירת קוד מתוך MATLABבגרסה זו. הפקודה שמייצרת קוד מתוך EMLהיא ,emlcושימוש לדוגמא: emlc -report -eg { myExamplePARAMS } myEMLFunction –s rtwcfg דוגמא זו מייצרת קוד Cמתוך הפונקציה ,myEMLFunctionמייצרת דו"ח HTMLשל הקוד. במקרה זה ניתן לראות גם את הגדרות יצירת הקוד ,ע"י השימוש בדגלון –sכשלאחריו מופיע אובייקט הגדרות הקוד. במידה וקיימת בעיה כלשהי – פונקציה שאיננה נתמכת למשל – תוצאת הריצה תהיה דו"ח שמציג מהי מהות השגיאה והצעה לפתרונה. בטרם הגעה לשלב זה ,יש לוודא כי קוד ה MATLAB-מותאם ל ,EML-וכן בוצעו כל ההגדרות של הפרקים הקודמים. הגדרת טיפוסי המשתנים ,גודלם ושאר הפרמטרים -מבוצע באותו האופן כמו עבור הפקודה emlmexכפי שהוצג בפרק הקודם. כמו עבור יצירת MEXיש לשים לב כי על מנת לייצר קוד ,יש להגדיר קומפיילר נתמך באמצעות הפקודה: >> mex –setup .6.1תוצרים שונים מהפקודה emlc כשאנחנו בוחרים לייצר קוד בצורה אוטומטית ,אנחנו נדרשים לבחור גם את אופן יצירת הקוד ,כלומר באיזה פורמט היינו מעוניינים לקבל אותו ,בהתאם לצורכינו emlc .מאפשרת לנו לייצר קוד במספר סוגים: א .ייצור קוד – MEXתוצר הזהה לשימוש בפקודה ,emlmexרק שכעת הקוד יעיל יותר, וניתן לראות גם את קוד המקור שלו .זוהי ברירת המחדל. עמוד 27מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB ב .יצירת ספריה – – libהקוד הנוצר נעטף בספריה מתאימה. ג .יצירת קובץ עצמאי – – EXEהקוד נוצר ,מקומפל ומקושר בכדי לייצר קובץ עצמאי. בכדי לבחור את התוצר המתאים ,יש להשתמש בדגלון –Tבאופן הבא: %Generate mex-function )% Generate library )% Generate Standalone exe >> emlc –T mex myEMLFunction >> emlc –T rtw:lib myEMLFunction >> emlc –T rtw:exe myEMLFunction .6.2התאמה אישית של הקוד הנוצר )דגלון (–s הקוד נוצר בצורה אוטומטית ,ועל כן יש להגדיר כיצד היינו רוצים שהקוד ייראה בסוף התהליך .בחירת שפת הקוד ,שמות המשתנים ,הוספת הערות ,שליטה על אופטימיזציה, אופן אתחול והעתקת וקטורים וכדומה – כולם פרמטרים שניתן לשלוט עליהם. אופן ההתאמה ב MATLAB-נעשה ע"י שימוש ב 3-אובייקטים מתאימים ,אשר מאפשרים לשלוט על: א .אופן יצירת קוד ה .MEX-בעזרת האובייקט . emlcoder.MEXConfig ב .הגדרות ה .RTW-בעזרת האובייקט . emlcoder.RTWConfig ג .הגדרות חומרה עבור מעבד המטרה .זאת נבצע ע"י הגדרת האובייקט . emlcoder.HardwareImplementation אובייקטים אלו נוצרים בתוך ה Workspace-של ,MATLABוניתן כמובן לשמור אותם לקובץ ,.matולדאוג להעברתם מ session-ל session-וממשתמש למשתמש ,מבלי לדאוג לייצר אותם בכל פעם מחדש. 6.2.1שימוש בemlcoder.MEXConfig- הגדרת האובייקט>> mxcfg = emlcoder.MEXConfig : עריכת האובייקט>> open mxcfg : מתקבל המסך הבא ,בו אפשר להגדיר מספר רב של נתונים ואפשרויות. תחת ,Generalנקבע האם ברצוננו לאפשר שימוש בוקטורים בעלי גודל משתנה ,לאפשר שימוש ב ,BLAS-ולבחור האם למקם כל פונקציית MATLABשנוצרת לקובץ Cנפרד, או האם לשלב את כל הקבצים לקובץ בודד .כאן גם נבחר האם ברצוננו לייצר קוד Cאו .C++ תחת Optimizationו Advanced-מופיעים אובייקטי האופטימיזציה – למשל קביעת ספים ל inline-של פונקציות ,שימוש ב memcpy-וב ,memset-ועוד. אם ברצוננו להוסיף הערות ותיעוד לקוד המיוצר ,נוכל לשלוט על כך ב report-וב- .comments עמוד 28מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB מסך הגדרות הemlcoder.MEXConfig- 6.2.2שימוש בemlcoder.RTWConfig- הגדרת האובייקט>> rtwcfg = emlcoder.RTWConfig : עריכת האובייקט>> open rtwcfg : מתקבל המסך הבא ,בו אפשר להגדיר מספר רב של נתונים ואפשרויות. תחת ,Generalנקבע האם ברצוננו לאפשר שימוש בוקטורים בעלי גודל משתנה ,לאפשר שימוש ב ,BLAS-ולבחור האם למקם כל פונקציית MATLABשנוצרת לקובץ Cנפרד, או האם לשלב את כל הקבצים לקובץ בודד .כאן גם נבחר האם ברצוננו לייצר קוד Cאו .C++ תחת Interfaceמצויות מספר הגדרות מאד משמעותיות ,ביניהן בחירת הTarget - ) ,Function Library (TFLתמיכה במספרים ,Floatingהגדרת פונקציית Terminate ועוד. במידה וברצוננו לשלוט ולדאוג לאופטימיזציה גבוהה יותר של הקוד ,נוכל לעשות זאת ע"י שימוש ב .RTW-EC-בכדי לייצר את האובייקט המתאים ,יש להגדירו באופן הבא: עמוד 29מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB )'>> rtwcfg = emlcoder.RTWConfig('ert מסך הגדרות הemlcoder.RTWConfig('ert')- 6.2.3שימוש בemlcoder.HardwareImplementation- הגדרת האובייקט>> hwcfg = emlcoder.HardwareImplementation : עריכת האובייקט>> open hwcfg : באמצעות אובייקט זה ניתן לבחור את ארכיטקטורת המעבד והיצרן שעבורו ברצוננו לייצר קוד. בחירה ביצרן מסויים מגדירה לנו את ארכיטקטורת יצירת הקוד ,שימוש ב Little-או BigEndianוכדומה. במידה ויש גישה ל ,Target Support Package-במסך זה יהיה מספר גדול יותר של אפשרויות ומעבדים שונים. עמוד 30מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB מסך הגדרות הemlcoder.HardwareImplementation- במידה וברצוננו להשתמש במספר אובייקטים ,נוכל לשרשר אותם: >> emlc –T rtw:lib myEMLFunction –s rtwcfg –s hwcfg עמוד 31מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .6.3שימוש בדו"ח יצירת הקוד כחלק מהליך יצירת הקוד ,מיוצר דו"ח מפורט המציג מספר נתונים מרכזיים: .1נתונים כלליים על מועד יצירת הקוד ,סיכום התהליך. .2מסך סיכום נתונים על הפרמטרים שהוגדרו בקוד ובממשק אליו – האם הם ממשיים או מרוכבים ,גודל ,טיפוס וכדומה. .3מסך על מעבד המטרה שעבורו נוצר הקוד. .4מסך קוד המקור שממנו נוצר קוד ה.C- .5אופן הקריאה לכל הפונקציות שמהן נוצר הקוד. .6הקוד המיוצר בחלוקה לפונקציות ,עם ניווט מהיר להגדרות הפרמטרים השונים. דו"ח זה מפשט ומקל על אופן בחינת הקוד והגדרתו ,ניתן לייצוא למסמך wordוpdf- וכמובן לבחינה בסקרי תכנון שונים. .6.4המלצות לייצור הקוד 6.4.1כפי שהוצג קודם ,ישנן אפשרויות רבות יותר לשליטה על הקוד באמצעות .Simulinkמאחר ומבחינה רישיונית בכל מקרה נעשה שימוש ב ,Simulink-הרי שמומלץ להשתמש בה כסביבת יצירת קוד .משתמשים רבים ב RTW-משתמשים בSimulink- כסביבת בדיקות וכסביבת יצירת קוד ולא כסביבת הפיתוח )למרות היתרונות הרבים שלה(. 6.4.2תהליך יצירת הקוד יכול להיות מאד מורכב וארוך .על כן ,מומלץ להיעזר במשתמש שכבר עבר הליך זה בעבר ,או ביועץ/מהנדס אפליקציה של נציג MathWorksבארץ. עמוד 32מתוך 33 קווים מנחים ליצירת קוד Cמתוך MATLAB .7סיכום השימוש ב Embedded MATLAB-ותהליך יצירת הקוד מסיר את הצורך לקודד ,לתחזק ולבדוק קוד שנכתב בצורה ידנית .סבבי הפיתוח מתקצרים כתוצאה מכך ,ומאפשרים להתמקד בשיפור וייעול התכנון במקום לתחזק עותקים כפולים של קוד שנכתבו בשפות שונות. במסמך זה הוצג תהליך העבודה הנדרש לצורך התאמת קוד המקור ל ,EML-כיצד ניתן לבדוק את הקוד מבחינה פונקציונלית ולוודא כי הוא מבצע את הנדרש ממנו ,כיצד ניתן לייצר קוד C/C++בצורה אוטומטית ,וכיצד ניתן להתאימו למעבד המטרה. חשוב לציין כי טכנולוגיה זו התפתחה בשנים האחרונות ,והיא ממשיכה להתפתח ולהיות יעילה יותר עם התקדמות הגרסאות .יכולות רבות נוספו בגרסאות האחרונות של התוכנה ,אשר לא היו זמינות בעבר ,ומומלץ לקורא להתעדכן מפעם לפעם על החידושים בגרסאות האחרונות בתחום זה. תהליך יצירת הקוד יכול להיות מאד מורכב וארוך .על כן ,מומלץ להיעזר במשתמש שכבר עבר הליך זה בעבר ,או ביועץ/מהנדס אפליקציה של חברת MathWorksבארץ. יש לציין כי מפעם לפעם נערכים סמינרים חופשיים אשר עוסקים בטכנולוגיית יצירת הקוד מתוך MATLABואופן שילובו ובדיקתו בתהליכי הפיתוח .במידה ותחום זה חשוב ויכול לתרום לחברתך – מומלץ להגיע. עמוד 33מתוך 33
© Copyright 2024