Space Vector Modulation(SVM) Konusu

Başlatan Mucit23, 16 Mart 2018, 11:48:28

Mucit23

Teşekkürler hocam yarın deneyeceğim. Şuan zaten ben nerde hata yaptım ona bakıyorum. Benim yazdığım kodda sizinkine benziyor.

Mucit23

Hocam verdiğiniz yapıyı matlabda çalıştırdım. Aynı kodları şimdi Keilde STM32 üzerinde deniyorum. Matlabde Magnitude değeri 1 olduğu zaman aldığım sinyaller 1 arasında değişiyor. Mag değeri 0.5 olduğunda çıkış sinyalide ona göre düşüyor. Keilde yazdığımda ise Magnitude değeri 1 olduğu zaman aldığım sinyalin max değeri 0.66 oluyor.

Burada sinyali bozmadan Magnitude değerini ne kadar arttırabilirim?

Cemre.

Merhaba,

Magnitude aslında bir çarpan ve normalde max değeri belirli olmalı. Siz daha ziyade Modulasyon Index'i isimli bir değişken daha tanımlayıp onu da çarpan olarak denklemlere ekleyin. Aynı magnitude için farklı modülasyon indexlerinde farklı sonuçlar alabiliyor olun. Bu size esneklik sağlayacaktır. Benim denklemlerdeki mod_index değişkeni aslında max_magnitude gibi bir değişken olmalıymış. Üstünkörü yazınca böyle kalıyor bazen hatalı olarak. Mag değerini de max_mag ile saturasyona sokun tabiki. Bu şekilde max_mag değeri duty max değerine eşit olabilir.

Örn, PWM CCR Max değeri 1023 ise siz de bootstap'tan dolayı misal max_mag = 999 gibi bir şey yapabilirsiniz. Mag değerini de svpwm hesabı yapan fonksiyonda saturasyona sokarsınız.

Zoroaster

#18
Alıntı yapılan: Mucit23 - 21 Mart 2018, 14:52:36
Hocam verdiğiniz yapıyı matlabda çalıştırdım. Aynı kodları şimdi Keilde STM32 üzerinde deniyorum. Matlabde Magnitude değeri 1 olduğu zaman aldığım sinyaller 1 arasında değişiyor. Mag değeri 0.5 olduğunda çıkış sinyalide ona göre düşüyor. Keilde yazdığımda ise Magnitude değeri 1 olduğu zaman aldığım sinyalin max değeri 0.66 oluyor.

Burada sinyali bozmadan Magnitude değerini ne kadar arttırabilirim?

SVPWM ile ilgili yazımda hatırlarsan anahtarlar DC V kaynağı üzerinden yıldız yükü beslerken yükün her bir fazında en fazla 2V/3 voltajı oluşuyordu.

V=1 için  2/3=0.66 olduğundan senin de max değer olarak 0.66 görmen çok normal.

Yazım henüz tam bitmedi eğer işlem hatası yapmadıysam sinüsel bozulmaya uğramadan en fazla 0.577 V elde edebilirsin.
Seytan deliginden kacti.

Mucit23

Birkaç gündür işlerim dolayısıyla il dışına çıkmıştım. Bu yüzden biraz ara vermek zorunda kaldım.

Hocam şimdi Motor üzerinde deneme yaptım ama motoru düzgün çalıştıramadım. @Cemre. hocamın verdiği algoritmayı çalıştırıyorum. Yaptıklarımı anlatayım hatam varsa düzeltin.

İlk önce aşağıdaki tablodan hal sensörden gelen bilgiye göre açıyı belirledim. Şöyle bir tablo oluşturdum.


const uint16_t angle_map[7]={0,240,120,180,0,300,60};

Hall sensörlerden Exint kesmesi geldiğinde aşağıdaki kod parçacığıyla açıyı belirledim.

angle=angle_map[PMSM_HallSensorsGetPosition()]

PMSM_HallSensorsGetPosition fonksiyonu 001 011 010 110 100 101 şeklinde çıkış veriyor.

