반응형

 

	public double ThresholdCurrent(in double[] Current, in double[] Power, double PowerLow, double PowerHigh)
	{
		double thresholdCurrent = 0;

		try
		{
			int startIndex = Array.FindIndex(Power, x => x >= PowerLow);
			int endIndex = Array.FindIndex(Power, x => x >= PowerHigh);

			var subCurrent = Current.Skip(startIndex).Take(endIndex - startIndex + 1).ToArray();
			var subPower = Power.Skip(startIndex).Take(endIndex - startIndex + 1).ToArray();

			var (slope, intercept) = LeastSquaresFit(subCurrent, subPower);

			if(slope != 0) thresholdCurrent = -intercept / slope;            
		}
		catch
		{
			thresholdCurrent = 0 ;
		}		

		return thresholdCurrent;
	}	
	//-----------------------------------------------------------------------------------------------------------------
	private (double Slope, double Intercept) LeastSquaresFit(double[] x, double[] y)
	{
		int n = x.Length;        
        
        double sumX = x.Sum();
        double sumY = y.Sum();
        double sumXY = x.Zip(y, (xi, yi) => xi * yi).Sum();
        double sumXX = x.Select(xi => xi * xi).Sum();
        
        var Slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
        var yIntercept = (sumY - slope * sumX) / n;
		
		return (slope, yIntercept);
	}
	//-----------------------------------------------------------------------------------------------------------------
반응형
반응형
double __fastcall Kink(double* Current, double* SE, int count)
{
double kink1=999.9 ;
double* coeff ;
double max, min, se_offset, temp ;
try
{
	coeff = Polynomial_Fitting(Current, SE, 2, count) ;

	temp = (coeff[2]*pow(Current[0], 2)) + (coeff[1]*Current[0]) + coeff[0] ;

	min   = SE[0] - temp ;
	max   = SE[0] - temp ;

	for(int loop=1 ; loop<count ; loop++)
	{
		temp = (coeff[2]*pow(Current[loop], 2)) + (coeff[1]*Current[loop]) + coeff[0] ;
		se_offset = SE[loop] - temp ;

		if(se_offset > max)
		{
			max = se_offset ;
		}

		if(se_offset < min)
		{
			min = se_offset ;
		}
	}

	if(SE[0] != 0) 
	{
		kink1 = ((fabs(max) + fabs(min)) / SE[0]) * 100 ;
	}
}
catch(...)
{
	kink1=999.9 ;
}

return kink1 ;
}

//---------------------------------------------------------------------------
double* __fastcall Polynomial_Fitting(double* x, double* y, const int degree, int Size)
{
/*********************************************************
x : X 축 데이타
y : Y 축 데이타
degree : 다항식 차수
size : 데이타 수
**********************************************************/

    int N=Size ;
    int n = degree ;
    int i, j, k ;
    double X[2*2+1];                        //Array that will store the values of sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2n)
    double B[2+1][2+2],a[2+1];            //B is the Normal matrix(augmented) that will store the equations, 'a' is for value of the final coefficients
    double Y[2+1];                    //Array to store the values of sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^n*yi)
    
    for(i=0 ; i<2*n+1 ; i++)
    {
    	X[i]=0;
    	for (j=0 ; j<N ; j++)
    	{
    		X[i]=X[i] + pow(x[j],i);        //consecutive positions of the array will store N,sigma(xi),sigma(xi^2),sigma(xi^3)....sigma(xi^2n)
    	}
    }
    
    for (i=0 ; i<=n ; i++)
    {
    	for (j=0 ; j<=n ; j++)
    	{
    		B[i][j] = X[i+j];            //Build the Normal matrix by storing the corresponding coefficients at the right positions except the last column of the matrix
    	}
    }
    
    for (i=0 ; i<n+1 ; i++)
    {
    	Y[i]=0;
    	for (j=0;j<N;j++)
    	Y[i]=Y[i] + pow(x[j],i) * y[j];        //consecutive positions will store sigma(yi),sigma(xi*yi),sigma(xi^2*yi)...sigma(xi^n*yi)
    }
    
    for(i=0 ; i<=n ; i++) B[i][n+1]=Y[i];                //load the values of Y as the last column of B(Normal Matrix but augmented)
    n = n + 1 ;                //n is made n+1 because the Gaussian Elimination part below was for n equations, but here n is the degree of polynomial and for n degree we get n+1 equations
    
    for(i=0 ; i<n ; i++)                    //From now Gaussian Elimination starts(can be ignored) to solve the set of linear equations (Pivotisation)
    {
    	for (k=i+1 ; k<n ; k++)
    	{
    		if (B[i][i]<B[k][i])
    		{
    			for (j=0 ; j<=n ; j++)
    			{
    				double temp=B[i][j];
    				B[i][j]=B[k][j];
    				B[k][j]=temp;
    			}
    		}
    	}
    }
    
    for(i=0 ; i<n-1 ; i++)            //loop to perform the gauss elimination
    {
    	for(k=i+1 ; k<n ; k++)
    	{
    		double t=B[k][i] / B[i][i];
    		for(j=0 ; j<=n ; j++)
    			B[k][j] = B[k][j]-t*B[i][j];    //make the elements below the pivot elements equal to zero or elimnate the variables
    	}
    }
    
    for(i=n-1 ; i>=0 ; i--)                //back-substitution
    {                        //x is an array whose values correspond to the values of x,y,z..
    	a[i]=B[i][n];                //make the variable to be calculated equal to the rhs of the last equation
    	for(j=0 ; j<n ; j++)
    	{
    		if(j!=i) a[i]=a[i]-B[i][j]*a[j];           //then subtract all the lhs values except the coefficient of the variable whose value is being calculated
    	}
    
    	a[i]=a[i]/B[i][i];            //now finally divide the rhs by the coefficient of the variable to be calculated
    }
    
    return a ;
}
반응형
반응형

 

