หน้าเว็บ

วันอาทิตย์ที่ 28 เมษายน พ.ศ. 2556

สร้าง Wafer Map ด้วย ruby และ Cairo

Wafer Probe หรือ Wafer Sort เป็นขั้นตอนที่สำคัญขั้นตอนหนึ่งของกระบวนการผลิต IC chip โดยจะเป็นการนำ Silicon Wafer ที่ทำการขึ้นลายวงจรเรียบร้อยแล้วมาทดสอบ "ได"(Die, ตัว chip ที่ยังอยู่บนแผ่น Wafer โดยยังไม่ได้ถูกตัดออกมาเป็นชิ้นๆ) ที่อยู่บน Wafer นั้นว่าดีหรือเสีย ซึ่งหลังจากทดสอบไดทุกตัวบนเวเฟอร์เรียบร้อยแล้ว เราจะได้ soft file ซึ่งระบุตำแหน่ง coordinate x,y และสถานะของไดที่ถูก probe ไปแล้วว่าตำแหน่ง coordinate นั้นๆ เป็นไดที่ดีหรือเสีย ไฟล์ที่ว่าอาจเป็น text file ง่ายๆ ซื่งผมขอเรียกมันว่า coordinate file แล้วกันครับ

อันนี้่คือตัวอย่างของแผ่นซิลิกอนเวเฟอร์จริงครับ


วันนี้เราจะทดลองนำไฟล์ coordinate มาใช้ในการสร้างกราฟฟิกในรูปของ Wafer map image file
Wafer map ที่เราต้องการจะมีหน้าตาประมาณนี้ครับ สีเขียวที่เห็นคือไดที่ดี (good die) ส่วนสีอื่นๆคือไดเสีย (rejected die) ซึ่งสีที่ต่างกันแสดงถึงสาเหตุของอาการเสียที่แตกต่างกันออกไป





Coordinate file
ไฟล์ coordinate ประกอบด้วยตำแหน่งของไดในแกน x/y และผลการทดสอบไดจากกระบวนการ Wafer Probe ซึ่งจะแสดงในรูปของ บินโค้ด(bin code) โดยทั่วไป บินโค้ด bin1 จะหมายถึงไดที่ดี ส่วนบินโค้ดอื่นๆจะหมายถึงไดเสีย
ตัวอย่างของไฟล์ coordinate เป็นดังนี้



หลังจากกระบวนการ Wafer Probe เสร็จสิ้นลงแล้วไฟล์ "Wafer map" จะถูกสร้างขึ้น
โดยทั่วไปไฟล์ Wafer map จะเป็น text file ที่ระบุตำแหน่งของ die และ bincode ของ die ที่ตำแหน่งนั้นๆ ซึ่งไฟล์ Wafer map จะถูกใช้เป็น reference เพื่อให้เครื่องจักรสามารถเลือกหยิบเฉพาะไดที่ดี ในตำแหน่งที่ถูกต้องไปใช้ ในกระบวนการผลิตไอซีขั้นต่อๆไป

แต่แทนที่จะนำข้อมูลที่เรามีอยู่จาก coordinate file มาใช้เพื่อสร้างไฟล์ Wafer map ที่เป็น text file เราจะสร้าง Wafer map ให้ออกมาอยู่ในรูปของ image file แทน โดยใช้ graphic library  ที่ชื่อว่า Cairo

Cairo
Cairo เป็น 2D graphic library ที่ใช้สร้างรูปภาพที่อยู่ในรูปแบบของ vector graphic โดย vector graphic จะแตกต่างจากรูปภาพดิจิตอลในระบบคอมพิวเตอร์ทั่วๆ ไปตรงที่รูปภาพที่เป็น vector graphic จะถูกสร้างขึ้นมาจากสมการทางคณิตศาสตร์ทั้งสิ้น ในขณะที่รูปภาพทั่วๆ ไปเกิดจากการรวมตัวกันของ pixel สีต่างๆกันจนเป็นรูปภาพ

รูปภาพแบบ vector กับรูปภาพทั่วๆไป (raster graphic) นั้นมีข้อดีข้อด้อยของตัวเอง แต่ในที่นี้ผมขอสรุปเฉพาะข้อดีของรูปแบบ vector เมื่อเทียบกับรูปภาพทั่วไป ดังนี้
- ขนาดของไฟล์เล็กกว่า(มาก) เมื่อขนาดของรูปใหญ่ขึ้น
- สามารถย่อขยาย หมุน, พลิก หรือปรับเปลี่ยนลักษณะของรูปได้ โดยไม่ทำให้รูปสูญเสียความละเอียดหรือคุณภาพของรูปไปแต่อย่างใด
ลองเข้าไปดูรายละเอียดเพิ่มเติมได้ที่ official site ของ Cairo นะครับ

