پیاده‌سازی فیلتر دیجیتال

پروژه: پیاده‌سازی فیلتر دیجیتال

فیلتر دیجیتال یکی از مهم‌ترین بخش‌های بیشتر الگوریتم‌های پردازش سیگنال دیجیتال است. تقریبا در اکثر سیستم‌هایی که نوعی از پردازش سیگنال دیجیتال در آنها وجود دارد، یک یا چند فیلتر دیجیتال هم موجود است. روند استفاده از این فیلترها در یک سیستم، از طراحی فیلتر شروع و به پیاده‌سازی آن ختم می‌شود. در این مقاله، بیشتر در مورد موضوعات مربوط به پیاده‌سازی صحبت می‌کنم.

 

فیلتر دیجیتال چیست؟

در تئوری سیگنال و سیستم، هر سیگنالی از مجموع تعدادی مؤلفه فرکانسی با دامنه‌های مختلف تشکیل شده است. یک فیلتر، در واقع سیستمی است که بعضی از این مؤلفه‌های فرکانسی را از خود عبور می‌دهد و بعضی را حذف می‌کند. یک فیلتر دیجیتال، این عمل را بر روی نمونه‌های دیجیتالی و گسسته سیگنال آنالوگ انجام می‌دهد.

مثلا یک فیلتر دیجیتال پایین‌گذر، مؤلفه‌های فرکانسی سیگنال ورودی به خود را از صفر هرتز تا یک فرکانس مشخص که فرکانس قطع فیلتر، Fc، نامیده می‌شود عبور می‌دهد و فرکانس‌های بیش از فرکانس قطع را حذف می‌کند. شکل زیر، پاسخ فرکانسی یک فیلتر پایین‌گذر ایده‌آل را نشان می‌دهد.

 

پاسخ فرکانسی فیلتر ایده‌آل

 

یک سیگنال تک‌تن یا سینوسی، سیگنالی است که فقط شامل یک مؤلفه فرکانسی است. در مثال فیلتر پایین‌گذر، اگر فرکانس سیگنال تک‌تن ورودی به فیلتر، کمتر از فرکانس قطع آن باشد، این سیگنال از فلتر عبور می‌کند و در حالت ایده‌آل، بدون تغییر در خروجی ظاهر می‌شود. اما اگر فرکانس سیگنال سینوسی، بیش از فرکانس قطع فیلتر باشد، سیگنال ورودی به خروجی فیلتر منتقل نمی‌شود.

برای اینکه یک فیلتر را مطابق با نیازهایتان طراحی کنید، روش‌ها و ابزارهای زیادی وجود دارند. همانطور که در ابتدای این مقاله هم اشاره کردم، در این مقاله بیشتر در مورد پیاده‌سازی یک فیلتر صحبت خواهم کرد. در یک فرآیند حرفه‌ای، معمولا افرادی که طراح سیستم هستند، فیلتر را طراحی می‌کنند و طراح یا پیاده‌ساز دیجیتال نیز فیلتر را پیاده‌سازی می‌کند. با این حال، نگاه کوتاهی به بعضی از جوانب طراحی می‌تواند برای شما به عنوان پیاده‌ساز دیجیتال هم مفید باشد.

برای آشنایی با روند طراحی سیستم‌های دیجیتال، این مقاله را بخوانید…

طراحی فیلتر معمولا با تهیه مشخصات اصلی فیلتر شروع می‌شود. مثلا برای یک فیلتر پایین‌گذر، باید مشخص شود که با توجه به نیاز مساله، چه فرکانس قطعی مورد نیاز است. در یک فیلتر واقعی پایین‌گذر، تمام مؤلفه‌های فرکانسی بیش از فرکانس قطع، به طور کامل حذف نمی‌شوند و فقط دامنه آنها تضعیف می‌شوند. مقدار این تضعیف هم جزء مشخصات فیلتر است.

در یک فیلتر واقعی، مرز ناحیه عبور و حذف هم به صورت پله‌ای شکل قبل نیست و معمولا داری یک منحنی است. شکل زیر، پاسخ فرکانسی یک فیلتر واقعی را نشان می‌دهد. همانطور که می‌بینید، در اطراف فرکانس قطع، پاسخ فیلتر به صورت یک منحنی است. هر چه شکل این منحنی به شکل ایده‌آل نزدیک‌تر باشد، یعنی با شیب بیشتری از ناحیه عبور به ناحیه حذف برود، از نظر طراح مطلوب‌تر است.

 

