{ Калибровка шкалы масс 1. по двум массам; 2. (!пока нет) по многим массам. } {--------------------------------------------------------------------------- The control program for mass-spectrometer MI1201-AGM (c) Copyright Aleksandrov O.E., 2001 Molecular Physics department, USTU, Ekaterinsburg, K-2, 620002, RUSSIA phone 75-47-15 E-mail: aleks@dpt.ustu.ru Программа управления масс-спектрометром МИ1201-АГМ (c) Собственность Александрова О.Е., 2001 620002, Екатеринбург, К-2, УГТУ, Кафедра молекулярной физики тел. 75-47-15 E-mail: aleks@dpt.ustu.ru ----------------------------------------------------------------------------} unit MCAD_MI1201_Thread2; interface uses Windows, Classes, SysUtils, SyncObjs, Registry, xSystem, MITypes, MassClbr, MCAD_MI1201_TChartSeries, MCAD_MI1201_Thread_Types, MCAD_MI1201_Thread0, MCAD_MI1201_Thread01; type tCalibrationData=record M1,M2:tMass; // точные значения масс C1,C2:tCounter; // соответствующие массам значения счетчиков dC:double; // поправка к значениям счетчиков K:tMass; // коэффициент перевода счетчиков в массу end; tMArrayIndex=0..1; tMArray=array[tMArrayIndex] of tMass; tRefinedSet=set of tMArrayIndex; tMArrayRecord=record M:tMArray; Refined:tRefinedSet; Disbalance:tCounter; DisbalanceValid:boolean; end; tCArray=array[tMArrayIndex] of tCounter; tNCError=(nceOK, nceCommandPending, ncePeakCentering, nceCalculation, nceSetNew, nceCommandNotAvailable); tNCErrorStrs=array[tNCError] of string; tNCFlag=(fCalibrationDoNotRemeasureOnMassRefine, fCalibrationTerminated); tNCFlags=set of tNCFlag; // Состояние процесса калибровки tRefineMassState=(csNotProcessed); tNCEvent=( evCalibrationMassRefined, // проведено уточнение текущих масс-центров пиков evCalibrationNewCalculated, // проведено вычисление новой калибровки шкалы масс evCalibrationParametersChanged, // проведено изменение параметров калибровки evCalibrationError, // ошибка при вычисление новой калибровки шкалы масс evCalibrationCommandPending, evCalibrationCommandEnd, evCalibrationPeakProcessing, evCalibrationPeakProcessing_Disbalance, evCalibrationPeakProcessing_End, evCalibrationPeakProcessing_Error ); const cNCErrors:tNCErrorStrs=( 'OK', 'Повтор команды до завершения предыдущей', 'Ошибка при поиске центра пика', 'Ошибка при вычислении новой калибровки', 'Ошибка при установке новой калибровки', 'Команда недоступна' ); type tMsThread = class(MCAD_MI1201_Thread01.tMsThread) private prFlags:tNCFlags; prCommandPendingCounter:integer; prNewMassCalibration:tMassCalibration; // prC:tCArray; // Точные значения счетчика prM:tMArrayRecord; // Текущие значения масс prM0:tMArray; // Точные значения масс prNCError:tNCError; prPeak:integer; prDataLockMutex:tHANDLE; // для блокировки данных на период исполнения function CalibrationGetNewK:tMass; function CalibrationGetNewM0:tMass; function CalibrationGetNew_dC:tMass; procedure CalibrationSetError(e:tNCError); procedure CalibrationSetM(i:tMArrayIndex; M:tMass); function CalibrationGetM(i:tMArrayIndex):tMass; procedure CalibrationSetM0(i:tMArrayIndex; M:tMass); function CalibrationGetM0(i:tMArrayIndex):tMass; function CalibrationInterlockedDecrement:integer; function CalibrationTerminatedGet:boolean; procedure CalibrationTerminatedSet(aState:boolean); protected function CalibrationCheckCommandPending:boolean; function CalibrationCheckExCommand:boolean; function CalibrationCheckExCommandPending:boolean; procedure CalibrationDoRefineMasses(Sender:tObject); procedure CalibrationDoRefineMass1(Sender:tObject); procedure CalibrationDoRefineMass2(Sender:tObject); procedure CalibrationDoCalculateNewCalibration(Sender:tObject); procedure CalibrationDoSetNewCalibration(Sender:tObject); function CalibrationExecuteCmd(p:tNotifyEvent):integer; procedure ConfigSave; override; procedure ConfigRead; override; function CalibrationPeakCenter(m:tMass):tMass; procedure CalibrationFlagsSet(AFlags:tNCFlags); function CalibrationNCErrorGet:string; procedure CalibrationNCNotify(ev:tNCEvent); public // блокирует данные procedure CalibrationLockData; // деблокирует данные procedure CalibrationUnLockData; // делает попытку блокировать данные function CalibrationTryLockData:boolean; overload; function CalibrationTryLockData(aTimeOut:cardinal):boolean; overload; function CalibrationRefineMass(N:tMArrayIndex):boolean; function CalibrationRefineMassIX(N:tMArrayIndex):boolean; function CalibrationRefineInitialMasses:boolean; function CalibrationCalculateNew:boolean; function CalibrationSetNew:boolean; function CalibrationRefineInitialMassesX:boolean; function CalibrationCalculateNewX:boolean; function CalibrationSetNewX:boolean; function CalibrationCalculateNew_SetNew:boolean; function CalibrationRefineInitialMasses_CalculateNew:boolean; function CalibrationRefineInitialMasses_CalculateNew_SetNew:boolean; function CalibrationCalculateNew_SetNewX:boolean; function CalibrationRefineInitialMasses_CalculateNewX:boolean; function CalibrationRefineInitialMasses_CalculateNew_SetNewX:boolean; function CalibrationDoRemeasure:boolean; property CalibrationError:tNCError read prNCError write CalibrationSetError; property CalibrationErrorMsg:string read CalibrationNCErrorGet; property CalibrationNew_K:tMass read CalibrationGetNewK; property CalibrationNew_M0:tMass read CalibrationGetNewM0; property CalibrationNew_dC:tMass read CalibrationGetNew_dC; property CalibrationNew_C:tCArray read prC; property CalibrationDisbalance:tCounter read prM.Disbalance; property CalibrationDisbalanceValid:boolean read prM.DisbalanceValid; property CalibrationCur_M[i:tMArrayIndex]:tMass read CalibrationGetM write CalibrationSetM; property CalibrationCur_M_Refined:tRefinedSet read prM.Refined; property CalibrationExact_M[i:tMArrayIndex]:tMass read CalibrationGetM0 write CalibrationSetM0; property CalibrationFlags:tNCFlags read prFlags write CalibrationFlagsSet; property CalibrationPeakInProcessing:integer read prPeak; property CalibrationTerminated:boolean read CalibrationTerminatedGet write CalibrationTerminatedSet; function CalibrationCanContinue:boolean; constructor Create(const Name:string); destructor Destroy; override; end; implementation constructor tMsThread.Create; begin prDataLockMutex:=CreateMutex(NIL,FALSE,NIL); Win32Check(prDataLockMutex<>0); CalibrationLockData; prNewMassCalibration.Init; CalibrationUnLockData; Inherited; end; destructor tMsThread.Destroy; begin Inherited; CalibrationLockData; CloseHandle(prDataLockMutex); end; procedure tMsThread.ConfigSave; begin Inherited; if not Assigned(Self) then Exit; CalibrationLockData; if RegistryOpenKey('MassCalibration',TRUE) then begin try Registry.WriteBinaryData('Ms', prM, SizeOF(prM)); except end; try Registry.WriteBinaryData('M0', prM0, SizeOF(prM0)); except end; try Registry.WriteBinaryData('MassCalibration', prNewMassCalibration, SizeOF(prNewMassCalibration)); prNewMassCalibration.Validate; except end; try Registry.WriteBinaryData('C', prC, SizeOF(prC)); except end; // try // Registry.WriteBinaryData('Disbalance', prDisbalance, SizeOF(prDisbalance)); // except end; try Registry.WriteBinaryData('CalibrationFlags', prFlags, SizeOF(prFlags)); except end; end; CalibrationUnLockData; Registry.CloseKey; end; procedure tMsThread.ConfigRead; begin Inherited; if not Assigned(Self) then Exit; CalibrationLockData; if RegistryOpenKey('MassCalibration',FALSE) then begin try Registry.ReadBinaryData('Ms', prM, SizeOF(prM)); except end; try Registry.ReadBinaryData('M0', prM0, SizeOF(prM0)); except end; try Registry.ReadBinaryData('MassCalibration', prNewMassCalibration, SizeOF(prNewMassCalibration)); except end; try Registry.ReadBinaryData('C', prC, SizeOF(prC)); except end; // try // Registry.ReadBinaryData('Disbalance', prDisbalance, SizeOF(prDisbalance)); // except end; try Registry.ReadBinaryData('CalibrationFlags', prFlags, SizeOF(prFlags)); prFlags:=prFlags*[Low(tNCFlag)..High(tNCFlag)]; except end; end; CalibrationUnLockData; Registry.CloseKey; end; function tMsThread.CalibrationCheckCommandPending:boolean; begin if prCommandPendingCounter>0 then begin Result:=FALSE; CalibrationSetError(nceCommandPending); end else begin Result:=TRUE; end; end; function tMsThread.CalibrationCheckExCommand:boolean; begin Result:=IsON and IsNoError; if not Result then CalibrationSetError(nceCommandNotAvailable); end; function tMsThread.CalibrationCheckExCommandPending:boolean; begin Result:=CalibrationCheckExCommand; if Result then Result:=CalibrationCheckCommandPending; end; procedure tMsThread.CalibrationSetError(e:tNCError); begin if (e=nceOK) then begin prNCError:=nceOK; CalibrationNCNotify(evCalibrationError); end else if (prNCError=nceOK) then begin prNCError:=e; CalibrationNCNotify(evCalibrationError); end; end; function tMsThread.CalibrationDoRemeasure:boolean; begin Result:=not (fCalibrationDoNotRemeasureOnMassRefine in CalibrationFlags) and IsON; end; function tMsThread.CalibrationPeakCenter(m:tMass):tMass; var oldPeakCenterFlags:tPCFlags; oldPCMeasureType:tPCMeasureType; begin Result:=-1; if PeakCenterTryLockData then begin try oldPCMeasureType:=PeakCenterMeasureType; oldPeakCenterFlags:=PeakCenterFlags; try if CalibrationDoRemeasure then PeakCenterMeasureType:=pcmtDirect else PeakCenterMeasureType:=pcmtData; PeakCenterFlags:=PeakCenterFlags-[fMoveToPeakCenterAtEnd]; PeakCenterMass0:=m; PeakCenterTerminated:=FALSE; Result:=PeakCenter; if PeakCenterError<>pceOK then Result:=-1; finally PeakCenterMeasureType:=oldPCMeasureType; PeakCenterFlags:=oldPeakCenterFlags; PeakCenterUnLockData end; except end; end; end; function tMsThread.CalibrationRefineInitialMasses:boolean; var lNewMs:tMArrayRecord; lMs:tMArray; lX,lM:tMass; lC0:tCounter; begin Result:=CalibrationCheckExCommand; if Result then begin Result:=CalibrationTryLockData; if Result then begin try prPeak:=1; CalibrationNCNotify(evCalibrationPeakProcessing); lM:=Mass; lNewMs:=prM; lMs:=lNewMs.M; lNewMs.Refined:=[]; lNewMs.DisbalanceValid:=FALSE; lX:=CalibrationPeakCenter(lMs[0]); Result:=(lX>0); if Result then begin lNewMs.M[0]:=lx; Include(lNewMs.Refined,0); prPeak:=2; CalibrationNCNotify(evCalibrationPeakProcessing); lC0:=Mass2Counter(lX); lX:=CalibrationPeakCenter(lMs[1]); Result:=(lX>0); if Result then begin lNewMs.M[1]:=lX; Include(lNewMs.Refined,1); prPeak:=3; CalibrationNCNotify(evCalibrationPeakProcessing_Disbalance); lX:=CalibrationPeakCenter(lNewMs.M[0]); Result:=(lX>0); if Result then begin lNewMs.Disbalance:=lc0-Mass2Counter(lX); lNewMs.DisbalanceValid:=TRUE; end else begin CalibrationNCNotify(evCalibrationPeakProcessing_Error); end; end else begin CalibrationNCNotify(evCalibrationPeakProcessing_Error); end; end else begin CalibrationNCNotify(evCalibrationPeakProcessing_Error); end; prM:=lNewMs; CalibrationNCNotify(evCalibrationMassRefined); Mass:=lM; prPeak:=0; except Result:=FALSE; CalibrationSetError(ncePeakCentering); end; CalibrationUnLockData; end; end; CalibrationNCNotify(evCalibrationPeakProcessing_End); end; function tMsThread.CalibrationCalculateNew:boolean; var lM:tMArray; // Текущие значения масс lM0:tMArray; // Точные значения масс i:tMArrayIndex; begin Result:=CalibrationTryLockData; if Result then begin try prMsSp.MassCalibrationGetEx(prNewMassCalibration); for i:=Low(i) to High(i) do begin lM[i]:=UnShiftMass(prM.M[i]); lM0[i]:=UnShiftMass(prM0[i]); end; Result:=prNewMassCalibration.CalculateAndSetM(lM[0],lM0[0],lM[1],lM0[1]); prC[0]:=prNewMassCalibration.Mass2Counter(lM0[0]); prC[1]:=prNewMassCalibration.Mass2Counter(lM0[1]); CalibrationNCNotify(evCalibrationNewCalculated); if not Result then begin CalibrationSetError(nceCalculation); end; except Result:=FALSE; CalibrationSetError(nceCalculation); end; CalibrationUnLockData; end; end; function tMsThread.CalibrationSetNew:boolean; var NewMassCalibration:tMassCalibration; begin Result:=CalibrationTryLockData; if Result then begin try NewMassCalibration:=prNewMassCalibration; except end; CalibrationUnLockData; end else begin Exit; end; if WaitReady then begin try Result:=MassCalibrationSet(NewMassCalibration); except Result:=FALSE; end; SetReady; end else begin Result:=FALSE; end; if not Result then CalibrationSetError(nceSetNew); end; function tMsThread.CalibrationGetNewK:tMass; begin Result:=prNewMassCalibration.Get_K; end; function tMsThread.CalibrationGetNewM0:tMass; begin Result:=prNewMassCalibration.Get_M0; end; function tMsThread.CalibrationGetNew_dC:tMass; begin Result:=prNewMassCalibration.Get_dC; end; function tMsThread.CalibrationInterlockedDecrement; begin Result:=InterlockedDecrement(prCommandPendingCounter); if Result=0 then CalibrationNCNotify(evCalibrationCommandEnd); end; procedure tMsThread.CalibrationDoRefineMasses; begin CalibrationSetError(nceOK); CalibrationRefineInitialMasses; CalibrationInterlockedDecrement; end; procedure tMsThread.CalibrationDoCalculateNewCalibration; begin CalibrationSetError(nceOK); CalibrationCalculateNew; CalibrationInterlockedDecrement; end; procedure tMsThread.CalibrationDoSetNewCalibration; begin CalibrationSetError(nceOK); CalibrationSetNew; CalibrationInterlockedDecrement; end; function tMsThread.CalibrationCalculateNew_SetNew:boolean; begin Result:=CalibrationCalculateNew and CalibrationSetNew; end; function tMsThread.CalibrationRefineInitialMasses_CalculateNew:boolean; begin Result:=CalibrationRefineInitialMasses and CalibrationCalculateNew; end; function tMsThread.CalibrationRefineInitialMasses_CalculateNew_SetNew:boolean; begin Result:=CalibrationRefineInitialMasses and CalibrationCalculateNew and CalibrationSetNew; end; function tMsThread.CalibrationExecuteCmd(p:tNotifyEvent):integer; begin InterlockedIncrement(prCommandPendingCounter); Result:=ExtendedCommand(p); if Result=-1 then InterlockedDecrement(prCommandPendingCounter) else CalibrationNCNotify(evCalibrationCommandPending); end; function tMsThread.CalibrationRefineInitialMassesX:boolean; begin Result:=CalibrationCheckExCommandPending; if not Result then Exit; Result:=CalibrationExecuteCmd(CalibrationDoRefineMasses)<>-1; end; function tMsThread.CalibrationCalculateNewX:boolean; begin Result:=CalibrationCheckExCommand; if Result Then begin Result:=CalibrationCheckCommandPending; if Result then begin Result:=ExecuteCmd(CalibrationDoCalculateNewCalibration)<>-1; end; end else begin Result:=CalibrationCalculateNew; end; end; function tMsThread.CalibrationSetNewX:boolean; begin Result:=CalibrationCheckExCommand; if Result Then begin Result:=CalibrationCheckCommandPending; if Result then begin Result:=ExecuteCmd(CalibrationDoSetNewCalibration)<>-1; end; end else begin Result:=CalibrationSetNew; end; end; function tMsThread.CalibrationCalculateNew_SetNewX:boolean; begin Result:=CalibrationCheckExCommand; if Result Then begin Result:=CalibrationCheckCommandPending; if Result then begin Result:=ExecuteCmd(CalibrationDoCalculateNewCalibration)<>-1; if Result then Result:=(ExecuteCmd(CalibrationDoSetNewCalibration)<>-1); end; end else begin Result:=CalibrationCalculateNew_SetNew; end; end; function tMsThread.CalibrationRefineInitialMasses_CalculateNewX:boolean; begin Result:=CalibrationCheckExCommandPending; if not Result then Exit; Result:=ExecuteCmd(CalibrationDoRefineMasses)<>-1; if Result then Result:=ExecuteCmd(CalibrationDoCalculateNewCalibration)<>-1; end; function tMsThread.CalibrationRefineInitialMasses_CalculateNew_SetNewX:boolean; begin Result:=CalibrationCheckExCommandPending; if not Result then Exit; Result:=ExecuteCmd(CalibrationDoRefineMasses)<>-1; if Result then Result:=ExecuteCmd(CalibrationDoCalculateNewCalibration)<>-1; if Result then Result:=ExecuteCmd(CalibrationDoSetNewCalibration)<>-1; end; procedure tMsThread.CalibrationSetM(i:tMArrayIndex; M:tMass); begin if CalibrationTryLockData then begin try prM.M[i]:=m; prM.Refined:=[]; prM.DisbalanceValid:=FALSE; CalibrationUnLockData; except end; end; end; function tMsThread.CalibrationGetM(i:tMArrayIndex):tMass; begin Result:=prM.M[i]; end; procedure tMsThread.CalibrationSetM0(i:tMArrayIndex; M:tMass); begin if CalibrationTryLockData then begin try prM0[i]:=m; CalibrationUnLockData; except end; end; end; function tMsThread.CalibrationGetM0(i:tMArrayIndex):tMass; begin Result:=prM0[i]; end; procedure tMsThread.CalibrationFlagsSet(AFlags:tNCFlags); begin if CalibrationTryLockData then begin try prFlags:=AFlags; CalibrationNCNotify(evCalibrationParametersChanged); except end; CalibrationUnLockData; end; end; function tMsThread.CalibrationNCErrorGet:string; begin Result:=cNCErrors[CalibrationError]; end; procedure tMsThread.CalibrationNCNotify(ev:tNCEvent); begin Notify(evCalibration, Byte(ev),0); end; procedure tMsThread.CalibrationDoRefineMass1; begin CalibrationSetError(nceOK); CalibrationRefineMass(0); CalibrationInterlockedDecrement; end; procedure tMsThread.CalibrationDoRefineMass2; begin CalibrationSetError(nceOK); CalibrationRefineMass(1); CalibrationInterlockedDecrement; end; function tMsThread.CalibrationRefineMassIX(N:tMArrayIndex):boolean; begin Result:=CalibrationCheckExCommand; if Result Then begin Result:=CalibrationCheckCommandPending; if Result then begin case N of 0: Result:=ExecuteCmd(CalibrationDoRefineMass1)<>-1; 1: Result:=ExecuteCmd(CalibrationDoRefineMass2)<>-1; end; end; end else begin CalibrationRefineMass(N); end; end; function tMsThread.CalibrationRefineMass(N:tMArrayIndex):boolean; var NewM:tMass; begin Result:=CalibrationTryLockData; if Result then begin CalibrationTerminated:=FALSE; prPeak:=N; try CalibrationNCNotify(evCalibrationPeakProcessing); NewM:=CalibrationPeakCenter(prM.M[N]); CalibrationNCNotify(evCalibrationPeakProcessing_End); Result:=(NewM>0); if Result then begin prM.M[N]:=NewM; Include(prM.Refined,N); CalibrationNCNotify(evCalibrationMassRefined); end; except end; CalibrationUnLockData; end; end; procedure tMsThread.CalibrationLockData; begin WaitForSingleObject(prDataLockMutex, INFINITE); end; procedure tMsThread.CalibrationUnLockData; begin Win32Check(ReleaseMutex(prDataLockMutex)); end; function tMsThread.CalibrationTryLockData:boolean; begin Result:=WaitForSingleObject(prDataLockMutex, 0)=WAIT_OBJECT_0; end; function tMsThread.CalibrationTryLockData(aTimeOut:cardinal):boolean; begin Result:=WaitForSingleObject(prDataLockMutex, aTimeOut)=WAIT_OBJECT_0; end; function tMsThread.CalibrationTerminatedGet:boolean; begin Result:=(fCalibrationTerminated in CalibrationFlags) or PeakCenterTerminated or Terminated; end; function tMsThread.CalibrationCanContinue:boolean; begin Result:=not CalibrationTerminated and IsNoError; end; procedure tMsThread.CalibrationTerminatedSet(aState:boolean); begin if aState then begin Include(prFlags, fCalibrationTerminated); PeakCenterTerminated:=TRUE; end else begin Exclude(prFlags, fCalibrationTerminated); end; end; END.