Cairo เป็น library ที่สร้างจากภาษา C แต่ถูกนำมาแปลถ่ายเป็น library ที่ support ภาษาอื่นๆ อีกหลายภาษา
สำหรับ ruby นั้นเรามี rcairo เป็น binding library โดยอยู่ในรูปของ gem package
ขั้นตอนการ install rcairo ลงใน Windows มีดังนี้


1) เปิด command windows โดยพิมพ์ cmd ที่ Run menu
2) ที่ command line, พิมพ์ gem install rcairo

หลักการใช้ Cairo ในการวาดรูป
ก่อนอื่นเราควรทำความเข้าใจกันสักนิดว่า Cairo สร้างรูปภาพแบบ vector ขึ้นมาได้อย่างไร และมันทำงานอย่างไรบ้าง


สรุปแบบสั้นๆ เลยนะครับ
รูปภาพแบบ vector ที่ถูกสร้างด้วย Cairo จะประกอบด้วยส่วนสำคัญ 3 ส่วน ได้แก่ Context (แบบร่าง), Surface (พื้นผิว), Path (เส้น) และ Source (แหล่งสี)

Context คือแบบร่างของรูปที่เราต้องการวาดซึ่ง context จะเก็บเนื่อหา รูปแบบรวมถึงลักษณะของเส้นและสีที่จะถูกวาดลงบน Surface เช่น จะต้องระบุลงไปว่า จะวาดรูปลงบนพื้นผิวลักษณะใด วาดด้วยเส้นแบบไหน วาดอย่างไรในตำแหน่งทิศทางใด ลงสีอย่างไรเป็นต้น

ซึ่ง Surface ก็คือพื้นผิวของรูปที่่้เราจะทำการวาดรูปลงไป ส่วนลักษณะของเส้นหรือสีในแบบต่างๆ จะถูกกำหนดด้วย Path และ Source ตามลำดับ

เพื่อให้เห็นภาพการทำงานของ Cairo เรามาดูตัวอย่างกันเลยดีกว่า
ตัวอย่างแรก ง่ายสุดๆ เราจะวาดรูปสี่เหลี่ยม ลงสี แล้ว save รูปที่วาดออกมาเป็นไฟล์รูปภาพ นามสกุล png

Ex1: stoke.rb

require 'cairo'

format = Cairo::FORMAT_ARGB32

surface = Cairo::ImageSurface.new(format, 120, 120)
context = Cairo::Context.new(surface)

context.set_line_width(10)
context.set_source_rgb(0,0.85,0)
context.rectangle(0, 0, 120, 120)
context.fill_preserve

context.set_source_rgb(0,0.5,0)
context.stroke

surface.write_to_png("stroke.png")


ตัวอย่างที่เห็นในโค้ด stoke.rb เป็นการวาดสี่เหลี่ยมสีเขียวอ่อน ขนาด 120x120 pixcel แล้วตัดเส้นด้วยสีเขียวเข้มขนาด 10pixel แล้ว save รูปเป็นไฟล์ png

ขั้นตอนในการสร้างรูปภาพจากโค้ดข้างต้นค่อนข้างเข้าใจได้ง่าย โดยจะเริ่มจากการสร้าง context ขึ้นมาเป็นอันดับแรก แล้วระบุว่า context ของเราสร้างอยู่บน surface แบบใด โดยจะเห็นได้จากโค้ดในบรรทัดที่ 5-6
ในที่นี้ surface ของเราคือ FORMAT_ARGB32 ซึ่งหมายถึงพื้นผิวที่้เป็นรูปภาพแบบ RGB ในขนาดความละเอียดของสีที่ 32bit pixel พร้อม alpha color.

ขั้นตอนถัดมาคือการกำหมดแบบร่างลงบน context
โค้ดในบรรทัดที่ 8-14 เป็นการกำหมดแบบร่างซึ่งก็คือแบบร่างของสี่เหลี่ยมสีเขียวของเรานั่นเอง ขั้นตอนนี้ทำได้โดยการเรียกใช้เมธอดจาก context ดังนี้

  • เมธอด set_line_width ในบรรทัดที่ 8 กำหนดค่าเส้นที่ต้องการวาดให้มีขนาดเท่ากับ 10 pixel
  • เมธอด set_source_rgb ในบรรทัดที่ 9 กำหนดค่าสี ณ ปัจจุบันของ source ซึ่ง parameter ของเมธอดนี้คือค่าสีในแบบ RGB
  • เมธอด regtangle ในบรรทัดที่ 10 ใช้ร่างแบบรูปสี่เหลี่ยมผืนผ้า โดยรูปแบบของเมธอดมีดังนี้ 