پاسخ فرکانسی فیلتر واقعی

 

موارد دیگری هم به عنوان مشخصات طراحی وجود دارند که معمولا طراح برای هر کدام از آنها با توجه به نیازمندی‌های مساله، حداقل‌هایی را در نظر می‌گیرد و سپس شروع به طراحی فیلتر می‌کند. برای طراحی فیلتر، روش‌های مختلفی وجود دارند. معمولا یکی از این روش‌ها انتخاب می‌شود و طراحی به وسیله آن انجام می‌شود.

به جز روش طراحی، مورد دیگری که توسط طراح باید انتخاب شود، نوع فیلتر است. به طور کلی، دو نوع فیلتر دیجیتال وجود دارد. فیلتر FIR یا Finite Impulse Response و فیلتر IIR یا Infinite Impulse Response. این دو نوع فیلتر، هر کدام دارای معایب و مزایایی هستند که طراح باید با توجه به نیازمندی‌های مساله و البته پیاده‌سازی، یکی را به عنوان راه‌حل انتخاب کند. در این مقاله، در مورد پیاده‌سازی فیلتر FIR صحبت خواهم کرد.

یکی از پارامترهایی که طراح در هنگام طراحی فیلتر انتخاب می‌کند، مرتبه یا طول فیلتر است. بسیاری از مشخصات فیلتر، با افزایش مرتبه فیلتر بهبود پیدا می‌کنند. مثلا شیب پاسخ فیلتر در محل بین ناحیه گذر و حذف، با افزایش درجه فیلتر بیشتر می‌شود. بعد از طراحی یک فیلتر دیجیتال، آنچه حاصل می‌شود تعدادی ضریب است. تعداد این ضریب‌ها در فیلتر FIR برابر با درجه یا طول فیلتر است.

شکل زیر، ساختار یک فیلتر دیجیتال FIR مرتبه N را نشان می‌دهد. به این ساختار از فیلتر FIR، ساختار Direct Form گفته می‌شود. در این ساختار، یک Delay Line یا خط تاخیر وجود دارد که نمونه‌های ورودی، x[n]، یکی یکی وارد آن می‌شوند. چون مرتبه فیلتر N است، پس به تعداد N ضریب و N-1 واحد تاخیر دارد. خروجی هر کدام از تاخیردهنده‌ها در یکی از ضرایب فیلتر، bN، ضرب شده و نهایتا تمام این حاصل‌ضرب‌ها با هم جمع می‌شوند و خروجی فیلتر، y[n]، را تشکیل می‌دهند.

 

فیلتر دیجیتال Direct Form

 

فیلتر FIR با ساختار Transpose

فیلتر FIR با ساختار Direct Form را می‌توان با تغییراتی به شکل زیر درآورد. این ساختار که Transposed Direct Form نام دارد، دارای مزایایی در پیاده‌سازی نسبت به ساختار Direct Form است و معمولا توسط پیاده‌سازان انتخاب می‌شود.

 

فیلتر دیجیتال Transpose

 

به کمک این ساختار می‌توانید پیاده‌سازی را با بیشترین سرعت کلاک ممکن انجام دهید و یک مدار کاملا پایپ‌لاین داشته باشید. برای پیاده‌سازی، پیشنهاد می‌کنم هر دو ساختار را پیاده‌سازی کنید و نتایج را از نظر سرعت و مقدار منابع اشغال شده در FPGA بررسی و مقایسه کنید.

 

ایده‌هایی برای پیاده‌سازی فیلتر دیجیتال

همانطور که در مقاله مربوط به پروژه پیاده‌سازی پروتکل SPI هم اشاره کردم، بهتر است قبل از شروع به پیاده‌سازی در نرم‌افزار ISE، ابتدا روی کاغذ، سعی کنید طرحی از آنچه در ذهن دارید را ترسیم کنید و وضعیت پورت‌های ورودی و خروجی را مشخص کنید. در مورد فیلتر دیجیتال، شما به جز انجام این مرحله، نیاز دارید تا مدلی از فیلتری که می‌خواهید پیاده‌سازی کنید را در یک نرم‌افزار شبیه‌ساز مثل نرم‌افزار MATLAB یا به کمک زبان C طراحی کنید.

