পাঠ ০৭ · ৫৭-এর মধ্যে · মডিউল ২
Home / Courses / Digital Signal Processing / কোয়ান্টাইজেশন

কোয়ান্টাইজেশন ও কোয়ান্টাইজেশন এরর

Quantization & quantization error
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • কোয়ান্টাইজেশনের সংজ্ঞা এবং কেন এটি স্যাম্পলিং থেকে ভিন্ন একটি প্রক্রিয়া
  • একটি ইউনিফর্ম কোয়ান্টাইজার হাতে বাস্তবায়ন করা (মিড-ট্রেড, uniform step)
  • প্রতিটি স্যাম্পলের প্রকৃত কোয়ান্টাইজেশন এরর সত্যিকারের কোড দিয়ে গণনা করা
  • কোয়ান্টাইজেশন নয়েজ পাওয়ার থেকে SNR হিসেব করা, ও বিট-সংখ্যার সাথে এর সম্পর্ক বোঝা

১ · কোয়ান্টাইজেশন কী

L05-L06-এ আমরা দেখেছি স্যাম্পলিং একটি সিগন্যালকে সময়ে ডিসক্রিট করে — নির্দিষ্ট মুহূর্তে মান নেওয়া হয়। কিন্তু সেই মানগুলো এখনও ধারাবাহিক (যেকোনো রিয়েল সংখ্যা হতে পারে)। একটি ডিজিটাল সিস্টেম (কম্পিউটার, মাইক্রোকন্ট্রোলার) সসীম সংখ্যক বিট দিয়ে সংখ্যা সংরক্ষণ করে, তাই প্রতিটি অ্যামপ্লিটিউড মানকেও একটি সসীম সংখ্যক ডিসক্রিট লেভেলের একটিতে গোল করতে হয় — একেই বলে কোয়ান্টাইজেশনQuantizationএকটি ধারাবাহিক অ্যামপ্লিটিউড মানকে একটি সসীম সংখ্যক ডিসক্রিট লেভেলের নিকটতমটিতে গোল করার প্রক্রিয়া।। স্যাম্পলিং সময়-অক্ষে ডিসক্রিটাইজেশন, কোয়ান্টাইজেশন অ্যামপ্লিটিউড-অক্ষে ডিসক্রিটাইজেশন — দুটো মিলেই একটি সম্পূর্ণ ADC পাইপলাইন তৈরি করে (L08-এ একত্রিত হবে)।

বিট ও লেভেল
$b$ বিট দিয়ে $2^b$টি ডিসক্রিট লেভেল প্রকাশ করা যায় — ৩ বিট = ৮ লেভেল, ৪ বিট = ১৬ লেভেল, ১৬ বিট (CD অডিও) = ৬৫,৫৩৬ লেভেল।
স্টেপ সাইজ
রেঞ্জ $[x_{min}, x_{max}]$-কে $2^b$ ভাগে ভাগ করলে স্টেপ সাইজ $\Delta = (x_{max}-x_{min})/2^b$ — যত বড় $\Delta$, তত মোটা গোলযোগ।

২ · একটি হাতে-লেখা কোয়ান্টাইজার ও প্রকৃত এরর

নিচের কোড সেলে একটি মিড-ট্রেড ইউনিফর্ম কোয়ান্টাইজার হাতে লেখা হয়েছে — এটি একটি মানকে $2^{bits}$টি সমান-দৈর্ঘ্যের ভাগে ভাগ করে প্রতিটি ভাগের মাঝামাঝি মান রিটার্ন করে। একটি ৫ Hz সাইন সিগন্যাল ($f_s=64$ Hz, $N=16$ স্যাম্পল) ৩-বিট (৮ লেভেল) দিয়ে কোয়ান্টাইজ করে প্রতিটি স্যাম্পলের এরর ($x[n]-x_q[n]$) এবং শেষে সিগন্যাল/নয়েজ পাওয়ার থেকে SNR গণনা করা হচ্ছে।

Python
import math