rectangle(x,y,width, height) x, y คือตำแหน่งมุมซ้ายบนใน coordinate x,y ของรูปสี่เหลี่ยมที่จะวาด 
width คือความกว้างูปสี่เหลี่ยม
height คือสูงของรูปสี่เหลี่ยม


  • เมธอด fill_reserve ในบรรทดที่ 11 ส่งห้วาดแบบร่างามค่าที่ถูกกำหนอยู่ในปัจจุบัน โดยจะลงสีเฉพาะบริเวณที่อยู่ใน path ของแบบร่างเท่านั้น
  • เมธอด stoke ในบรรทดที่ 14 ทำหน้าที่วาดแบบร่างของเส้นลงบน surface โดยเฉพาะ เส้นที่ทำการ "stoke" ลงไปนั้นจะมีลักษณะหนาบางหรือคุณลักษณะอื่นามแต่จะกำหนด ในที่นี้จะ stoke ด้วยเส้นที่มีความหนาเท่ากับ 10 pixel ตามที่ได้กำหนดไว้ก่อนหน้านี้

หลังจากที่วาดแบบร่างทุกอย่างลงบน surface ของ context เรยบร้อยแล้ว ก็จะ save ออกมเป็นไฟล์ png ด้วยเมธอด write_to_png ในบรรทัดสุดท้าย 

เพื่อให้เห็นภาพชัดขั้นลองดูต้วอย่างถ้ดไป ซึ่งจะเป็นการวาดรูปธงชาติไทย ดังโค้ดต่อไปนี้ครับ

thaiflag.rb
require 'cairo'

w = 300
h = 200

surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, w, h)  # define surface
context = Cairo::Context.new(surface)       # create context from given surface

# specify details how to draw on to context
context.set_source_rgb(1,1,1)  # set source to color WHITE
context.rectangle(0,0,w,h)   # define white color for the whole flag first
context.fill      # draw it

context.set_source_rgb(1, 0, 0)  # set source to color RED
context.rectangle(0,0,w,30)   # define where the red first strip is located
context.rectangle(0,170,w,30)  # define where the second first strip is located
context.fill      # draw it

context.set_source_rgb(0, 0, 1)  # set source to color BLUE
context.rectangle(0,60,w,80)  # define where the blue strip is located
context.fill      # draw it

# save it to png image
surface.write_to_png("thaiflag.png")

เราจะได้ธงไตรรงค์ที่สวยงามหลังจาก run โค้ด thaiflag.rb



จากโค้ดในบรรทัดที่ 6-7 เราจะเริ่มจากการสร้าง context ขึ้นมาก่อนเช่นเคย โดยระบุว่า context ของเราอยู่บน surface แบบ FORMAT_ARGB32

ต่อเป็นการเป็นการกำหนดแบบร่างลงไปบน context ในบรรทัดที่ 9-21 โดยการเรียกใช้เมธอดต่างๆ จาก context ดังนี้
  • เมธอด set_source_rgb(r,g,b) ทำหน้าที่ตั้งค่าสี ณ ปัจจุบัน
  • เมธอด regtangle(x,y,width, height) ใช้ร่างแบบรูปสี่เหลี่ยมผืนผ้า เหมือนตัวอย่างก่อนหน้า แต่ในครั้งนี้เราจะร่างรูปสี่เหลี่ยมหลายรูปในตำแหน่งที่ต่างกันตามสีของธงชาติ
  • เมธอด fill ทำการลงสีลงบน surface าม path ที่ระบุอยบนแบบร่าง หลังจากที่เรียกเมธอด fill มาใช้ในแต่ละครั้งเราก็จะได้สีเหลี่ยมผืนผ้าตามสีต่างๆบน surface เมธอด fill และ fill_preserve ต่างกันตรงที่ fill_preserve จะไม่ลงสีไปทับีหรือขนาดของเส้นของ path ที่เราได้ระบุเอาไว้ก่อนหน้า
ส่วนขั้นตอนสุดท้าย ก็เรียกใช้เมธอด write_to_png เพื่อ save รูปที่เราวาด ออกมาเป็นไฟล์นามสกุล png เหมือนเคย


เป็นอย่างไรครับ ผ่านไป 2 ตัวอย่าง น่าจะเริ่มจับทางได้แล้ว
ทีนี้มาดูตัวอย่างสุดท้ายที่น่าสนใจขึ้นสักนิด โดยเราจะใช้ Cairo วาดโลโก้ของทีวีสีช่อง 7 ทีวีเพื่อคุณที่เราคุ้นเคย

tv7.rb
require 'cairo'

w = 150
h = 150

surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, w, h)
surface1 = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, w, h)
surface2 = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, w, h)
surface3 = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, w, h)

