 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                              
 //   Данный алгоритм предназначен для анализа параметров систем зажигания ДВС  
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                              
 //                               Используемые константы                             
 InductSenThreshold = 0.05;      // 50 mV пороговое напряжение для индуктивного датчика                             
 CapSenThreshold = 0.2;           // 200 mV пороговое значение для ёмкостного                             
 ScaleFactor = 10000;                // 1:10`000 Коэффициент деления ёмкостного датчика                            
 ///////////////////////////////////////////////////////////////////////////                              
 var EngTypes = Array("1-3-4-2","1-2-4-5-3","1-5-3-6-2-4","1-4-3-6-2-5","1-4-2-5-3-6","1-2-3-4-5-6","1-5-4-8-6-3-7-2","1-8-4-3-6-5-7-2","1-2-3","1-3-2","1-2-4-3","1-2","1");        
 //var EngCylinders = Array(4,5,6,6,6,6,8,8,3,3,4,2,1);        
         
 var Setup = CreateConfigure("Ignition check");                                  
                               
 DataChannel = "Канал ёмкостного датчика";                               
 EngineType  = "Тип двигателя";        
                                  
 Setup.AddItem(DataChannel, 1);                                  
 Setup.AddItem(EngineType, EngTypes.join("\n"));                                  
                                  
 Setup.Configure();                                  
                                  
 DataChannel = Setup.GetValue(DataChannel);                                     
 EngineType = Setup.GetValue(EngineType);        
  
 var EngCylinders = EngTypes[EngineType].split("-"); 
 Cylinders = EngCylinders.length; 
  
                
 if (DataChannel > 0 && DataChannel <= 2)// Validate number of data channel is used for capacitor sensor                     
 /////////////////////////////////////////////////////////////////////(присвоить каналу данных номер канала ёмкостного датчика)                     
 {                                
  if (Cylinders > 0 && Cylinders <= 8)////////////////////////////////////// Validate number of engine cylinders ( 0 < проверка количества цилиндров < 8 )                            
  {                              
   if (DataType == "ANA" && Frequency >= 125000 && Channels == 2)///////////////////////////// Validate type of source data ( проверка типа данных )                         
   {                                     
     TotalSize = NumberOfSamples;                                     
                                  
     ReportOut("Анализ запущен\t\t\tразмер массива данных: " + TotalSize.toString(10)+"\n");                                         
     ReportOut("Тип двигателя: " + EngTypes[EngineType] + "\n==============================================================\n");                                         
                              
     DataChannel ^= 3;//////////////////////// Set induction sensor channel number (присвоить каналу данных номер канала индуктивного датчика)                             
                              
     SynLevel = InductSenThreshold*GetFullScale(DataChannel)/30;                              
                                   
     MaxStrobe = new Array(Cylinders);                              
     MaxStrobePos = new Array(Cylinders);                              
     CylinderDelay = Frequency/Cylinders;                              
     CurDelay = 0;/////////////////////////////////////////////////// unlimited interval for first strobe                              
     MaxDelay = 1000/(1000000/Frequency);/////////// number of samples for 1,5 ms (интервал для поиска max импульса индуктивного датчика)                     
     var CurValue;                              
                                  
     for (iStrobe = 0; iStrobe < Cylinders; iStrobe++)                              
      MaxStrobe[iStrobe] = 0;                              
                                   
     for (CurPos = 0, iStrobe = 0; CurPos < TotalSize && iStrobe < Cylinders*3; iStrobe++)                              
     {                              
      CurPos = SynchBy(DataChannel, 1, SynLevel, CurPos, CurDelay);                                     
      CurDelay = CylinderDelay;                              
                                    
      if (CurPos > 0)                              
      {                              
       Max = 0;                              
                                     
       if ( iStrobe < Cylinders )                              
        MaxStrobePos[iStrobe] = CurPos;                              
                                      
         for (i=0; i<MaxDelay; i++)                              
       {                              
        CurValue = ValueAt(DataChannel, CurPos++);                              
                                      
        if (Max < CurValue)                              
         Max = CurValue;                              
       }                              
                                     
       MaxStrobe[iStrobe % Cylinders] += Max;                              
      }                              
      else                              
       break;                              
                                     
      CurPos += 1000/(1000000/Frequency);///////////////////////////////////////////////////////           
      //////////////////////////////////////////////////////////////Shift in time on 1 ms.                              
     }                              
                                   
     if (iStrobe == Cylinders*3)                              
     {                              
      Max = 0;                              
                                   
      for (iStrobe = 0; iStrobe < Cylinders; iStrobe++)                              
      {                              
       if (Max < MaxStrobe[iStrobe])                              
       {                              
        Max = MaxStrobe[iStrobe];                              
        CurPos = MaxStrobePos[iStrobe];                              
       }                              
      }                              
                                    
      SetMarker(CurPos, "Синхронизирующий цилиндр (№1)");                                                   
                                    
      DataChannel ^= 3;/////////////////////////////////////////// Set capacitor sensor channel number            
      ////////////////////////////////         (присвоить каналу данных номер канала ёмкостного датчика)                             
      CurPos -= 1000/(1000000/Frequency);///////////Shift back in time for 1 ms.                              
                                    
      if (CurPos < 0)                              
       CurPos = 0;                              
                                    
      SynLevel = CapSenThreshold*GetFullScale(DataChannel)/30;                              
                                    
      delete MaxStrobe;                              
      delete MaxStrobePos;                              
                                    
      AveDisruption = new Array(Cylinders);                              
      MaxDisruption = new Array(Cylinders);                              
      MinDisruption = new Array(Cylinders);                              
                                    
      AveBurnVoltage = new Array(Cylinders);                              
      MaxBurnVoltage = new Array(Cylinders);                              
      MinBurnVoltage = new Array(Cylinders);                                    
                                    
      AveBurnTime = new Array(Cylinders);                              
      MaxBurnTime = new Array(Cylinders);                              
      MinBurnTime = new Array(Cylinders);                                
                                    
      AveCntr = new Array(Cylinders);                                
                                    
      for (iStrobe = 0; iStrobe < Cylinders; iStrobe++)                              
      {                              
       AveDisruption[iStrobe] = 0;                              
       MaxDisruption[iStrobe] = 0;                              
       MinDisruption[iStrobe] = GetFullScale(DataChannel);                              
                                    
       AveBurnVoltage[iStrobe] = 0;                              
       MaxBurnVoltage[iStrobe] = 0;                              
       MinBurnVoltage[iStrobe] = GetFullScale(DataChannel);                              
                                    
       AveBurnTime[iStrobe] = 0;                              
       MaxBurnTime[iStrobe] = 0;                              
       MinBurnTime[iStrobe] = Frequency;//////////////////////////// for 1 sec.///////////////////////////////                             
                                     
       AveCntr[iStrobe] = 0;                              
      }                              
                                  
      MaxDelay = 50/(1000000/Frequency);// number of samples for 50 us         (интервал для поиска max напряжения пробоя)                     
      CheakDelay = 100/(1000000/Frequency);// number of samples for 100 us  ( усреднение слева и справа)                     
      //                     
      //                     
      BurnDetDelay = 2500/(1000000/Frequency);/////////////////////////////////////////////////////////           
      ///////////////////////////////////////////////// number of samples for 2 ms ( мах время горения )                            
      //                     
      //                     
      BurnEndDelay = 50/(1000000/Frequency);///////////////////////////////////////////////////////////           
      //////////////////////////////////////////// number of samples for 50 us  ( отступ влево от конца горения )                            
                                    
      for (iStrobe = 0; CurPos < TotalSize;)                              
      {                              
       CurPos = SynchBy(DataChannel, 1, SynLevel, CurPos, CylinderDelay);                                     
       //CurDelay                              
       if (CurPos > 0 && (CurPos + BurnDetDelay + MaxDelay) < TotalSize)                              
       {                              
        LeftAve = 0;                              
        RightAve = 0;                              
        LeftCntr = 0;                              
                     
        for (i=0; i<CheakDelay; i++)                               
        {                              
         if ((CurPos - CheakDelay + i) >= 0)                              
         {                              
          LeftAve += ValueAt(DataChannel, CurPos - CheakDelay + i);                              
          LeftCntr++;                              
         }                              
                                       
         RightAve += ValueAt(DataChannel, CurPos + i);                              
        }                              
                                      
        LeftAve /= LeftCntr;                              
        RightAve /= CheakDelay;                              
                                               
        if (LeftAve + SynLevel/2 < RightAve) //Сравнение разницы усреднённых напряжений справа и слева строба                             
        {///////////////////////////////////////////////////////////////////////////////////// Ok strobe found                              
         Max = 0;                              
                                       
          for (i=0; i<MaxDelay; i++)                              
         {                              
          CurValue = ValueAt(DataChannel, CurPos++);                              
                                      
          if (Max < CurValue)                              
           Max = CurValue;                              
         }                               
                       
         AveDisruption[iStrobe] += Max;                              
                                       
         if ( Max > MaxDisruption[iStrobe] )                              
          MaxDisruption[iStrobe] = Max;                                       
                                        
         if ( Max < MinDisruption[iStrobe] )                              
          MinDisruption[iStrobe] = Max;                                                 
                                                          
         EndPos = SynchBy(DataChannel, -1, LeftAve, CurPos, BurnDetDelay);//LeftAve SynLevel                              
                                       
         if (EndPos > 0)                              
         {///////////////////////////////////////////////////////////////////////////////////// calculate burn parameters                              
          Max = EndPos - CurPos - BurnEndDelay;                              
          ////////////////////////////////////////////////////////////////////////////////////// burn time                              
          AveBurnTime[iStrobe] += Max;                              
                                        
          if ( Max > MaxBurnTime[iStrobe] )                              
           MaxBurnTime[iStrobe] = Max;                                       
                                        
          if ( Max < MinBurnTime[iStrobe] )                              
           MinBurnTime[iStrobe] = Max;                                                           
                                         
          ////////////////////////////////////////////////////////////////////////////////////// burn voltage                                         
          for (CurValue = 0; CurPos < (EndPos - BurnEndDelay); CurPos++)                              
           CurValue += ValueAt(DataChannel, CurPos);                              
                                         
          CurValue /= Max;                              
                                         
          AveBurnVoltage[iStrobe] += CurValue;                              
                                        
          if ( CurValue > MaxBurnVoltage[iStrobe] )                              
           MaxBurnVoltage[iStrobe] = CurValue;                                       
                                        
          if ( CurValue < MinBurnVoltage[iStrobe] )                              
           MinBurnVoltage[iStrobe] = CurValue;                                                                      
                                         
          CurPos += BurnDetDelay;                               
          AveCntr[iStrobe]++;                              
         }                              
         else                              
         {                              
          SetMarker(CurPos, "Ошибка определения участка горения искры");                                                            
          ReportOut("Ошибка определения участка горения искры (смотрите маркер)\n");                                       
          break;                              
         }                              
                                      
         if( ++iStrobe >= Cylinders )                              
          iStrobe = 0;                              
        }                              
        else                              
        {                              
         //SetMarker(CurPos, "Error");                                                            
         break;                              
        }                              
       }                              
       else                              
        break;                              
       }                              
                                    
      for (iStrobe = 0; iStrobe < Cylinders; iStrobe++)                              
      {                              
       if (AveCntr[iStrobe] == 0)                              
        break;                              
      }                              
                                    
      if (iStrobe == Cylinders)                              
      {// Ok data ready                              
       ScaleFactor /= GetFullScale(DataChannel)/30;                              
                                  
       for (iStrobe = 0; iStrobe < Cylinders; iStrobe++)                              
       {                              
        CurValue = EngCylinders[iStrobe];//iStrobe+1;   ///////////////////////////////               
        ReportOut("\n\n=======================     Цилиндр: " +  CurValue.toString(10) + "    =========================\n\n\t\t\tМин.\tСред\tМак.\tРазм.\n");                              
                                      
        CurValue = Math.round(MinDisruption[iStrobe]*ScaleFactor/100)/10;                              
        ReportOut("Напряжение пробоя:\t" + CurValue.toString(10));                                       
        CurValue = Math.round(AveDisruption[iStrobe]/AveCntr[iStrobe]*ScaleFactor/100)/10;                              
        ReportOut("\t" + CurValue.toString(10));                                       
        CurValue = Math.round(MaxDisruption[iStrobe]*ScaleFactor/100)/10;                              
        ReportOut("\t" + CurValue.toString(10));                                               
                                      
        ReportOut("\tkV\n");                                                       
                                      
        CurValue = Math.round(MinBurnVoltage[iStrobe]*ScaleFactor/100)/10;                              
        ReportOut("Напряжение горения:\t" + CurValue.toString(10));                                       
        CurValue = Math.round(AveBurnVoltage[iStrobe]/AveCntr[iStrobe]*ScaleFactor/100)/10;                              
        ReportOut("\t" + CurValue.toString(10));                                       
        CurValue = Math.round(MaxBurnVoltage[iStrobe]*ScaleFactor/100)/10;                              
        ReportOut("\t" + CurValue.toString(10));                                                       
                                      
        ReportOut("\tkV\n");                                                       
                                      
        CurValue = Math.round(MinBurnTime[iStrobe]/Frequency*1000*10)/10;                              
        ReportOut("Время горения:\t\t" + CurValue.toString(10));                                       
        CurValue = Math.round(AveBurnTime[iStrobe]/AveCntr[iStrobe]/Frequency*1000*10)/10;                              
        ReportOut("\t" + CurValue.toString(10));                                       
        CurValue = Math.round(MaxBurnTime[iStrobe]/Frequency*1000*10)/10;                              
        ReportOut("\t" + CurValue.toString(10));//" мс\n"                              
                                      
        ReportOut("\tms\n");                                                       
       }                              
                                     
       ReportOut("\n\n==============================================================\nПроанализировано циклов: " + AveCntr[0].toString(10) + " \n");                              
      }                              
     }                              
     else                              
      ReportOut("Недостаточно данных для синхронизации цилиндров.\n");                                       
                                     
    ReportOut("Анализ завершён\n");                              
   }                                     
   else                                     
    ReportOut("Неверный формат данных!\nРекомендованный формат: 2-канала, развертка-0.200 ms");                              
  }                              
  else                                     
   ReportOut("Неверное количество цилиндров \t\t\tN = " + Cylinders.toString(10) + "\nУкажите количество цилиндров в диапазоне \t\t0 < N < 8");                              
 }                              
 else                                     
  ReportOut("Неверный номер канала ёмкостного датчика -" + DataChannel.toString(10)+"\n");        
          
///////////////////////////////////////////////////////////////////////////////////////////        
//        
///////////////////////////////////////////////////////////////////////////////////////////        
      