def quantize(x, bits, xmin=-1.0, xmax=1.0):
    """মিড-ট্রেড ইউনিফর্ম কোয়ান্টাইজার -- [xmin, xmax] রেঞ্জকে 2**bits ভাগে ভাগ করে"""
    levels = 2 ** bits
    step = (xmax - xmin) / levels
    idx = int((x - xmin) / step)
    idx = max(0, min(levels - 1, idx))     # রেঞ্জের বাইরে গেলে ক্ল্যাম্প করা
    xq = xmin + (idx + 0.5) * step          # সেই ভাগের মাঝামাঝি মান
    return xq, step, levels

fs = 64.0
f = 5.0
N = 16
bits = 3

samples = [math.sin(2 * math.pi * f * n / fs) for n in range(N)]

print(f"{'n':>3} | {'x[n]':>9} | {'xq[n]':>9} | {'error':>9}")
errors = []
for n, x in enumerate(samples):
    xq, step, levels = quantize(x, bits)
    e = x - xq
    errors.append(e)
    print(f"{n:>3} | {x:>9.5f} | {xq:>9.5f} | {e:>9.5f}")

print(f"\nবিটস={bits}, লেভেল={levels}, স্টেপ সাইজ={step}")

signal_power = sum(x * x for x in samples) / N
noise_power = sum(e * e for e in errors) / N
snr = 10 * math.log10(signal_power / noise_power)
print(f"signal power = {signal_power:.6f}")
print(f"noise power  = {noise_power:.8f}")
print(f"SNR = {snr:.3f} dB")

    
লক্ষ্য করুন প্রতিটি এরর $|\Delta/2|=0.125$-এর মধ্যেই থাকছে (কারণ মিড-ট্রেড কোয়ান্টাইজার সবসময় নিকটতম লেভেলের মাঝামাঝি মান দেয়, তাই সর্বোচ্চ এরর অর্ধেক স্টেপ সাইজ) — প্রকৃত সর্বোচ্চ এরর কোড রানে $\approx 0.125$ (n=০-এ)। মোট নয়েজ পাওয়ার $\approx 0.00603$, সিগন্যাল পাওয়ার $\approx 0.46875$, ফলে SNR $\approx \mathbf{18.904}$ dB — এটি একটি সুপরিচিত ইঞ্জিনিয়ারিং অভিজ্ঞতাসূত্র $6.02b+1.76$ dB (পূর্ণ-স্কেল সাইন সিগন্যালের জন্য প্রমিত টেক্সটবুক সূত্র, $b=3$-এ $\approx 19.82$ dB)-এর কাছাকাছি — ছোট স্যাম্পল-সংখ্যায় ঠিক মিলবে না, কারণ এই ফর্মুলাটি বড় সংখ্যক স্যাম্পলে গড় আচরণ ধরে, উপরের রান মাত্র ১৬টি স্যাম্পলের সুনির্দিষ্ট মান।

৩ · বিট বাড়ালে কী হয়

একই সিগন্যালকে ৩ বিটের বদলে ৪ বিট (১৬ লেভেল) দিয়ে কোয়ান্টাইজ করলে স্টেপ সাইজ অর্ধেক ($0.25 \to 0.125$) হয়ে যায়, নয়েজ পাওয়ার কমে ($0.00603 \to 0.00149$), আর SNR বাড়ে ($18.904 \to \mathbf{24.967}$ dB) — এই সম্পর্ক নিচের অনুশীলনে নিজে যাচাই করুন।

মূল কথা · Key takeaway

কোয়ান্টাইজেশন এরর কোনো "বাগ" নয় — এটি সসীম বিটে অসীম-নির্ভুল সংখ্যা সংরক্ষণের একটি অপরিহার্য, গাণিতিকভাবে নিয়ন্ত্রিত পরিণতি। বিট-সংখ্যা বাড়ালে এরর কমে, ব্যয় (মেমরি, ব্যান্ডউইথ) বাড়ে — এটাই ADC ডিজাইনের একটি মূল ট্রেড-অফ, যা L08-এ সম্পূর্ণ ADC/DAC পাইপলাইনে প্রয়োগ হবে।

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

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

প্র ০১ কোয়ান্টাইজেশন এরর কি সবসময় ধনাত্মক নাকি ঋণাত্মক হবে? উপরের টেবিল দেখে বলুন।