Public Sub CalcELmaxQE(ByRef Data As MeasureData_typ)
    Dim i As Integer
    
    ''--(1)--파장의 피크값을 찾는 루틴
    Dim max As Double
    ''--(1-1)-- Find the max starting from the left
    Dim indexLeft As Integer
    indexLeft = 0
    max = Data.LL(0)
    For i = 1 To Data.DataLen
        If max < Data.LL(i) Then
            max = Data.LL(i)
            
            indexLeft = i
        End If
    Next i

    ''--(1-2)-- 스펙트럼의 오른쪽부터 시작하여 피크치가 어떤 파장값인지 서치하는 루틴
    Dim indexRight As Integer
    indexRight = 0
    max = Data.LL(0)
    For i = Data.DataLen To 1 Step (-1)
        If max < Data.LL(i) Then
            max = Data.LL(i)
            
            indexRight = i
        End If
    Next i
    
    ''--(1-3)-- 왼쪽의 max와 오른쪽의 max값 사이의 중간파장값을 찾는 서치루틴 
      (정확한 피크값을 찾기 위한 방법)
    Dim Index As Integer
    If (indexLeft = indexRight) Then
        Index = indexLeft
    Else
        Index = indexLeft + (indexRight - indexLeft) / 2
    End If
    
    m_MeasDataPoint.Meas_ELmax = Data.wave(Index)
    
    ''--(2)--Q.E
    ''--(2-1)--각 파장에서의 광자(photon)의 갯수
    For i = 0 To Data.DataLen
        Data.x(i) = Data.LL(i) / ((6.6E-34) * 300000000 / (Data.wave(i) * 0.000000001)) * 3.14
    Next i
    
    ''--(2-2)--광자의 토탈 갯수
    Dim gNumber As Double     '
    gNumber = 0
    For i = 0 To Data.DataLen
        gNumber = gNumber + Data.x(i)
    Next i
    
    ''--(2-3)--전류밀도 
    Dim ifData As Double
    ifData = m_MeasDataPoint.Meas_If
    
    Dim area As Double
    area = m_SystemSpec.AreaOfEL_mm2
    
    Dim currentDensity As Double
'''    currentDensity = ifData / ((2 * 0.001) * (2 * 0.001))
''    currentDensity = ifData / (2 * 2 )
    If (area <> 0) Then
        currentDensity = ifData / area
'''        currentDensity = ifData / (area * 0.001 * 0.001)
    Else
        currentDensity = 9999999
    End If
    
    ''--(2-4)--injected electrons의 갯수
    Dim eNumber As Double
    eNumber = currentDensity / 1.6E-19
    
    ''--(2-5)--Q.E
    If (eNumber <> 0) Then
        m_MeasDataPoint.Meas_QE = (gNumber / eNumber) * 100
    Else
        m_MeasDataPoint.Meas_QE = -99.9
    End If
End Sub
반응형
반응형

스펙트로메타를 통해 LED의 스펙트럼 데이타를 추출한 후 색좌표 상의 u',v'(CIE1976) 을 계산하는 알고리즘 입니다. 