Main programda ise ADC den okuduğum değere göre genliği belirleyip cemre hocamın kodlarını çalıştırıyorum.
amp=(float)ADCConvertedValue/4095.0;
	
		ta=calc_ta_time(angle,amp);
		tb=calc_tb_time(angle,amp);
    tz = (1 - (ta + tb)) / 2;
    
		if(angle<60)
		{
		  pwmu = ta + tb + tz;
			pwmv = tb + tz;
			pwmw = tz;
		}
		else if(angle>=60 && angle<120)
		{
		  pwmu = ta + tz;
			pwmv = ta + tb + tz;
			pwmw = tz;		  
		}
		else if(angle>=120 && angle<180)
		{
			pwmu = tz;
			pwmv = ta + tb + tz;
			pwmw = tb + tz;		
		}
		else if(angle>=180 && angle<240)
		{
		  pwmu = tz;
			pwmv = ta + tz;
			pwmw = ta + tb + tz;			
		}
		else if(angle>=240 && angle<300)
		{
		  pwmu = tb + tz;
			pwmv = tz;
			pwmw = ta + tb + tz;	
		}
		else if(angle>=300 && angle<360)
		{
		  pwmu = ta + tb + tz;
			pwmv = tz;
			pwmw = ta + tz;			
		}
		
		pwmu=pwmu*4500;
		pwmv=pwmv*4500;
		pwmw=pwmw*4500;
		
		PMSM_SetPWM_UVW((uint16_t)pwmu,(uint16_t)pwmv,(uint16_t)pwmw);


PWM Periyodum yada Tim1 ARR değeri 16Khz için 4500, FOSC frekansım 72Mhz. Tim1 Presacaller değeri 1/1 dolayısıyla 72000000/4500 =16Khz yapıyor. Motoru 16Khz'de anahtarlıyorum.

Genlik değerini arttırdığımda motor videodaki gibi hareket ediyor.
https://www.youtube.com/watch?v=y7PKaFk_cvI

Bu komutasyon hatasımıdır? Neden olur bu durum?

Zoroaster

Bana aci tablon hatali gibi geldi

const uint16_t angle_map[7]={0,240,120,180,0,300,60};
001 011 010 110 100 101 şeklinde çıkış veriyor.


1,3,2,6,4,5

0,60,120,180,240,300 siraya sokarsak

const uint16_t angle_map[7]=0,0,120,60,240,300,180}; olmali

Seytan deliginden kacti.

Cemre.

Angle 60 derecelik dilimlerle mi değişiyor? Hall sensörleri dikkate almadan, çok düşük bir hızda angle 0-360 gezdirecek şekilde çalıştırmayı dener misiniz? Bir de Bootstrap'tan ötürü doluluğu 4500 yerine atıyorum 4500*95/100 gibi bir değer ile çarpmanızı tavsiye ederim. Bootstrap kapasitörlerine şarj olacak süreyi tanıdığımızı garanti etmiş olalım.

M.Salim GÜLLÜCE

Mucit anladığım kadarıyla 3 faz çalışan fırçasız motor sürmeye çalışıyorsun.
1-Temel olarak sinüs ile sürüldüğünde dengeli bir tork ve dönüş elde edilir.
2-Digital olarak sürmen gerektiğinden Sinüs e simule etmelisin.
3-Dünüş hısını Faz frekansı Dönüş torkunu ise Faz akımı belirler. (tüm fazların dengeli ve Faz açısı dışında eşit olduğunu belirtmek gerek)
4-Akım seviyesi torku belirlerken dönüş momentlerinde yük etkisine bağıl bir denge sağlamayı gerektirir.
5-Sürme işleminde Akımı belirlemek için PWM kullanmak zorunda olduğundan Bir periyodluk işlemi Sinüs simulasyonu (Sinüs tablosu) ile ve Darbe boşluk katsayısı ile belirlenebilir olduğundan PID kullanmak zorundasın.
6-PID için geri besleme referansı Hall effekt çıkışları olacak şekilde istenen deviri oluşturmada refeans teşkil etmelidir.
7-Düşük devirde Period başına PWM pals adedi artırıldığında stabil olacağından Yüksek devirde ise Dönüş momenti nedeniyle PWM pals adedini düşürmen verimliliği artıracaktır.

Mucit kardeşim muhtemelen bunları biliyorsun ve uygulamaya çalışıyorsun.
Aklımın erdiğince anlatmaya çalıştım. Sörçü lisan affola.

Acizane istenen devirle değişken yükle fırçalı motor sürmeye çalıştığımda da benzer problemler beni sıkıntıya sokmuştu.
umarım karınca kararınca faydam olur.

Mucit23

#23
Alıntı yapılan: Cemre. - 27 Mart 2018, 13:05:10
Angle 60 derecelik dilimlerle mi değişiyor? Hall sensörleri dikkate almadan, çok düşük bir hızda angle 0-360 gezdirecek şekilde çalıştırmayı dener misiniz? Bir de Bootstrap'tan ötürü doluluğu 4500 yerine atıyorum 4500*95/100 gibi bir değer ile çarpmanızı tavsiye ederim. Bootstrap kapasitörlerine şarj olacak süreyi tanıdığımızı garanti etmiş olalım.