দুটোই — টেবিলে $n=0$-এ এরর $-0.125$ (ঋণাত্মক, কোয়ান্টাইজড মান আসলের চেয়ে বেশি), আবার $n=3$-এ এরর $+0.12018$ (ধনাত্মক, কোয়ান্টাইজড মান আসলের চেয়ে কম)। মিড-ট্রেড কোয়ান্টাইজার সবসময় নিকটতম লেভেলে গোল করে, তাই এরর সবসময় $[-\Delta/2, +\Delta/2]$ রেঞ্জে থাকে — গড়ে প্রায় শূন্যের কাছাকাছি, কিন্তু প্রতিটি পৃথক স্যাম্পলে যেকোনো চিহ্ন হতে পারে।

প্র ০২ যদি সিগন্যালের রেঞ্জ $[-1,1]$-এর বাইরে চলে যায় (যেমন একটি স্যাম্পল $1.5$), তাহলে উপরের quantize() ফাংশন কী করবে?

কোডে idx = max(0, min(levels - 1, idx)) লাইনটি ইনডেক্সকে ক্ল্যাম্প (clamp) করে — অর্থাৎ $1.5$ সর্বোচ্চ লেভেলেই আটকে যাবে, আসল মান $1.5$ হলেও কোয়ান্টাইজড আউটপুট রেঞ্জের শীর্ষ লেভেলের মাঝামাঝি মানই দেবে। এটাকে বলে ক্লিপিং — রেঞ্জের বাইরের মানে কোয়ান্টাইজেশন এরর হঠাৎ অনেক বড় হয়ে যায়, তাই বাস্তব ADC ডিজাইনে ইনপুট রেঞ্জ ঠিকভাবে সেট করা (gain staging) গুরুত্বপূর্ণ।

প্র ০৩ SNR হিসাবের সূত্র 10*log10(signal_power/noise_power) কেন ১০ দিয়ে গুণ করা হয়, ২০ দিয়ে নয় (যেমন কখনো কখনো amplitude-ratio-তে দেখা যায়)?

signal_power ও noise_power ইতিমধ্যে "পাওয়ার" রাশি (অ্যামপ্লিটিউডের বর্গের গড়), আর ডেসিবেল সংজ্ঞা অনুযায়ী পাওয়ার-অনুপাতের জন্য $10\log_{10}$ ব্যবহার হয় ($20\log_{10}$ ব্যবহার হয় যখন সরাসরি অ্যামপ্লিটিউড-অনুপাত নেওয়া হয়, কারণ পাওয়ার $\propto$ অ্যামপ্লিটিউড², আর $10\log_{10}(A^2)=20\log_{10}(A)$)। উপরের কোডে যেহেতু আমরা সরাসরি পাওয়ার (বর্গের গড়) নিয়েছি, $10$ দিয়ে গুণ করাই সঠিক — এই কনভেনশন M11-এর SNR পাঠগুলোতেও (L49) একইভাবে ব্যবহৃত হবে।

অনুশীলন

  1. চিন্তা করুন: উপরের কোড সেলে bits = 3-কে bits = 4-এ বদলালে লেভেল-সংখ্যা ও স্টেপ সাইজ কত হবে? SNR বাড়বে না কমবে বলে আপনার ধারণা?

    লেভেল $2^4=16$ (৩-বিটের ৮ থেকে দ্বিগুণ), স্টেপ সাইজ $\Delta=2/16=0.125$ (আগের অর্ধেক)। স্টেপ সাইজ অর্ধেক মানে গড় এরর ম্যাগনিটিউডও কমবে, তাই নয়েজ পাওয়ার কমবে এবং SNR বাড়বে।

  2. পরীক্ষা করুন: কোড সেলে bits = 3-কে bits = 4-এ পরিবর্তন করে Run চেপে দেখুন প্রকৃত SNR কত হয়।

    রান করলে levels=16, step=0.125, noise power ≈ 0.00149364, এবং SNR ≈ 24.967 dB দেখাবে — ৩-বিটের ১৮.৯০৪ dB থেকে প্রায় ৬ dB বেড়েছে, যা "প্রতি বিটে প্রায় ৬ dB SNR বৃদ্ধি" নিয়মের ($6.02$ dB/বিট) সাথে সামঞ্জস্যপূর্ণ।

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

আগের পাঠ
অ্যালিয়াসিং — কারণ ও প্রতিরোধ