context = Cairo::Context.new(surface)
context1 = Cairo::Context.new(surface1)
context1.set_source_rgb(0.85, 0, 0)
context1.arc(50, 50, 50, 0, 2*Math::PI)

context1.fill
context2 = Cairo::Context.new(surface2)
context2.set_source_rgb(0, 0, 0.85)
context2.arc(100, 50, 50, 0, 2*Math::PI)
context2.fill

context3 = Cairo::Context.new(surface3)
context3.set_source_rgb(0, 0.85, 0)
context3.arc(75, 100, 50, 0, 2*Math::PI)
context3.fill

context1.set_operator(Cairo::OPERATOR_ADD)
context1.set_source(surface2)
context1.paint

context1.set_operator(Cairo::OPERATOR_ADD)
context1.set_source(surface3)
context1.paint

context.set_source(surface1)
context.paint

context.set_source_rgb(0, 0, 0)
context.select_font_face("Arial", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD)
context.set_font_size(34)
context.move_to(68, 80)
context.show_text("7")

# save it to png image
surface.write_to_png("composit.png")

จากโค้ดข้างต้น จะเห็นว่าขั้นตอนของการสร้างรูปโดยรวมยังคงเหมือนเดิมคือ มีการสร้าง context ออกแบบแบบร่าง วาดลง surface แล้ว save ออกมาเป็นรูป
ที่แตกต่างออกไปจะเป็นการใช้เทคนิก composition เพื่อผสมผสานรูปบน surface มากกว่าหนึ่ง surface เข้าด้วยกันเพื่อให้ได้รูปใหม่ๆ ออกมา

จะเห็นว่าในบรรทัดที่ 6-9 มีการสร้่าง surface ขึ้นมา 4 ชิ้นโดยแต่ละชิ้นจะถูกนำไปใช้เพื่อสร้าง context ออกมา 4 แบบเช่นกัน โดย context1, context2 และ context3 จากบรรทัดที่ 12-25 จะเป็นแบบร่างของวงกลมสีแดง น้ำเงิน และเขียวตามลำดับ
วงกลมสามารถร่างขึ้นมาจากเมธอด arc ซึ่งรูปแบบการใข้เมธอดมีดังนี้

arc(x, y, radius, angle1, angle2)
x = ตำแหน่ง x ของจุดศูนย์กลางของวงกลม
y = ตำแหน่ง y ของจุดศูนย์กลางของวงกลม
radius = ระยะรัศมีของวงกลม
angle1 = องศาเริ่มต้นของวงกลมที่ต้องการวาดในหน่วย radian
angle2 = องศาสิ้นสุดของวงกลมที่ต้องการวาด ในที่นี้ได้แก่ 2 x PI (180 degree)

เมื่อได้วงกลม 3 สีทั้งสามวงแล้วเราจะนำมันมารวมกันโดยการ composite surface แต่ละชิ้นเข้าด้วยกัน ซึ่งมีขั้นตอนดังนี้
กำหนดโหมดของการ composite ให้เป็นแบบรูปซ้อนรูป จาก context1.set_operator(Cairo::OPERATOR_ADD) ในบรรทัดที่ 27 จากนั้น ระบุของ surface ที่ต้องการจะรวมกับ surface ของ context ปัจจุบันด้วยเมธอด set_source(surface1) ซึ่งเราจะเห็นว่าตอนนี้ source ของเราไม่จำเป็นต้องเป็น สี หรือ path เสมอไป สามารถเป็น surface ซึ่งหมายถึงแบบร่างทั้งหมดที่อยู่บน surface ได้ด้วย

ขั้นตอนต่อไปก็ใช้เมธอด paint เพื่อระบาย source ในปัจจุบันลงบน surface ของ context ที่เราเรียกเมธอด paint ออกมา

จากบรรทัดที่ 27-37 จะพบว่าสุดท้ายแล้ว surface1, surface2 และ suface3 จะถูก "paint" ทับๆ กันลงบน "surface" ของ "context" ซึ่งเป็น แบบร่างสุดท้าย

สุดท้ายอย่าลืมเขียนเลข 7 ลงไปตรงกลางวงกลมทั้งสามวง ซึ่งทำได้โดยโค้ด บรรทัดที่ 40-43
เท่านี้เป็นอันเสร็จ ซึ่งจะได้ผลลัพธ์หลังการ run โค้ด ดังนี้ครับ




ตอนนี้ผมว่าเราน่าจะพอเห็นภาพและเริ่มคุ้นเคยกับ Cairo กันแล้ว
ครั้งหน้าเราจะนำ Cairo ไปใช้ในการสร้าง Wafer map กัน
ครั้งนี้ลาไปก่อน แล้วเจอกันใหม่เร็วๆ นี้ครับ

ไม่มีความคิดเห็น:

แสดงความคิดเห็น