table.h
0.02MB

void CIE1976_Chromaticity(double* Wavelength, double* Spectrum,  int Length, double& uPrime, double& vPrime)
{
    double TristimulusX, TristimulusY, TristimulusZ;
    Tristimulus_Value(Wavelength, Spectrum, Length, TristimulusX, TristimulusY, TristimulusZ) ;

    try
    {
        uPrime = (4 * TristimulusX) / (TristimulusX + (TristimulusY * 15) + (TristimulusZ * 3)) ;
        vPrime = (9 *TristimulusY) / (TristimulusX + (TristimulusY * 15) + (TristimulusZ * 3)) ;
    }
    catch(...)
    {
        uPrime = 0 ;
        vPrime = 0 ;
    }
}
//---------------------------------------------------------------------------
void Tristimulus_Value(double* Wavelength, double* Spectrum, int Length, double& TristimulusX, double& TristimulusY, double& TristimulusZ)
{
    double X=0, Y=0, Z=0 ;
    double delta_wavelength = 380 ;
    int index = 0 ;
	
    for(int loop=0 ; loop<Length ; loop++)       // 380nm ~ 830nm 까지의 영역만 계산 ( 1nm 간격 )
    {
        if(Wavelength[loop] > 830) break ;
		
        if(Wavelength[loop] >= delta_wavelength)
        {
            X += (rgb_table[index].Red * Spectrum[loop]) ;
            Y += (rgb_table[index].Green * Spectrum[loop]) ;
            Z += (rgb_table[index].Blue * Spectrum[loop]) ;
			
            index ++ ;
            delta_wavelength += 1 ;    	// 1nm 증가 
        }		
    }	
	
    TristimulusX  = X * K ;
    TristimulusY  = Y * K ;
    TristimulusZ  = Z * K ;	
}
반응형
반응형

LD(Laser Diode)는 낮은 전류에서는 LED처럼 동작하지만 일정전류 이상(임계전류) 부터는 발진이 되면서 광출력이 급격히 증가하는 현상이 나타나게 됩니다. LD 의 특성 평가에서 이 임계전류값은 중요한 특성지표로 사용이 됩니다.  

임계전류를 계산하는 방식은 여러 방법이 있습니다. 이번장에서는 대표적인 방법으로 Least Square(직선근사) 방식을 이용한 Threshold Current 계산 코드를 적용하였습니다. 

Threshold Current
Threshold Current&nbsp; 정의

1. 계산 파라메타 ( 아래 이미지 참조 )

  *  Pth1, Pth2 : 전체 측정 파워데이타 중에서 직선근사를 적용할 파워의 범위 ( 가능한 낮은 파워구간을 선택하는것이 좋다.)

  * vector<float> Power : 측정된 파워 데이타 

  * vector<float> Current : 측정된 전류 데이타

Threshold Current
측정 파라메타 정보

2. 계산 알고리즘 코드 ( C++ )

vector<float> Current ;
vector<float> Power ;

float Ith_LeastSquare_Method(const float Pth1, const float Pth2)
{
    float fDegree, fYvalue, result ;

    tuple<float, float>value = LeastSquare(Current, Power, powerLow, powerHigh) ;

    fDegree = get<0>(value) ;    // 직선의 방정식의 기울기 
    fYvalue = get<1>(value) ;    // 직선의 방정식의 Y 절편 

    if(fDegree == 0) result = -1 ;
    else
    {
        try
        {
            result = -fYvalue / fDegree ;    // 직선의 방정식에서 X 절편값 계산(Ith)
        }
        catch(...)
        {
            result = -1 ;
        }
    }

    return result ;
}
//---------------------------------------------------------------------------
tuple<float, float> __fastcall CLIV_Calculate_Data::LeastSquare(const vector<float>& xAxis, const vector<float>& yAxis, const float lowValue, const float highValue)
{
    float sumx=0, sumy=0, sumxx=0, sumxy=0 ;
    float mother, child1, child2 ;
    float rDegree, rYvalue ;
    int index = 0, length = 0 ;

    auto endIt = cend(yAxis) ;
    auto startIt  = find_if(cbegin(yAxis), endIt, [lowValue](float i){ return i >= lowValue ; }) ;
    auto finishIt = find_if(cbegin(yAxis), endIt, [highValue](float i){ return i >= highValue ; }) ;

    if(finishIt == endIt)
    {
        rDegree = rYvalue = 0 ;
    }
    else
    {
        index = startIt - cbegin(yAxis);

        for(auto yIt = startIt ; yIt != finishIt ; ++yIt)
        {
            sumx += xAxis[index] ;
            sumy += *yIt ;
            sumxx += (xAxis[index] * xAxis[index]) ;
            sumxy += (xAxis[index] * (*yIt)) ;
            length ++ ;
            index ++ ;
        }

        mother = (length * sumxx) - (sumx * sumx) ;
        child1 = (length * sumxy) - (sumx * sumy) ;
        child2 = (sumxx  * sumy)  - (sumxy * sumx) ;

        if(mother == 0) rDegree = rYvalue = 0 ;
        else
        {
            rDegree = child1 / mother ;
            rYvalue = child2 / mother ;
        }
    }

    return make_tuple(rDegree, rYvalue) ;
}
//---------------------------------------------------------------------------

 

