unit MCAD_MI1201_Thread01; { Определение центра пика } {--------------------------------------------------------------------------- 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 ----------------------------------------------------------------------------} interface uses Windows, Classes, SysUtils, SyncObjs, Registry, xSystem, MITypes, MassClbr, MCAD_MI1201_TChartSeries, MCAD_MI1201_Thread_Types, MCAD_MI1201_Thread0, MCAD_MI1201_Thread1, MCAD_MI1201_ThreadPeakCentering; const cRegSubKey='MassCalibration'; type tNoizeData=record M:tMass; // значение массы N:cardinal; // число измерений ABS_dM, // отклонение ABS_deltaM:=Сумма(|M[i]-M[i-1]|) Sqr_dM:tMass; // отклонение Sqr_deltaM:=Сумма(Sqr(M[i]-M[i-1])) end; tPCError=(pceOK, pceCommandNotAvailable, pceCommandPending, pceMassSetError, pceSignalReadError, pcePeakCentering, pceNoiseError {, nceCalculation, nceSetNew} ); tPCErrorStrs=array[tPCError] of string; tPCFlag=(fDoNotRemeasure); tPCFlags=set of tPCFlag; tPCEvent=( evMassRefined, // проведено уточнение текущих масс-центров пиков evNewCalculated, // проведено вычисление новой калибровки шкалы масс evParametersChanged, // проведено изменение параметров калибровки evError, // ошибка при вычисление новой калибровки шкалы масс evPeakProcessing, evPeakProcessing_Disbalance, evPeakProcessing_End, evPeakProcessing_Error ); tPeakCenterData=record Error:tPCError; // ошибка при поиске M0:tMass; // начальное значение массы M:tMass; // значение массы для центра пика MaxSignal:double; // значение сигнала в максимуме Noise:tNoizeData; // данные по шуму end; const cPCErrors:tPCErrorStrs=( 'ОК', 'Команда недоступна', 'Повтор команды до завершения предыдущей', 'Ошибка при установке массы', 'Ошибка при чтении сигнала', 'Ошибка при поиске центра пика', 'Ошибка при измерении шума' {, 'Ошибка при вычислении новой калибровки', 'Ошибка при установке новой калибровки', } ); type tMsThread = class(MCAD_MI1201_ThreadPeakCentering.tMsThread) private prFlags:tPCFlags; prError:tPCError; prCommandPendingCounter:integer; prNoiseData:tNoizeData; prNoiseCoeff:double; prPeakCenterData:tPeakCenterData; // данные по поиску центра пика procedure SetError(e:tPCError); protected function CheckCommandPending:boolean; function CheckExCommand:boolean; function CheckExCommandPending:boolean; function ExecuteCmd(p:tNotifyEvent):integer; function PCErrorGet:string; procedure PCNotify(ev:tPCEvent); procedure ConfigSave; override; procedure ConfigRead; override; procedure FlagsSet(AFlags:tPCFlags); procedure DoPeakCenter(Sender:TObject); function PeakCenterGetSignal:tChannelSignal; public function PeakCenter:tMass; function PeakCenterX(m:tMass):boolean; function Noise(RepeatCount:cardinal):tNoizeData; function DoRemeasure:boolean; property PeakCenterError:tPCError read prError write SetError; property PeakCenterErrorMsg:string read PCErrorGet; property PeakCenterFlags:tPCFlags read prFlags write FlagsSet; property PeakCenterMass0:tMass read prPeakCenterData.M0; end; implementation procedure tMsThread.ConfigSave; begin Inherited; if not Assigned(Self) then Exit; if RegistryOpenKey(cRegSubKey,TRUE) then begin try Registry.WriteFloat('NoiseCoefficient', prNoiseCoeff); except end; try // Registry.WriteBinaryData('M0', prM0, SizeOF(prM)); except end; try // Registry.WriteBinaryData('MassCalibration', prNewMassCalibration, SizeOF(prNewMassCalibration)); 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; Registry.CloseKey; end; procedure tMsThread.ConfigRead; begin Inherited; if not Assigned(Self) then Exit; if RegistryOpenKey(cRegSubKey,FALSE) then begin try // Registry.ReadBinaryData('M', prM, SizeOF(prM)); except end; try // Registry.ReadBinaryData('M0', prM0, SizeOF(prM)); 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; Registry.CloseKey; end; function tMsThread.CheckCommandPending:boolean; begin if prCommandPendingCounter>0 then begin Result:=FALSE; SetError(pceCommandPending); end else begin Result:=TRUE; end; end; function tMsThread.CheckExCommand:boolean; begin Result:=IsON and IsNoError; if not Result then SetError(pceCommandNotAvailable); end; function tMsThread.CheckExCommandPending:boolean; begin Result:=CheckExCommand; if Result then Result:=CheckCommandPending; end; procedure tMsThread.SetError(e:tPCError); begin if (e=pceOK) then begin prError:=pceOK; PCNotify(evError); end else if (prError=pceOK) then begin prError:=e; PCNotify(evError); end; end; function tMsThread.DoRemeasure:boolean; begin Result:=not (fDoNotRemeasure in PeakCenterFlags) and MeasureAvailable; end; function tMsThread.PeakCenterGetSignal:tChannelSignal; begin if DoRemeasure then begin Result:=SignalGetDirect(Mass,MainChannel); if IsError then begin SetError(pceSignalReadError); end; end else begin end; end; function tMsThread.Noise(RepeatCount:cardinal):tNoizeData; var i:cardinal; x,x1,x2,dx:extended; begin Result.M:=Mass; Result.N:=RepeatCount; Result.ABS_dM:=0; Result.Sqr_dM:=0; if RepeatCount=0 then Exit; try x2:=PeakCenterGetSignal.Signal; x:=x2; if DoRemeasure then begin for i:=1 to RepeatCount do begin x1:=x2; x2:=PeakCenterGetSignal.Signal; x:=x+x2; dx:=x2-x1; Result.ABS_dM:=Result.ABS_dM+Abs(dx); Result.Sqr_dM:=Result.Sqr_dM+Sqr(dx); end; x:=x/Succ(RepeatCount); prNoiseCoeff:=(Result.ABS_dM/RepeatCount)/Sqrt(Abs(x)); end else begin if prNoiseCoeff<=0 then prNoiseCoeff:=1; Result.ABS_dM:=prNoiseCoeff*Sqrt(Abs(x2)); Result.Sqr_dM:=Sqr(Result.ABS_dM); end; except SetError(pceNoiseError); end; end; function tMsThread.PeakCenter:tMass; begin SetError(pceOK); Result:=-1; try prPeakCenterData.Noise:=Noise(prNoiseData.N); Result:=0; except end; end; function tMsThread.ExecuteCmd(p:tNotifyEvent):integer; begin Result:=ExtendedCommand(p); if Result<>-1 then Inc(prCommandPendingCounter); end; function tMsThread.PeakCenterX(m:tMass):boolean; begin Result:=CheckExCommand; if Result Then begin Result:=CheckCommandPending; if Result then begin prPeakCenterData.M0:=m; Result:=ExecuteCmd(DoPeakCenter)<>-1; end; end else begin Result:=PeakCenter<>-1; end; end; procedure tMsThread.DoPeakCenter; begin Dec(prCommandPendingCounter); SetError(pceOK); Mass:=prPeakCenterData.M0; prPeakCenterData.M:=PeakCenter; end; procedure tMsThread.FlagsSet(AFlags:tPCFlags); begin prFlags:=AFlags; PCNotify(evParametersChanged); end; function tMsThread.PCErrorGet:string; begin Result:=cPCErrors[prError]; end; procedure tMsThread.PCNotify(ev:tPCEvent); begin NotifyEx(evPeakCenter, Byte(ev),0); end; END.