نمونه سورس کد چارت نموداری زنده در سی شارپ (شبیه اسیلوسکوپ)


ایجاد یک چارت نموداری زنده در سی‌شارپ، که به نوعی شبیه اسیلوسکوپ باشد، می‌تواند یک پروژه بسیار جذاب و در عین حال چالش‌برانگیز باشد. این نوع برنامه‌نویسی نیازمند درک عمیق از مفاهیم مربوط به رسم گرافیک، مدیریت وقایع زمانی، و پردازش داده‌های لحظه‌ای است تا بتوان تصویری دینامیک و واقعی از سیگنال‌های آنالوگ شبیه‌سازی کرد. در ادامه، یک راهنمای جامع و کامل برای ساخت چنین پروژه‌ای آورده شده است، به همراه نمونه سورس کدهای قابل اجرا در زبان سی‌شارپ.
مقدمۀ کلی
در ابتدا، باید بدانید که هدف ما ساخت یک برنامه است که قادر باشد سیگنال‌های ورودی را در زمان واقعی نمایش دهد، درست همان‌طور که یک اسیلوسکوپ واقعی کار می‌کند. برای این کار، نیاز به یک کنترل گرافیکی داریم که بتواند داده‌های پیوسته و سریع را به صورت دینامیک رسم کند، و این کار را معمولاً با کمک کنترل‌های گرافیکی مانند `PictureBox` یا `Graphics` در سی‌شارپ انجام می‌دهیم. علاوه بر این، باید بتوانیم داده‌های سیگنال را تولید کنیم، یعنی یک منبع داده‌های لحظه‌ای که به صورت مصنوعی یا واقعی می‌تواند باشد.
در این پروژه، فرض بر این است که داده‌های سیگنال به صورت مصنوعی ساخته می‌شوند، مثلا با استفاده از توابع سینوسی، مربعی، یا دیگر موج‌ها، و سپس این داده‌ها در قالب یک حلقه بی‌نهایت یا وقفه‌های زمانی کوتاه به صفحه رسم می‌شوند.
مرحله اول: راه‌اندازی پروژه و طراحی رابط کاربری
در شروع، یک پروژه ویندوز فرم (Windows Forms) در سی‌شارپ ایجاد می‌کنیم. سپس، یک کنترل `PictureBox` به فرم اضافه می‌کنیم که محل نمایش نمودار زنده باشد. همچنین، کنترل‌هایی برای تنظیم پارامترهای سیگنال مانند فرکانس، دامنه، و نوع موج اضافه می‌کنیم. این کنترل‌ها می‌تواند شامل `TrackBar`، `ComboBox`، و یا `NumericUpDown` باشند که کاربر بتواند پارامترهای موج را تغییر دهد.
مرحله دوم: تولید داده‌های سیگنال
در این بخش، باید بتوانیم داده‌های سیگنال را به صورت لحظه‌ای تولید کنیم. برای این کار، می‌توانیم از یک تابع سینوسی ساده استفاده کنیم، که پارامترهای آن قابل تنظیم باشد. مثلا:
csharp  
double GenerateSignal(double time, double frequency, double amplitude)
{
return amplitude * Math.Sin(2 * Math.PI * frequency * time);
}

در حلقه اصلی برنامه، زمان جاری به صورت پیوسته افزایش می‌یابد و بر اساس آن، مقدار سیگنال تولید می‌شود. این داده‌ها در یک آرایه یا لیست نگهداری می‌شوند تا بتوان آن‌ها را رسم کرد.
مرحله سوم: رسم گرافیک زنده
در این قسمت، از کلاس `Graphics` برای رسم استفاده می‌شود. هر بار که داده‌های جدید تولید می‌شود، باید صفحه رسم را پاک کنیم و نقاط جدید را بر روی آن رسم کنیم. این کار معمولاً در رویداد `Paint` کنترل `PictureBox` انجام می‌گیرد، و هر بار باید `Invalidate()` فراخوانی شود تا صفحه بروزرسانی گردد.
برای ترسیم، می‌توانیم از `DrawLine` استفاده کنیم تا خط‌های پیوسته بین نقاط مختلف رسم شود، که نتیجه یک موج پیوسته و طبیعی است. نمونه کد ترسیم چنین موجی ممکن است به شکل زیر باشد:
csharp  
private void DrawWave(List<double> dataPoints)
{
Bitmap bmp = new Bitmap(pictureBox.Width, pictureBox.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Black);
Pen pen = new Pen(Color.Green);
for (int i = 1; i < dataPoints.Count; i++)
{
float x1 = (i - 1) * (pictureBox.Width / dataPoints.Count);
float y1 = (float)(pictureBox.Height / 2 - dataPoints[i - 1] * scaleFactor);
float x2 = i * (pictureBox.Width / dataPoints.Count);
float y2 = (float)(pictureBox.Height / 2 - dataPoints[i] * scaleFactor);
g.DrawLine(pen, x1, y1, x2, y2);
}
}
pictureBox.Image = bmp;
}