반응형
반응형

table.h
0.02MB

계산상 필요한 table 은 위의 파일을 다운로드 받으세요

스펙트로메타를 통해 LED의 스펙트럼 데이타를 추출한 후 색좌표 상의 x,y (CIE1931)값을 계산하는 알고리즘 입니다. 

void CIE1931_Chromaticity(double* Wavelength, double* Spectrum,  int Length, double& x, double& y)
{
    double TristimulusX, TristimulusY, TristimulusZ;
    
    Tristimulus_Value(Wavelength, Spectrum, Length, TristimulusX, TristimulusY, TristimulusZ) ;

    try
    {
        x = TristimulusX / (TristimulusX + TristimulusY + TristimulusZ) ;
        y = TristimulusY / (TristimulusX + TristimulusY + TristimulusZ) ;
    }
    catch(...)
    {
        x = 0 ;
        y = 0 ;
    }
}
//---------------------------------------------------------------------------
void Tristimulus_Value(double* Wavelength, double* Spectrum, int Length, double& TristimulusX, double& TristimulusY, double& TristimulusZ)
{
    double X=0, Y=0, Z=0 ;
    double delta_wavelength = 380 ;
    int index = 0 ;
	
    for(int loop=0 ; loop<Length ; loop++)       // 380nm ~ 830nm 까지의 영역만 계산 ( 1nm 간격 )
    {
        if(Wavelength[loop] > 830) break ;
		
        if(Wavelength[loop] >= delta_wavelength)
        {
            X += (rgb_table[index].Red * Spectrum[loop]) ;
            Y += (rgb_table[index].Green * Spectrum[loop]) ;
            Z += (rgb_table[index].Blue * Spectrum[loop]) ;
			
            index ++ ;
            delta_wavelength += 1 ;    	// 1nm 증가 
        }		
    }	
	
    TristimulusX  = X * K ;
    TristimulusY  = Y * K ;
    TristimulusZ  = Z * K ;	
}
//---------------------------------------------------------------------------
반응형
반응형

table.h
0.02MB

계산상 필요한 table 은 위의 파일을 다운로드 받으세요

색좌표상의 X,Y 값을 이용한 LED Dominant 파장 계산을 위한 알고리즘 입니다.

double __fastcall Dominant_Wavelength(double Chroma_x, double Chroma_y)
{
    DPOINT TempPos[4], Dominant ;
    double dtemp = 1000, value, degree, result ;
    int start = 0, stop = 0, temp = 0 ;
    double  dominant_wavelength ;

    TempPos[0].x = TempPos[0].y = 0.33 ;
    TempPos[1].x = Chroma_x ;
    TempPos[1].y = Chroma_y ;

    try{ degree = (Chroma_y - 0.33) / (Chroma_x - 0.33) ; }  //  색좌표의 x,y 값과 백색좌표값의 기울기 계산
    catch(...) { degree = 0 ; }

    if(Chroma_x > 0.33){ start = 35 ; stop = 80 ; }
    else if(Chroma_y > 0.33) { start = 23 ; stop = 34 ; }
    else{ start = 0 ; stop = 22 ; }

    for(int i=start ; i<stop ; i++)     // 색좌표의 기울기와 가장 근사한 기울기를 가진 파장의 좌표를 찾는다.
    {
        result = (wxy[i].y - 0.33) / (wxy[i].x - 0.33) ;

        value = fabs(result-degree) ;
        if(dtemp > value)
        {
            dtemp = value ;
            temp  = i ;
            TempPos[2].x = wxy[i].x  ;
            TempPos[2].y = wxy[i].y  ;
        }
    }

    result = (wxy[temp+1].y - 0.33) / (wxy[temp+1].x - 0.33) ;
    value  = (wxy[temp-1].y - 0.33) / (wxy[temp-1].x - 0.33) ;

    result = fabs(degree - result) ;
    value  = fabs(degree - value) ;

    if(result > value)
    {
        TempPos[3].x = wxy[temp-1].x  ;
        TempPos[3].y = wxy[temp-1].y  ;
        temp -- ;
    }
    else
    {
        TempPos[3].x = wxy[temp+1].x  ;
        TempPos[3].y = wxy[temp+1].y  ;
    }

    GetIntersectPoint(TempPos[0],TempPos[1],TempPos[2],TempPos[3],&Dominant) ;    // 두직선의 교점
    dominant_wavelength = Calculate_Dominant_Wavelength(Dominant, temp) ;

    m_dfDominant_X = Dominant.x  ;
    m_dfDominant_Y = Dominant.y  ;

    return dominant_wavelength ;
}
//---------------------------------------------------------------------------