Hocam denedim o şekilde de dönmüyor. Farklı bir sorun var gibi. Diğer bir taraftan boostrap için tolerans çok fazla. 4500=%100 duty. Benim SVPWM fonksiyonlarıma genlik olarak 1 verirsem max 0.66 gibi çıkış alıyorum. Dolayısıyla Duty çok yükselmiyor.

@Zoroaster Abi O şekilde de denedim. Önceden zorlada olsa dönüyordu. Şimdi sadece ileri geri yapıyor. Fazları değiştirdim aynı. Komutasyon sırasını değiştirdim ters yöne dönüyor ama yine aynı videodaki gibi dönüyor. Bana göre komutasyon yada açıyla ilgili bir durum. Doğru açıyı doğru sıralamayı nasıl tespit edebilirim abi?

@MehmetSalimGüllüce Bilgi için teşekkürler. Bende öğrene öğrene birşeyler yapmaya çalışıyorum. SVPWM konusundayım bu işi tam oturtamadım henüz.

Cemre.

Basit bir kontrol için V/f oranı sabit olacak şekilde deneyebilirsiniz.

Bir de, önce belirli bir magnitude'da 0derece açıda 200-300ms gibi bekletip rotorun başlangıç pozisyonuna gelmesini bekleyip daha sonra 0-360 gezecek şekilde deneyebilirsiniz.

Ben basit bir V/f kontrolü ve rampa fonksiyonu yazarak servo motor çalıştırmıştım. Uzun rampa süresi ile kaldırmak önemli. Aksi halde motor devrilip sizinki gibi hareketler sergileyecektir.

Cemre.

Alıntı yapılan: Mucit23 - 27 Mart 2018, 17:51:58
Benim SVPWM fonksiyonlarıma genlik olarak 1 verirsem max 0.66 gibi çıkış alıyorum. Dolayısıyla Duty çok yükselmiyor.

Burayı anlayamadım. Neden? Akşam eve gidince bir ekran görüntüsü paylaşacağım bununla alakalı.

Mucit23

Hocam ayrıntılı debug yapmadım. Matlab'da duruö böyle değil. Genlik değerini 1 verirsem max genlik 1 oluyor ama STM32'de böyle olmuyor. Yapılan işlem aynı ama sonuç farklı.

Buda tam çalışan kod.
int main(void)
{ 
	SysTick_init();
	
	GPIO_Configuration();
	NVIC_Configuration();
	USART2_Configuration();
	ADC_DMA_Configuration();
  PMSM_PWMTimer_Init();
	PMSM_HALL_Init();
	
	while(1)
  {  
		
		amp=(float)ADCConvertedValue/4095.0;
	
		ta=calc_ta_time(angle,amp);
		tb=calc_tb_time(angle,amp);
    tz = (1 - (ta + tb)) / 2;
    
		if(angle<60)
		{
		  pwmu = ta + tb + tz;
			pwmv = tb + tz;
			pwmw = tz;
		}
		else if(angle>=60 && angle<120)
		{
		  pwmu = ta + tz;
			pwmv = ta + tb + tz;
			pwmw = tz;		  
		}
		else if(angle>=120 && angle<180)
		{
			pwmu = tz;
			pwmv = ta + tb + tz;
			pwmw = tb + tz;		
		}
		else if(angle>=180 && angle<240)
		{
		  pwmu = tz;
			pwmv = ta + tz;
			pwmw = ta + tb + tz;			
		}
		else if(angle>=240 && angle<300)
		{
		  pwmu = tb + tz;
			pwmv = tz;
			pwmw = ta + tb + tz;	
		}
		else if(angle>=300 && angle<360)
		{
		  pwmu = ta + tb + tz;
			pwmv = tz;
			pwmw = ta + tz;			
		}
		
		pwmu=pwmu*4500;
		pwmv=pwmv*4500;
		pwmw=pwmw*4500;
		
		PMSM_SetPWM_UVW((uint16_t)pwmu,(uint16_t)pwmv,(uint16_t)pwmw);
		
    sprintf(txt,"angle=%d %f %f %f\n",angle,pwmu,pwmv,pwmw);
	  printf(txt);
//	 	delay_ms(1);
//		
//		angle++;
//		if(angle>359)
//		{ 
//		   angle=0;	
//		}	

  }
}


float calc_ta_time(uint16_t Angle, float amplitude)
{
  float AngleRad = (Angle % 60) * RAD2DEG;
	float Ta = 0;
	
	Ta = ((amplitude * cos(AngleRad)) / Mod_Index) - (((amplitude * sin(AngleRad)) / Mod_Index) * (1/sqrt(3)));
	 
	return Ta;
}