در این کد، `scaleFactor` برای تنظیم مقیاس موج و تناسب آن با ابعاد کنترل `PictureBox` است.
مرحله چهارم: مدیریت زمان و حلقه‌های بروزرسانی
برای داشتن یک نمایش زنده و پیوسته، از تایمر (`Timer`) در سی‌شارپ استفاده می‌کنیم. تایمر هر چند میلی‌ثانیه، داده‌های جدید تولید و رسم می‌کند. مثلا، تایمر با فاصلۀ 10 میلی‌ثانیه فعال می‌شود و در رویداد `Tick` آن، داده‌های جدید اضافه و نمودار بروزرسانی می‌شود.
کد نمونه:
csharp  
private void timer_Tick(object sender, EventArgs e)
{
double currentTime = stopwatch.Elapsed.TotalSeconds;
double signalValue = GenerateSignal(currentTime, frequency, amplitude);
dataPoints.Add(signalValue);
if (dataPoints.Count > maxDataPoints)
dataPoints.RemoveAt(0);
DrawWave(dataPoints);
}

در اینجا، `stopwatch` زمان جاری را نگه‌داری می‌کند و `maxDataPoints` تعداد نقاط رسم است که تنظیم می‌شود تا از مصرف زیاد حافظه جلوگیری شود.
مرحله پنجم: افزودن قابلیت‌های پیشرفته
برای جذاب‌تر کردن پروژه، می‌توان قابلیت‌هایی مانند تغییر سریع پارامترهای موج، ذخیره‌سازی تصویر، یا ضبط سیگنال‌های طولانی مدت را اضافه کرد. همچنین، می‌توان از امکانات پیشرفته‌تر مانند استفاده از `WriteableBitmap` برای عملکرد بهتر بهره برد، و یا از کتابخانه‌های گرافیکی دیگر بهره گرفت.
نکات مهم و توصیه‌ها
1. دقت کنید که بروزرسانی گرافیک باید سریع و بدون تأخیر باشد، بنابراین، بهتر است عملیات رسم در یک thread جداگانه انجام گیرد و از قفل کردن UI جلوگیری شود.
2. هنگام رسم، حتماً از `using` برای مدیریت منابع گرافیکی استفاده کنید.
3. پارامترهای موج را به صورت دینامیک تنظیم کنید تا کاربر بتواند تغییرات را در لحظه ببیند.
4. برای تولید داده‌های واقعی، می‌توانید از سنسورهای خارجی یا ورودی‌های دیگر نیز بهره ببرید.
نتیجه‌گیری
در کل، ساخت یک چارت نموداری زنده در سی‌شارپ، که شبیه اسیلوسکوپ باشد، نیازمند ترکیبی از مفاهیم برنامه‌نویسی گرافیکی، مدیریت زمان، و تولید داده‌های لحظه‌ای است. با رعایت نکات و ساختارهای گفته‌شده، می‌توان یک برنامه حرفه‌ای و کاربردی توسعه داد که قابلیت‌های زیادی داشته باشد. این پروژه نه تنها یک تمرین عالی است برای یادگیری عمیق‌تر مفاهیم گرافیکی و زمان‌بندی در برنامه‌نویسی ویندوز، بلکه می‌تواند در توسعه سیستم‌های اندازه‌گیری، تحلیل سیگنال، و یا ابزارهای تخصصی دیگر نیز مورد استفاده قرار گیرد.