در مورد پورت‌های ورودی و خروجی، نسبتا کار ساده‌ای در پیش داریم. برای یک فیلتر دیجیتال ساده، فقط یک پورت ورودی برای دریافت نمونه‌های دیتا و یک پورت خروجی برای خروج نمونه‌های فیلتر شده لازم داریم. البته مثل همیشه، پورتی برای کلاک هم وجود خواهد داشت. عرض بیت پورت‌های دیتای ورودی و خروجی، بستگی به نیازمندی‌های مساله دارد که معمولا در زمان طراحی سیستمی و توسط طراح سیستم مشخص می‌شود. فرض کنید این مقدار در طراحی سیستمی، ۱۴ بیت به دست آمده است.

حال باید مدلی از فیلتر را در یک نرم‌افزار شبیه‌ساز مثل MATLAB طراحی کنید. در این نرم‌افزار امکانات بسیار زیادی برای طراحی و شبیه‌سازی فیلترها وجود دارد. پیشنهاد می‌کنم، بخش FDATool در نرم‌افزار MATLAB را که ابزاری بسیار عالی برای طراحی و تحلیل انواع فیلترهای دیجیتال است مطالعه کنید.

فرض ما در اینجا بر این است که فیلتر قبلا توسط شما یا طراح سیستم طراحی شده است و حاصل طراحی که تعدادی ضریب است، اکنون در اختیار ما است. فرض کنید که فیلتر مورد نظر ما از مرتبه پنج است. بنابراین تعداد پنج ضریب وجود دارد. ما قصد داریم این فیلتر FIR را با ساختار Transposed پیاده‌سازی کنیم. پس نیاز به پنج واحد ضرب‌کننده و چهار واحد جمع‌کننده داریم. همچنین چهار مرحله پایپ خواهیم داشت که به کمک چهار رجیستر میانی پیاده‌سازی خواهند شد.

حال شاید این سوال برای شما پیش بیاید که دلیل تهیه مدلی نرم‌افزاری در MATLAB قبل از پیاده‌سازی روی FPGA چیست. دو دلیل اصلی برای این کار وجود دارد. اول اینکه شما نیاز دارید بعد از اینکه پیاده‌سازی برای FPGA را به کمک زبان توصیف سخت‌افزاری مثل VHDL انجام دادید، آن را درستی‌آزمایی کنید. به عبارت دیگر، شما باید ورودی‌هایی به مدار خود بدهید و صحت خروجی‌ها را بررسی کنید. برای این کار نیاز خواهید داشت تا خروجی‌های حاصل از شبیه‌سازی کد VHDL را با خروجی‌هایی که از درستی آنها مطمئن هستید مقایسه کنید. این خروجی‌های مرجع را می‌توانید به کمک مدلی که در نرم‌افزار MATLAB تهیه کرده‌اید ایجاد کنید.

دلیل دوم برای تهیه یک مدل نرم‌افزاری از فیلتر دیجیتال این است که شما به هنگام طراحی مدار، با عرض بیت‌های محدود روبرو هستید. وقتی در نرم‌افزاری مثل MATLAB فیلتر را طراحی می‌کنید، دقت ضرایب و محاسبات بسیار زیاد و به صورت Floating-Point هستند. اما برای پیاده‌سازی در FPGA، برای اینکه منابع دیجیتالی کمتری مصرف کنید و در عین حال، به سرعت بیشتری هم برسید، مجبور هستید تا محاسبات را با دقت محدود (عرض بیت محدود) و به صورت Fixed-Point انجام دهید. شما به کمک مدل نرم‌افزاری، آزمایشاتی انجام می‌دهید تا حداقل عرض بیت یا دقت مورد نیاز را برای نمایش ضرایب و انجام محاسبات در فیلتر به دست بیاورید. این موضوع مفصلی است که در کارگاهی که به زودی در مورد پردازش سیگنال با FPGA برگزار خواهم کرد، بیشتر در موردش صحبت خواهم کرد.