float calc_tb_time(uint16_t Angle, float amplitude)
{
  float AngleRad = (Angle % 60) * RAD2DEG;
	float Tb = 0;
	
  Tb = ((amplitude * sin(AngleRad)) / Mod_Index) * (2 / sqrt(3));
	
	return Tb;
}

marecrisium

Alıntı yapılan: Mucit23 - 27 Mart 2018, 18:15:23
Hocam ayrıntılı debug yapmadım. Matlab'da duruö böyle değil. Genlik değerini 1 verirsem max genlik 1 oluyor ama STM32'de böyle olmuyor. Yapılan işlem aynı ama sonuç farklı.

Buda tam çalışan kod.
int main(void)
{ 
   SysTick_init();
   
   GPIO_Configuration();
   NVIC_Configuration();
   USART2_Configuration();
   ADC_DMA_Configuration();
  PMSM_PWMTimer_Init();
   PMSM_HALL_Init();
   
   while(1)
  {  
      
      amp=(float)ADCConvertedValue/4095.0;
   
      ta=calc_ta_time(angle,amp);
      tb=calc_tb_time(angle,amp);
    tz = (1 - (ta + tb)) / 2;
    
      if(angle<60)
      {
        pwmu = ta + tb + tz;
         pwmv = tb + tz;
         pwmw = tz;
      }
      else if(angle>=60 && angle<120)
      {
        pwmu = ta + tz;
         pwmv = ta + tb + tz;
         pwmw = tz;        
      }
      else if(angle>=120 && angle<180)
      {
         pwmu = tz;
         pwmv = ta + tb + tz;
         pwmw = tb + tz;      
      }
      else if(angle>=180 && angle<240)
      {
        pwmu = tz;
         pwmv = ta + tz;
         pwmw = ta + tb + tz;         
      }
      else if(angle>=240 && angle<300)
      {
        pwmu = tb + tz;
         pwmv = tz;
         pwmw = ta + tb + tz;   
      }
      else if(angle>=300 && angle<360)
      {
        pwmu = ta + tb + tz;
         pwmv = tz;
         pwmw = ta + tz;         
      }
      
      pwmu=pwmu*4500;
      pwmv=pwmv*4500;
      pwmw=pwmw*4500;
      
      PMSM_SetPWM_UVW((uint16_t)pwmu,(uint16_t)pwmv,(uint16_t)pwmw);
      
    sprintf(txt,"angle=%d %f %f %f\n",angle,pwmu,pwmv,pwmw);
     printf(txt);
//       delay_ms(1);
//      
//      angle++;
//      if(angle>359)
//      { 
//         angle=0;   
//      }   

  }
}


float calc_ta_time(uint16_t Angle, float amplitude)
{
  float AngleRad = (Angle % 60) * RAD2DEG;
   float Ta = 0;
   
   Ta = ((amplitude * cos(AngleRad)) / Mod_Index) - (((amplitude * sin(AngleRad)) / Mod_Index) * (1/sqrt(3)));
    
   return Ta;
}

float calc_tb_time(uint16_t Angle, float amplitude)
{
  float AngleRad = (Angle % 60) * RAD2DEG;
   float Tb = 0;
   
  Tb = ((amplitude * sin(AngleRad)) / Mod_Index) * (2 / sqrt(3));
   
   return Tb;
}



Hocam kodun ta ve tb sürelerini hesaplama fonksiyonlarında bir gariplik var gibi.


float AngleRad = (Angle % 60) * RAD2DEG;


Burada Angle değeriniz için {0,240,120,180,0,300,60} değerinden birisi olması gerekli, bu değerlerin 60'a göre modu hepsinde sıfır olmaz mı ?
Her açı için aynı AngleRad değeri hesaplanıyor gibi geldi bana.



Cemre.

@Mucit23

CCRx_Max değeri ile grafikteki max değerin eşit olduğunu görebilirsiniz. Sizinle paylaştığım yapının C implementasyonundan farklı bir kod çalıştırmıyorum ben de.



Mucit23

Hocam ona yarın ayrıntılı olarak bakacağım ama öncelikle 60'ar derecelik komutasyonda neden düzgün bir döner alan elde edemiyorum onu çözmem gerekiyor. Şuanda genliğin tam 1 olmaması çok da sorun yaratmıyor.


@marecrisium evet haklısın açının 60'a modu sürekli sıfır oluyor fakat açıyla birlikte sektörde değiştiği pwm değerleri sürekli değişiyor. Sorun  burada olabilirmi emin değilim.