পাঠ ২১ · ৫৭-এর মধ্যে · মডিউল ৫
Home / Courses / Microprocessors, Embedded Systems & IoT / ডিজিটাল-টু-অ্যানালগ কনভার্সন (DAC)

ডিজিটাল-টু-অ্যানালগ কনভার্সন (DAC)

Digital-to-Analog Conversion (DAC)
৯ মিনিট পড়া মধ্যম · Intermediate Python সিমুলেশনসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • DAC কী এবং ADC-এর সাথে এর সূত্রগত সম্পর্ক
  • একটি ডিজিটাল কোড থেকে অ্যানালগ আউটপুট ভোল্টেজ গণনার সূত্র
  • দুই ভিন্ন রেজোলিউশনে একই কোডের আউটপুট ভোল্টেজ তুলনা
  • একটি সত্যিকারের সফটওয়্যার সাইন-ওয়েভ DAC আউটপুট সিমুলেশন, math.sin দিয়ে যাচাই করা

১ · DAC — ADC-এর বিপরীত দিক

L20-এ আমরা দেখেছি ADC কীভাবে একটি অ্যানালগ ভোল্টেজকে ডিজিটাল কোডে রূপান্তর করে। DACDigital-to-Analog Converterএকটি পেরিফেরাল যা একটি ডিজিটাল কোড ইনপুট নিয়ে তার প্রতিনিধিত্বকারী অ্যানালগ ভোল্টেজ আউটপুট পিনে তৈরি করে। ঠিক তার বিপরীত কাজ করে — একটি ডিজিটাল কোড ইনপুট হিসেবে নিয়ে, সেই কোডের সাথে মিলে যাওয়া অ্যানালগ ভোল্টেজ পিনে তৈরি করে দেয়। বাস্তব ব্যবহার: অডিও আউটপুট, সফটওয়্যার-জেনারেটেড ওয়েভফর্ম, নির্ভুল রেফারেন্স ভোল্টেজ তৈরি করা।

ডিজিটাল কোড (Discrete, n-bit) DAC (code × step size) অ্যানালগ ভোল্টেজ (step-approximated)
DAC ঠিক ADC-এর বিপরীত দিকে কাজ করে — কোডকে স্টেপ সাইজ দিয়ে গুণ করে সেই ধাপে থাকা অ্যানালগ ভোল্টেজ তৈরি করে।

২ · আউটপুট ভোল্টেজের সূত্র

L20-এর একই স্টেপ-সাইজ সূত্র এখানেও প্রযোজ্য:

$$ \Delta = \dfrac{V_{ref}}{2^{n}} $$

কিন্তু এবার গণনার দিক উল্টো — একটি ডিজিটাল কোড $D$ থেকে সরাসরি আউটপুট ভোল্টেজ বের করা হয় গুণ করে, ভাগ করে নয়:

$$ V_{out} = D \times \Delta $$

যেহেতু DAC-ও সসীম সংখ্যক ধাপেই আউটপুট দিতে পারে (কোনো ইন-বিটুইন মান নয়), DAC-এর আউটপুটও একটি "ধাপে-ধাপে" (step-approximated) অ্যানালগ সিগন্যাল — একদম মসৃণ অ্যানালগ ভোল্টেজ নয়, বরং তার একটি নিখুঁত ধারণা।

Python
def dac_output_voltage(code, vref, bits):
    step_size = vref / (2 ** bits)
    return code * step_size


vref = 3.3