بعد از تهیه مدل نرم‌افزاری و بررسی عرض بیت‌های لازم برای پیاده‌سازی بخش‌های مختلف فیلتر، می‌توانید کدنویسی را شروع کنید. اجازه دهید برای مثال خودمان، عرض بیتی را برای ضرایب فرض کنیم و از روی آن، باقی عرض بیت‌ها را محاسبه کنیم تا بتوانیم پیاده‌سازی را پیش ببریم. فرض کنید، عرض بیت ضرایب فیلتر مورد نظرمان ۱۲ بیت باشد. چون عرض بیت سیگنال ورودی را ۱۴ در نظر گرفته بودیم، بنابراین، عرض بیت خروجی ضرب‌کننده‌ها ۱۲+۱۴ = ۲۶ خواهند بود.

از طرف دیگر، جمع‌کننده‌ها هر بار باید تعداد پنج حاصلضرب را با هم جمع کنند. اگر اعداد ۲۶ بیتی را N بار با هم جمع کنیم، رشد عرض بیت برابر با (log2(N خواهد بود. اگر این عدد اعشار داشته باشد باید به سمت زیاد روند شود. چون در مثال ما، N که همان مرتبه فیلتر یا تعداد ضرایب است برابر با پنج است، بنابراین رشد عرض بیت حاصل از جمع خروجی ضرب‌کننده‌ها برابر با ۳ خواهد بود. پس عرض بیت جمع‌کننده‌ها باید برابر با ۲۶+۳ = ۲۹ باشد.

در این مثال، فرض کرده‌ایم که ورودی‌ها و همه ضرایب، بدون علامت هستند و تمام محاسبات را بدون علامت انجام می‌دهیم. اگر محاسبات را به صورت علامتدار انجام دهیم، محاسباتی که انجام دادیم، تغییرات کوچکی خواهند داشت. همچنین چون خروجی را هم مشابه ورودی، ۱۴ بیتی در نظر گرفتیم، بنابراین باید از ۲۹ بیت جمع‌کننده آخر که خروجی فیلتر را محاسبه می‌کند، ۱۴ بیت سنگین آن را جدا کرده و به خروجی اعمال کنیم.

همانطور که از شکل فیلتر با ساختار Transpose هم می‌توان به راحتی متوجه شد، این فیلتر دارای ساختار پایپ‌لاین است و همین موضوع باعث افزایش سرعت و throughput آن شده است. برای آشنایی با روش‌های افزایش سرعت مدارات دیجیتال و نحوه پایپ‌لاین کردن یک مدار دیجیتال در کدنویسی VHDL، می‌توانید مقاله زیر را مطالعه کنید.

آشنایی با روش‌های افزایش سرعت مدارات دیجیتال…

 

قدم بعدی برای طراحی فیلتر دیجیتال

به کمک توضیحاتی که در این مقاله داده شده و عرض بیت‌هایی که برای مثال مطرح شدند، می‌توانید شروع به طراحی یک فیلتر FIR با ساختار Transpose کنید. اما جزئیات دیگری هم در طراحی و پیاده‌سازی فیلترهای دیجیتال وجود دارند که در این مقاله مجال مطرح کردن آنها نیست. برای آشنایی بیشتر با انواع فیلترهای دیجیتال و ساختارهای مختلف پیاده‌سازی آنها، پیشنهاد می‌کنم به کتاب Digital Signal Processing with FPGA که قبلا در سایت و کانال معرفی کرده بودم مراجعه کنید.

همچنین به زودی کارگاهی را در زمینه پیاده‌سازی الگوریتم‌های پردازش سیگنال با FPGA برگزار خواهم کردم که در آن به اصول و روش‌های پیاده‌سازی انواع الگوریتم‌های پردازش سیگنال به کمک FPGA خواهم پرداخت. به کمک اطلاعاتی که از این کارگاه به دست خواهید آورد، می‌توانید دانش و مهارت خودتان را در بکارگیری FPGAها برای طراحی مدارات دیجیتال، یک گام به جلو ببرید و قابلیت خودتان را در انجام پروژه‌های حرفه‌ای و بزرگ به نحو چشمگیری افزایش دهید.

 

چطور از صحت پیاده‌سازی خودمان مطمئن شویم؟

اولین کار بعد از اینکه فیلتر دیجیتال را به کمک زبان VHDL پیاده‌سازی کردید، انجام شبیه‌سازی رفتاری برای اطمینان از صحت عملکرد آن است. برای این منظور باید یک تست‌بنچ ایجاد کنید و به کمک نرم‌افزار ISim شبیه‌سازی را شروع کنید. در تست‌بنچ باید یک رشته دیتای ورودی به فیلتر اعمال کنید و در نرم‌افزار ISim خروجی فیلتر را ببینید.

برای آشنایی با نرم‌افزار ISim و شبیه‌سازی رفتاری به کمک آن، این برنامه ویدئویی را ببینید…

 

اما ممکن است این سوال برایتان پیش بیاید که چطور متوجه شویم که خروجی‌ها درست هستند؟

جواب این سوال را می‌توان به کمک مدل نرم‌افزاری که در MATLAB ایجاد کرده‌اید به دست آورید. روند درستی‌آزمایی به این صورت است که شما ابتدا یک رشته یا بردار از نمونه‌ها را در نرم‌افزار MATLAB ایجاد می‌کنید و به عنوان ورودی به فیلتری که به عنوان مدل نرم‌افزاری طراحی کرده‌اید اعمال می‌کنید. سپس خروجی‌های حاصل را در جایی مثلا در یک فایل متنی ذخیره می‌کنید.

در مرحله بعد، همان رشته یا بردار ورودی را که در نرم‌افزار MATLAB استفاده کرده بودید، به کمک تست‌بنچ به کد VHDL اعمال می‌کنید. بعد از اجرای شبیه‌سازی باید خروجی‌های حاصل از شبیه‌سازی کدتان را هم در یک فایل منتی ذخیره کنید. در نهایت، برای اطمینان از صحت عملکرد مدارتان باید خروجی‌های حاصل از شبیه‌سازی مدل فیلتر در نرم‌افزار MATLAB را با خروجی حاصل از شبیه‌سازی کدتان در نرم‌افزار ISim مقایسه کنید.

چند مورد را برای انجام این درستی‌آزمایی باید فرا بگیرید که مطالعه آنها را برعهده خودتان می‌گذارم. اول اینکه چطور خروجی حاصل از شبیه‌سازی در MATLAB را در یک فایل متنی قرار دهید. دوم، استفاده از رشته ورودی‌هایی که در MATLAB استفاده کرده‌اید به عنوان ورودی مدارتان در تست‌بنچ؛ و سوم، ذخیره کردن خروجی حاصل از شبیه‌سازی با نرم‌افزار ISim در یک فایل منتی.

اگر سوالی در زمینه پیاده‌سازی این فیلتر دارید، یا روش‌های دیگری برای پیاده‌سازی و شبیه‌سازی آن دارید، لطفا همین جا و در پایین همین مقاله، آنها را با من و دیگر علاقمندان به اشتراک بگذارید.

کانال آموزش FPGA از صفر

12 پاسخ
  1. هادی
    هادی گفته:

    سلام
    بنده این روش رو تو بخشی از پایان نامه ام انجام دادم. ابتدا فایل تصویر رو بوسیله متلب به فایل متنی(txt.) تبدیل کردم و به عنوان مقادیر ورودی استفاده نمودم.
    در آخر هم ضرایب خروجی رو به وسیله تست بنچ در یک فایل متنی نوشته و ذخیره کردم. این فایل متنی رو دوباره با متلب به فایل تصویر تبدیل کردم.

    پاسخ دادن
  2. masoud
    masoud گفته:

    اگر مقدار ضریب کمتر از یک هست پس چرا نتیجه در یک رجیستر که به اندازه حاصل جمع اندازه دو رجیستر قبلی هست باید ریخته شود؟ چون وقتی مقدار کوچکتر از یک هست ما عملآ یک تقسیم داریم و دیگر لزومی نداره حاصل در یک رجیستر که به اندازه جمع اندازه دو رجیستر قبلی است ریخته شود!!!
    برای روشنتر شدن یک مثال میزنم، اگر ضریب ما b=0.25 باشد یعنی مقدار ورودی تقسیم بر چهار میشود که برای ذخیره حاصل ما به ریجستری کوچکتر (به اندازه دو بیت) از ریجستر ورودی نیاز خواهیم داشت.

    پاسخ دادن
    • احمد ثقفی
      احمد ثقفی گفته:

      نکته اول در این مورد این هست که طبق قانون ضرب در زبان VHDL اگر شما یک عدد mبیتی را در یک عدد nبیتی ضرب کنید، حاصل را باید در یک رجیستر m+n بیتی بریزید.

      نکته دوم این هست که ممکن است بعد از انجام این ضرب، شما به بعضی از بیت‌های حاصلضرب نیاز نداشته باشید که در این صورت می‌توانید آنها را حذف کنید. البته برای این منظور باید آزمایشاتی را در نرم‌افزاری مثل MATLAB انجام دهید.

      نکته آخر هم این هست که شما در اینجا در حال انجام محاسبات اعشاری هستید. درست است که حاصل این ضرب‌ها کوچک می‌شوند، اما دارای مقادیر اعشاری هستند و تقریبا تمام بیت‌های حاصلضرب برای ذخیره بخش اعشار استفاده می‌شوند.

      سعی می‌کنم در مقالات دیگری در مورد این موضوعات بیشتر صحبت کنم. کارگاه پردازش سیگنال با FPGA هم به زودی آماده خواهد شد که در آن به طور مفصل در این زمینه آموزش خواهم داد.

      موفق باشید.

      پاسخ دادن
  3. MONTGOMERY
    MONTGOMERY گفته:

    خوب ظاهرا تو این پروژه من اوت شدم چون نه میتونم با فیلتر های متلب کار کنم و نه حتی کوچکترین چیزی از مفاهیم سیگنالی و فیلترها بلدم …
    ظاهرا باید بشینم اول سیگنال و بعد متلب یاد بگیرم که متاسفانه جفتشون کوه های عظیمی هستند و عملا از میدون FPGA اوت شدم
    🙁

    پاسخ دادن
    • احمد ثقفی
      احمد ثقفی گفته:

      برای پیاده‌سازی الگوریتم‌های پردازش سیگنال دیجیتال لازم نیست حتما به خود الگوریتم‌ها مسلط شوید. اطلاعات پایه‌ای در این زمینه لازم است که به راحتی قابل یادگیری هستند.

      چیزی که شما باید یاد بگیرید، نحوه پیاده‌سازی این الگوریتم‌ها هستند که موضوع متفاوتی نسبت به مثلا طراحی فیلتر است.

      موفق باشید.

      پاسخ دادن
      • MONTGOMERY
        MONTGOMERY گفته:

        سلام و عرض ادب خدمت استاد عزیزم آقای ثقفی … ممنون از راهنمایی ارزشمندتون
        پس گمونم نباید زود قضاوت کنم راجب این موضوع
        چشم و ممنون

        پاسخ دادن
  4. محمد امین
    محمد امین گفته:

    سلام استاد

    من یک سیگنال دیتا دارم. اونارو از یک فیلتر با ورودی ۱۶ بیت عبور میدم خروجی همونطور که شما اشاره کردین تعداد بیتهاش با توجه به فرمول هاصی که گفتین تقریبا دو برابر میشه و میشه ۳۲ بیت.
    سوال من اینجاست که اگر بخوام خروجی فیلترم هم ۱۶ بیت باشه شما گفتین که ۱۶ بیت پر ارزش را نگه میداریم یعنی out(32 downto 16). آیا حذف شدن ۱۶ بیت در نتیجه کار اثر نمیذاره؟
    مثلا وقتی یک سیگنال راداری داریم که پر از اطلاعات هست این کار باعث نمیشه این اظلاعات از بین بره؟

    پاسخ دادن
    • احمد ثقفی
      احمد ثقفی گفته:

      سلام،

      همونطور که در این پست هم اشاره کردم، قبل از پیاده‌سازی باید آزمایشاتی را در نرم‌افزاری مثل MATLAB انجام دهید تا حداقل عرض بیت‌های قابل قبول برای بخش‌های مختلف طرح را پیدا کنید.

      حذف کردن بیت‌های سبک خروجی، رزولوشن خروجی را کم می‌کند. ممکنه مشکل ایجاد کنه و ممکنه ایجاد نکته. حتی ممکن است با توجه به نوع سیگنال ورودی، شما بتوانید تعدادی از بیت‌های سنگین رو حذف کنید.

      همه اینها بستگی به شرایط مساله و نتیجه آزمایشاتی که شما بر مبنای اون شرایط انجام می‌دهید دارد.

      موفق باشید

      پاسخ دادن

دیدگاه خود را ثبت کنید

خوشحال خواهم شد نظر شما را در مورد این پست بدانم.
ایمیل شما برای دیگران قابل مشاهده نخواهد بود.

پاسخ دهید

You have to agree to the comment policy.