bool __fastcall GetIntersectPoint(const DPOINT& AP1, const DPOINT& AP2, const DPOINT& BP1, const DPOINT& BP2, DPOINT* IP)
{
// 두 직선의 교점을 구하는 함수 

double t, s ;
double under = (BP2.y-BP1.y)*(AP2.x-AP1.x)-(BP2.x-BP1.x)*(AP2.y-AP1.y) ;

if(under == 0)
    {
     IP->x = 0 ;
    IP->y = 0 ;
        return false ;
    }

double _t = (BP2.x-BP1.x)*(AP1.y-BP1.y) - (BP2.y-BP1.y)*(AP1.x-BP1.x) ;
double _s = (AP2.x-AP1.x)*(AP1.y-BP1.y) - (AP2.y-AP1.y)*(AP1.x-BP1.x) ;

t = _t / under ;
s = _s / under ;

if(_t==0 && _s==0) return false ;

IP->x = AP1.x + t * (double)(AP2.x-AP1.x) ;
IP->y = AP1.y + t * (double)(AP2.y-AP1.y) ;

return true ;
}
//---------------------------------------------------------------------------
double __fastcall Calculate_Dominant_Wavelength(DPOINT Dominant, int index)
{
    double Wavelength ;
    double temp1, temp2 ;

    temp1 = fabs(wxy[index].y - wxy[index+1].y) ;
    temp2 = fabs(wxy[index].y - Dominant.y) ;

    if(temp1 == 0) Wavelength = 0 ;
    else
    {
        try
        {
            temp1 = (temp2 / temp1) * 5.0 ;
            Wavelength = wxy[index].wavelength + temp1 ;
        }
        catch(...)
        {
            Wavelength = 0 ;
        }
    }

    return Wavelength ;
}
//---------------------------------------------------------------------------
반응형
반응형

table.h
0.02MB

계산상 필요한 table 은 위의 파일을 다운로드 받으세요

색좌표상의 x, y 값을 이용하여 발광빛의 색온도(Correlated Color Temperature)를 계산하는 코드 입니다.

 

double CCT(double xs, double ys)
{
    int j;
    double us,vs;
    double uj,vj,tj,di,dj,mi,mj;
    double cct ;  

    /* convert (x,y) to CIE 1960 (u,v) */
    try
    {
        us = (2*xs) / (-xs + 6*ys + 1.5);
        vs = (3*ys) / (-xs + 6*ys + 1.5);
    }
    catch(...)
    {
        us = 0 ;
        vs = 0 ;
    }

    /* search for closest isotemp lines */
    for(j=0 ; j<niso ; j++)
    {
        uj = isotempdata[j].ut ;
        vj = isotempdata[j].vt ;
         tj = isotempdata[j].tt ;
         mj = isotempdata[j].mirek ;

          try
          {
             dj = ((vs - vj) - tj * (us - uj)) / sqrt(1 + tj*tj) ; /* dj = distance from (us,vs) to this isotemp line */
          }
          catch(...)
          {
                dj = 0 ;
          }

    /* we stop when (di/dj) < 0.0, i.e. when distance changes sign, because this means we have found isotemp lines
       that "straddle" our point. */

          try
          {
                if ((j!=0) && (di/dj < 0.0))
                {
                    cct = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi));
                    break;
                 }
            }
            catch(...)
            {
                cct = 0 ;
                break ;
            }

            di = dj;
            mi = mj;
        }

        if (j == niso) cct = -1 ;

        return cct ;
}
반응형

+ Recent posts