for bits in (8, 10):
    step_size = vref / (2 ** bits)
    max_code = (2 ** bits) - 1
    print(f"--- {bits}-bit DAC (Vref={vref}V, স্টেপ সাইজ Δ={step_size:.6f}V) ---")
    for code in (0, max_code // 4, max_code // 2, max_code):
        v_out = dac_output_voltage(code, vref, bits)
        print(f"  code={code:4d} / {max_code:4d}  ->  আউটপুট ভোল্টেজ = {v_out:.4f} V")
    print()

    
লক্ষ্য করুন code=max_code // 2-এর জন্য দুই রেজোলিউশনেই আউটপুট ভোল্টেজ প্রায় $V_{ref}/2$ হচ্ছে (মাঝামাঝি কোড মানে মাঝামাঝি ভোল্টেজ) — কিন্তু ১০-বিট DAC ৮-বিট DAC-এর চেয়ে অনেক বেশি সূক্ষ্ম মধ্যবর্তী মান দিতে পারে, কারণ এর স্টেপ সাইজ চারভাগের এক ভাগ (L20-এর একই যুক্তি, উল্টো দিকে প্রযোজ্য)।

৩ · একটি সফটওয়্যার সাইন ওয়েভ

DAC-এর একটি সাধারণ বাস্তব ব্যবহার হলো একটি ওয়েভফর্ম (যেমন অডিও টোন) তৈরি করা — ফার্মওয়্যার একের পর এক DAC কোড দ্রুত পাঠায়, যেখানে প্রতিটি কোড একটি সাইন কার্ভের একটি নির্দিষ্ট বিন্দুর সবচেয়ে কাছের কোয়ান্টাইজড মান প্রতিনিধিত্ব করে। নিচের কোড সেলে একটি সম্পূর্ণ সাইন চক্রের কয়েকটি বিন্দুর জন্য math.sin দিয়ে টার্গেট ভোল্টেজ গণনা করে, প্রতিটিকে নিকটতম DAC কোডে রূপান্তর করে, এবং কোডের মান বার-চার্ট আকারে প্রিন্ট করে দেখানো হয়েছে যে এটি সত্যিই একটি সাইন আকৃতি তৈরি করছে (উঠছে, চূড়ায় পৌঁছাচ্ছে, নামছে, তলানিতে যাচ্ছে)।

Python
import math


def dac_output_voltage(code, vref, bits):
    step_size = vref / (2 ** bits)
    return code * step_size


def voltage_to_code(voltage, vref, bits):
    step_size = vref / (2 ** bits)
    max_code = (2 ** bits) - 1
    code = round(voltage / step_size)
    return max(0, min(code, max_code))


vref = 3.3
bits = 8
n_points = 16
max_code = (2 ** bits) - 1

print(f"{n_points}-পয়েন্ট সফটওয়্যার সাইন ওয়েভ ({bits}-bit DAC, Vref={vref}V):\n")

for i in range(n_points):
    angle_rad = 2 * math.pi * i / n_points
    # DAC ইউনিপোলার (শুধু ০ থেকে vref) তাই সাইনকে vref/2 কেন্দ্র করে অফসেট করা হচ্ছে
    target_voltage = (vref / 2) + (vref / 2) * math.sin(angle_rad)
    code = voltage_to_code(target_voltage, vref, bits)
    actual_voltage = dac_output_voltage(code, vref, bits)
    bar = "#" * round(code / max_code * 40)
    print(f"i={i:2d}  angle={math.degrees(angle_rad):6.1f}°  টার্গেট={target_voltage:.3f}V  "
          f"code={code:3d}  আউটপুট={actual_voltage:.3f}V  {bar}")

    
মূল কথা · Key takeaway

i=0-এ ($0°$) সাইন মান ০, তাই টার্গেট ভোল্টেজ $V_{ref}/2$ (মাঝামাঝি) — বার-চার্ট মাঝারি দৈর্ঘ্যের। i=4-এ ($90°$) সাইন মান $+1$, টার্গেট $V_{ref}$ (সর্বোচ্চ) — বার-চার্ট দীর্ঘতম। i=12-এ ($270°$) সাইন মান $-1$, টার্গেট $0V$ (সর্বনিম্ন) — বার-চার্ট প্রায় শূন্য। এই ওঠা-নামার প্যাটার্নই একটি প্রকৃত সাইন আকৃতির প্রমাণ। বাস্তব ফার্মওয়্যারে অবশ্য প্রতিবার math.sin (বা C-এর sin()) কল করা কম্পিউটেশনালি ব্যয়বহুল হতে পারে — তাই প্রায়ই একটি প্রি-কম্পিউটেড সাইন লুকআপ টেবিল ব্যবহার করা হয়, রিয়েল-টাইমে গণনা করার বদলে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ সাইন ওয়েভ কোড সেলে সাইনকে vref/2 দিয়ে অফসেট করা হয়েছে কেন — সরাসরি vref/2 * math.sin(angle) কেন ব্যবহার করা হয়নি?

কারণ math.sin() $-1$ থেকে $+1$ পর্যন্ত মান দেয়, যার মানে অফসেট ছাড়া টার্গেট ভোল্টেজ নেগেটিভ হয়ে যেত (যেমন $angle=270°$-এ $-V_{ref}/2$)। কিন্তু এই লেসনের DAC ইউনিপোলার — এটি শুধু $0$ থেকে $V_{ref}$ রেঞ্জের ভোল্টেজ দিতে পারে, নেগেটিভ ভোল্টেজ নয়। তাই সাইনকে $V_{ref}/2$ দিয়ে "উপরে ঠেলে" পুরো ওয়েভফর্মটাকে $0$ থেকে $V_{ref}$ রেঞ্জের মধ্যে আনা হয়েছে — এটি বাইপোলার সিগন্যালকে ইউনিপোলার DAC-এ চালানোর একটি প্রমিত কৌশল।

প্র ০২ n_points ১৬ থেকে বাড়িয়ে ৬৪ করলে সাইন ওয়েভের "মানের" কী উন্নতি হবে?

n_points বাড়ালে প্রতি চক্রে বেশি বিন্দু নেওয়া হয়, ফলে আসল অবিচ্ছিন্ন সাইন কার্ভের তুলনায় ধাপে-ধাপে আকৃতিটা আরও মসৃণ (সূক্ষ্ম কৌণিক রেজোলিউশনে) দেখাবে — একে টেম্পোরাল রেজোলিউশন বলা যায়, DAC-এর নিজস্ব বিট-রেজোলিউশনের (স্টেপ সাইজের) থেকে আলাদা একটি ধারণা। তবে এটি ঐ ওয়েভফর্মের কম্পাঙ্ক (frequency)-ও প্রভাবিত করবে যদি প্রতি পয়েন্টে সময় স্থির রাখা হয় — বাস্তব ফার্মওয়্যারে এই দুটো (স্যাম্পল সংখ্যা ও আউটপুট রেট) সাবধানে একসাথে ঠিক করতে হয়।

প্র ০৩ DAC-এর V_out = D × Δ সূত্র আর ADC-এর D = round(V_in / Δ) সূত্র — এই দুটো ঠিক একে অপরের বিপরীত কেন?

কারণ ADC আর DAC একই "গ্রিড" ধারণার উপর কাজ করে, শুধু বিপরীত দিক থেকে — ADC একটি অ্যানালগ মানকে গ্রিডের নিকটতম বিন্দুর ইনডেক্স (কোড) খুঁজে বের করে (ভাগ + রাউন্ড), আর DAC একটি ইনডেক্স (কোড) থেকে সেই গ্রিড-বিন্দুর প্রকৃত মান ফিরিয়ে দেয় (গুণ)। এই কারণেই L20-এর কোয়ান্টাইজেশন এরর ধারণাও DAC-এর ক্ষেত্রে প্রযোজ্য — একটি DAC কোড কখনও আসল টার্গেট ভোল্টেজের সাথে নিখুঁতভাবে না মিলে, সেই একই স্টেপ-সাইজ সীমার মধ্যে কাছাকাছি থাকে।

অনুশীলন

  1. চিন্তা করুন: একটি ১২-বিট DAC-এ (vref=3.3) code=2048 দিলে আউটপুট ভোল্টেজ কত হবে বলে আপনার ধারণা? কোড সেলে বসিয়ে যাচাই করুন।

    স্টেপ সাইজ $\Delta = 3.3 / 2^{12} = 3.3/4096 \approx 0.0008057$V। যেহেতু $2048$ ঠিক $2^{12}/2 = 2048$ (মাঝামাঝি কোড), আউটপুট হবে $V_{out} = 2048 \times 0.0008057 \approx 1.65$V — অর্থাৎ প্রায় ঠিক $V_{ref}/2$, যেমনটা প্রথম কোড সেলের মাঝামাঝি-কোড উদাহরণেও দেখা গিয়েছিল।

  2. পরীক্ষা করুন: সাইন-ওয়েভ কোড সেলে bits = 8-কে bits = 4 করে Run চাপুন — বার-চার্টের আকৃতিতে কী পার্থক্য দেখা যায়?

    bits=4 মানে মাত্র $2^4=16$টি সম্ভাব্য কোড ($0$-১৫) — অনেক কম রেজোলিউশন। বার-চার্টে এখন অনেক কম আলাদা দৈর্ঘ্যের ধাপ দেখা যাবে (অনেক পাশাপাশি পয়েন্টের কোড একই বা কাছাকাছি হয়ে যাবে), ফলে সাইন আকৃতিটা "খাঁজকাটা" (blocky/coarse) দেখাবে, ৮-বিটের তুলনায় অনেক কম মসৃণ — এটি L20-এর রেজোলিউশন-বনাম-এরর সম্পর্কেরই একটি ভিজ্যুয়াল প্রতিফলন।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ মাইক্রোপ্রসেসর আর্কিটেকচার, এমবেডেড C, GPIO, টাইমার/PWM/ADC, সিরিয়াল প্রোটোকল, RTOS, সেন্সর/অ্যাকচুয়েটর, IoT আর্কিটেকচার, ওয়্যারলেস প্রোটোকল, MQTT/CoAP ও IoT সিকিউরিটি — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Computer Architecture & Digital Logic কোর্স সহোদর কোর্স সংখ্যা পদ্ধতি ও বাইনারি প্রতিনিধিত্বের সাধারণ ভিত্তি সেই কোর্সেই তৈরি হয়েছে — এই কোর্স DAC-এর মতো পেরিফেরাল-স্পেসিফিক হার্ডওয়্যারে গভীরে যায়।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Design and Analysis of Algorithms ও আরও অনেক কোর্স — সব এক জায়গায়।
আগের পাঠ
অ্যানালগ-টু-ডিজিটাল কনভার্সন (ADC)