Various methods of data analysis will be presented in this post:
- velocity,
- low-pass filter (a special type of averaging with lower latency) of the velocity,
- RMS (root mean square) value of the velocity,
- integral (simulation of a heavy ball on a flat surface) of the velocity,
- daily view of the velocity.
The spectral analysis will be explained in the next post.
Types of analysis
Velocity
v = u / s * 1000.
Low-pass filter of the velocity
A_1 := exp (-SQR_2 * PI / 20); B_1 := 2 * A_1 * cos (SQR_2 * PI / 20); C_2 := B_1; C_3 := -A_1 * A_1; C_1 := 1 - C_2 - C_3; M_Data_LP_Y_A[M_Data_A_Index] := (C_1 * M_Data_Y_A [M_Data_A_Index]) + (C_2 * M_Data_LP_Y_A [M_Data_A_Index - 1]) + (C_3 * M_Data_LP_Y_A [M_Data_A_Index - 2]);
RMS value of the velocity
The RMS value is the root mean square value of the velocity, which is equivalent to the effective velocity. The effective value of an alternating current for example is the value of a direct current, which would produce the same amount of energy than the alternating current.
The RMS value is always greater or equal to zero.
Integral of the velocity
Integral [Index] := Integral [Index - 1] + Data [Index] - (LP_Integral [Index - 1] / 8000);Finally the low pass value of the integral is displayed, with an low pass span of 800. Again the value of 800 was determined empirically and can be changed according to one’s need.
Daily view of the velocity
The daily view of the velocity displays the values of the last 23 hours within hourly diagrams. In order to simplify the grahics, only the maximum and the minimum within a timeframe of 2 seconds are displayed.
This way, it is easy to recognise large velocity parts within the last hours.
Day Data Project
The files main_unit.pas, main_unit.frm and project_defines.inc contain the source code for measuring and analysing the data. Again project_defines.inc offer some project options.
The file go.sh will compile and run the program.
The software for the day data project can be downloaded here and be copied to any directory. The choosen path of the used directory needs to be adjusted in go.sh.
main_unit.pas
{ ####################################################################################### } { ## ## } { ## Main_Unit ## } { ## ## } { ## Main form ## } { ## ## } { ## Copyright (C) 2018-2020 : Dr. Jürgen Abel ## } { ## Email : juergen@juergen-abel.info ## } { ## Internet : www.seismometer.info ## } { ## ## } { ## This program is free software: you can redistribute it and/or modify ## } { ## it under the terms of the GNU Lesser General Public License as published by ## } { ## the Free Software Foundation, either version 3 of the License, or ## } { ## (at your option) any later version with the following modification: ## } { ## ## } { ## As a special exception, the copyright holders of this library give you ## } { ## permission to link this library with independent modules to produce an ## } { ## executable, regardless of the license terms of these independent modules, and ## } { ## to copy and distribute the resulting executable under terms of your choice, ## } { ## provided that you also meet, for each linked independent module, the terms ## } { ## and conditions of the license of that module. An independent module is a ## } { ## module which is not derived from or based on this library. If you modify ## } { ## this library, you may extend this exception to your version of the library, ## } { ## but you are not obligated to do so. If you do not wish to do so, delete this ## } { ## exception statement from your version. ## } { ## ## } { ## This program is distributed in the hope that it will be useful, ## } { ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## } { ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## } { ## GNU General Public License for more details. ## } { ## ## } { ## You should have received a copy of the GNU Lesser General Public License ## } { ## COPYING.LGPL.txt along with this program. ## } { ## If not, see https://www.gnu.org/licenses. ## } { ## ## } { ####################################################################################### } Unit Main_Unit; {$mode objfpc}{$H+} {$INCLUDE project_defines.inc} Interface Uses CThreads, Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, ComCtrls, TAGraph, TASeries, ADS1262_Unit, TACustomSeries, TAIntervalSources, TATools, Types, TACustomSource, Process, LCLType, LCLIntf; Const ADS1262_MODE2_GAIN_01_LIMIT = 2.5; ADS1262_MODE2_GAIN_02_LIMIT = ADS1262_MODE2_GAIN_01_LIMIT / 2; ADS1262_MODE2_GAIN_04_LIMIT = ADS1262_MODE2_GAIN_01_LIMIT / 4; ADS1262_MODE2_GAIN_08_LIMIT = ADS1262_MODE2_GAIN_01_LIMIT / 8; ADS1262_MODE2_GAIN_16_LIMIT = ADS1262_MODE2_GAIN_01_LIMIT / 16; ADS1262_MODE2_GAIN_32_LIMIT = ADS1262_MODE2_GAIN_01_LIMIT / 32; ADS1262_SAMPLE_RATE = 400; ADS1262_INTERRUPT_TIMEOUT_MSEC = 1000; {$IFDEF USE_INTERRUPT} {$ELSE} DATA_INTERVAL_MS = 2; {$ENDIF} LP_SPAN_INIT = 20; LP_SLOW_SPAN = 4000; LP_SLOW_SETTLE_FACTOR = 4; LP_INTEGRAL_SPAN = 800; LP_INTEGRAL_CORRECTION_DIVIDER = 8000; DATA_ARRAY_SIZE = 1024 * 1024; DATA_CHART_EXTEND_Y = 0.02; DATA_CHART_EXTEND_Y_MAX = 2.5; DATA_CHART_LABEL_SIZE = 120; DATA_CHART_UNIT_FORMAT = '%0:.9g mm/s'; TIME_UNIT_FORMAT = '%0:.9g mm/s'; VALUES_PER_HOUR = 60 * 60; RMS_COLOR = $2222AA; RMS_BAR_WIDTH_PERCENT = 100; DATA_COLOR = $FF4444; DATA_PIN_WIDTH = 3; POSITION_COLOR = $66EE66; POSITION_WIDTH = 11; CURRENT_IMAGE_FILE_NAME = 'images/current_image.jpg'; DAILY_IMAGE_FILE_NAME = 'images/daily_image.jpg'; HOUR_CHART_N = 24; HOUR_CHART_FONT_SIZE = 6; STATION_NAME = 'SEISMOMETER_NORF_GERMANY'; CURRENT_TIME_FORMAT_00_S = 'Live Data - Station Name: ' + STATION_NAME + ' - Date: '; CURRENT_TIME_FORMAT_01_S = ' - Time: '; SQR_2 = sqrt (2); BIT_N_RANGE = 100; VOLTAGE_LIMIT = ADS1262_MODE2_GAIN_32_LIMIT; SM24_VELOCITY_FACTOR = 20.9; INTERNET_SERVER_USERNAME_TXT = 'xxxxx'; INTERNET_SERVER_PASSWORD_TXT = 'xxxxx'; INTERNET_SERVER_URL_TXT = 'www.xxxxx.info'; TRANSFER_FILE_TXT = 'ncftpput -u ' + INTERNET_SERVER_USERNAME_TXT + ' -p ' + INTERNET_SERVER_PASSWORD_TXT + ' -E ' + INTERNET_SERVER_URL_TXT + ' / '; DELAY_SHOW_TIME_MSEC = 2000; HALT_TIME_MSEC = 60000; FORM_LEFT = 10; FORM_TOP = 10; FORM_WIDTH = 1920; FORM_HEIGHT = 1038; CLOSE_WAIT_TIME_MSEC = 1000; RANDOM_N = 100; RANDOM_MAX = 4 * 1024 * 1024; Type T_Data_X_A = Array [0 .. DATA_ARRAY_SIZE - 1] Of TDateTime; T_Data_Y_A = Array [0 .. DATA_ARRAY_SIZE - 1] Of Int_32; T_Hour_Chart_A = Array [0 .. HOUR_CHART_N - 1] Of TChart; T_Hour_RMS_BS_A = Array [0 .. HOUR_CHART_N - 1] Of TBarSeries; T_Hour_Data_LS_A = Array [0 .. HOUR_CHART_N - 1] Of TLineSeries; T_Hour_Position_CL_A = Array [0 .. HOUR_CHART_N - 1] Of TConstantLine; T_Chart_Kind = (CURRENT_CHART_CK, DAILY_CHART_CK); { ####################################################################################### } { ## T_Timer_Thread ## } { ####################################################################################### } T_Timer_Thread = Class(TThread) Private M_ADS1262 : T_ADS1262; M_Data_X_A : T_Data_X_A; M_Data_Y_A : T_Data_Y_A; M_Data_LP_Y_A : T_Data_Y_A; M_Data_Integral_Y_A : T_Data_Y_A; M_Data_LP_Integral_Y_A : T_Data_Y_A; M_Data_A_Index : Integer; M_Count : Int_64; M_LP_Span : Integer; Public Property Data_X_A : T_Data_X_A Read M_Data_X_A; Property Data_Y_A : T_Data_Y_A Read M_Data_Y_A; Property Data_LP_Y_A : T_Data_Y_A Read M_Data_LP_Y_A; Property Data_Integral_Y_A : T_Data_Y_A Read M_Data_Integral_Y_A; Property Data_LP_Integral_Y_A : T_Data_Y_A Read M_Data_LP_Integral_Y_A; Property Data_A_Index : Integer Read M_Data_A_Index; Property Count : Int_64 Read M_Count; Property ADS1262 : T_ADS1262 Read M_ADS1262; Property LP_Span : Integer Read M_LP_Span Write M_LP_Span; Constructor Create (F_Suspended : Boolean); Destructor Destroy; Override; Procedure Execute; Override; End; { T_Timer_Thread } { ####################################################################################### } { ## TMain_F ## } { ####################################################################################### } { TMain_F } TMain_F = Class(TForm) Chart_00_11_P : TPanel; Chart_12_23_P : TPanel; Chart_TS : TChartToolset; Chart_TS_ZoomDragTool : TZoomDragTool; Chart_TS_DataPointHintTool : TDataPointHintTool; Chart_TS_PanDragTool : TPanDragTool; Chart_TS_ZoomMouseWheelTool : TZoomMouseWheelTool; Close_B : TButton; Current_Chart_C : TChart; Current_Integral_LP_LS : TLineSeries; Current_Integral_LS : TLineSeries; Current_CL : TConstantLine; Current_EMA_LS : TLineSeries; Current_LP_LS : TLineSeries; Current_LS : TLineSeries; Current_RMS_LS : TLineSeries; Daily_Chart_P : TPanel; Hour_00_11_P : TPanel; Hour_0_C : TChart; Hour_0_Data_LS : TLineSeries; Hour_0_Position_CL : TConstantLine; Hour_0_RMS_BS : TBarSeries; Hour_10_C : TChart; Hour_10_Data_LS : TLineSeries; Hour_10_Position_CL : TConstantLine; Hour_10_RMS_BS : TBarSeries; Hour_11_C : TChart; Hour_11_Data_LS : TLineSeries; Hour_11_Position_CL : TConstantLine; Hour_11_RMS_BS : TBarSeries; Hour_12_23_P : TPanel; Hour_12_C : TChart; Hour_12_Data_LS : TLineSeries; Hour_12_Position_CL : TConstantLine; Hour_12_RMS_BS : TBarSeries; Hour_13_C : TChart; Hour_13_Data_LS : TLineSeries; Hour_13_Position_CL : TConstantLine; Hour_13_RMS_BS : TBarSeries; Hour_14_C : TChart; Hour_14_Data_LS : TLineSeries; Hour_14_Position_CL : TConstantLine; Hour_14_RMS_BS : TBarSeries; Hour_15_C : TChart; Hour_15_Data_LS : TLineSeries; Hour_15_Position_CL : TConstantLine; Hour_15_RMS_BS : TBarSeries; Hour_16_C : TChart; Hour_16_Data_LS : TLineSeries; Hour_16_Position_CL : TConstantLine; Hour_16_RMS_BS : TBarSeries; Hour_17_C : TChart; Hour_17_Data_LS : TLineSeries; Hour_17_Position_CL : TConstantLine; Hour_17_RMS_BS : TBarSeries; Hour_18_C : TChart; Hour_18_Data_LS : TLineSeries; Hour_18_Position_CL : TConstantLine; Hour_18_RMS_BS : TBarSeries; Hour_19_C : TChart; Hour_19_Data_LS : TLineSeries; Hour_19_Position_CL : TConstantLine; Hour_19_RMS_BS : TBarSeries; Hour_1_C : TChart; Hour_1_Data_LS : TLineSeries; Hour_1_Position_CL : TConstantLine; Hour_1_RMS_BS : TBarSeries; Hour_20_C : TChart; Hour_20_Data_LS : TLineSeries; Hour_20_Position_CL : TConstantLine; Hour_20_RMS_BS : TBarSeries; Hour_21_C : TChart; Hour_21_Data_LS : TLineSeries; Hour_21_Position_CL : TConstantLine; Hour_21_RMS_BS : TBarSeries; Hour_22_C : TChart; Hour_22_Data_LS : TLineSeries; Hour_22_Position_CL : TConstantLine; Hour_22_RMS_BS : TBarSeries; Hour_23_C : TChart; Hour_23_Data_LS : TLineSeries; Hour_23_Position_CL : TConstantLine; Hour_23_RMS_BS : TBarSeries; Hour_2_C : TChart; Hour_2_Data_LS : TLineSeries; Hour_2_Position_CL : TConstantLine; Hour_2_RMS_BS : TBarSeries; Hour_3_C : TChart; Hour_3_Data_LS : TLineSeries; Hour_3_Position_CL : TConstantLine; Hour_3_RMS_BS : TBarSeries; Hour_4_C : TChart; Hour_4_Data_LS : TLineSeries; Hour_4_Position_CL : TConstantLine; Hour_4_RMS_BS : TBarSeries; Hour_5_C : TChart; Hour_5_Data_LS : TLineSeries; Hour_5_Position_CL : TConstantLine; Hour_5_RMS_BS : TBarSeries; Hour_6_C : TChart; Hour_6_Data_LS : TLineSeries; Hour_6_Position_CL : TConstantLine; Hour_6_RMS_BS : TBarSeries; Hour_7_C : TChart; Hour_7_Data_LS : TLineSeries; Hour_7_Position_CL : TConstantLine; Hour_7_RMS_BS : TBarSeries; Hour_8_C : TChart; Hour_8_Data_LS : TLineSeries; Hour_8_Position_CL : TConstantLine; Hour_8_RMS_BS : TBarSeries; Hour_9_C : TChart; Hour_9_Data_LS : TLineSeries; Hour_9_Position_CL : TConstantLine; Hour_9_RMS_BS : TBarSeries; Input_X_Axis_Extend_E : TEdit; Input_LP_Span_E : TEdit; Input_X_Axis_Extend_L : TLabel; Input_LP_Span_L : TLabel; Label_0 : TLabel; Label_1 : TLabel; Label_10 : TLabel; Label_11 : TLabel; Label_12 : TLabel; Label_13 : TLabel; Label_14 : TLabel; Label_15 : TLabel; Label_16 : TLabel; Label_17 : TLabel; Label_18 : TLabel; Label_19 : TLabel; Label_2 : TLabel; Label_20 : TLabel; Label_21 : TLabel; Label_22 : TLabel; Label_23 : TLabel; Label_3 : TLabel; Label_4 : TLabel; Label_5 : TLabel; Label_6 : TLabel; Label_7 : TLabel; Label_8 : TLabel; Label_9 : TLabel; Maint_00_11_P : TPanel; Maint_12_23_P : TPanel; Main_PC : TPageControl; Margin_00_11_P : TPanel; Margin_12_23_P : TPanel; Current_Chart_P : TPanel; Save_B : TButton; Input_OFCAL_Value_E : TEdit; Input_OFCAL_Value_L : TLabel; Main_P : TPanel; Output_1_P : TPanel; Output_2_P : TPanel; Output_Bits_E : TEdit; Output_Bits_L : TLabel; Output_Counter_E : TEdit; Output_Counter_L : TLabel; Output_Freq_E : TEdit; Output_Freq_L : TLabel; Output_NPS_E : TEdit; Input_Sensivity_Bits_E : TEdit; Output_NPS_L : TLabel; Input_Sensivity_Bits_L : TLabel; Reset_B : TButton; Save_Image_E : TCheckBox; Save_Image_L : TLabel; Show_Integral_CB : TCheckBox; Show_LP_Integral_CB : TCheckBox; Show_Integral_L : TLabel; Show_LP_Integral_L : TLabel; Status_L : TLabel; Status_P : TPanel; Show_Current_Data_CB : TCheckBox; Show_Data_CB : TCheckBox; Show_EMA_CB : TCheckBox; Show_RMS_CB : TCheckBox; Show_EMA_L : TLabel; Show_RMS_L : TLabel; Show_LP_Data_CB : TCheckBox; Show_Current_Data_L : TLabel; Show_Data_L : TLabel; Show_LP_Data_L : TLabel; Start_Stop_B : TButton; Current_Chart_TS : TTabSheet; Daily_Chart_TS : TTabSheet; Daily_Chart_0_P : TPanel; Transfer_T : TTimer; Time_CS : TDateTimeIntervalChartSource; Output_0_P : TPanel; Chart_T : TTimer; Procedure Chart_TS_DataPointHintToolHint (ATool : TDataPointHintTool; Const APoint : TPoint; Var AHint : String); Procedure Chart_TTimer (Sender : TObject); Procedure Close_BClick (Sender : TObject); Procedure FormCreate (Sender : TObject); Procedure FormDestroy (Sender : TObject); Procedure FormShow (Sender : TObject); Procedure Input_LP_Span_EEditingDone (Sender : TObject); Procedure Input_OFCAL_Value_EEditingDone (Sender : TObject); Procedure Input_Sensivity_Bits_EEditingDone (Sender : TObject); Procedure Input_X_Axis_Extend_EEditingDone (Sender : TObject); Procedure Reset_BClick (Sender : TObject); Procedure Save_BClick (Sender : TObject); Procedure Start_Stop_BClick (Sender : TObject); Procedure Transfer_TTimer (Sender : TObject); Protected M_Data_Start_Index : Integer; M_Data_End_Index : Integer; M_Data_A_Size : Integer; M_Transfer_Process : TProcess; M_Timer_Thread : T_Timer_Thread; M_Data_A_Index_0 : Integer; M_Data_A_Index_1 : Integer; M_Start_Time : TDateTime; M_End_Time : TDateTime; M_Hour_Chart_A : T_Hour_Chart_A; M_Hour_RMS_BS_A : T_Hour_RMS_BS_A; M_Hour_Data_LS_A : T_Hour_Data_LS_A; M_Hour_Position_CL_A : T_Hour_Position_CL_A; M_Old_Data_Time : TDateTime; M_Old_Data_Hour : Integer; M_Old_Data_Minute : Integer; M_Old_Data_Second : Integer; M_Last_Saved_Minute : Integer; M_Transfer_Command : String; M_Count : Int_64; Procedure Debug_Output (F_Text : String); Function Calculate_Velocity (F_Data : Int_32) : Double; Procedure Save_Data (F_Filename : String; F_Panel : TPanel); Procedure Transfer_File (F_Command : String); Procedure Read_Array_Data (F_Index : Integer; Var F_X : TDateTime; Var F_Y : Int_32; Var F_LP_Y : Int_32); Procedure Output_Current_Time; Procedure Output_Current_Data (F_Measurement_N : Integer; F_Zero_Crossings_N : Integer; F_End_Time : TDateTime); Procedure Clear_Hour_Data_LS (F_Hour_Data_LS : TLineSeries); Procedure Clear_Hour_RMS_BS (F_Hour_RMS_BS : TBarSeries); Public {$IFDEF USE_CRITICAL_SECTION} M_Critical_Section : TCriticalSection; {$ENDIF} Property Count : Int_64 Read M_Count; End; { TMain_F } Var Main_F : TMain_F; Implementation {$R *.frm} Uses Math, DateUtils, LazFileUtils, TAChartUtils; {#####################################################################################} { Utilities } {#####################################################################################} { --------------------------------------------------------------------------------------- } Function Validate_Array_Index (F_Index : Integer; F_Array_Size : Integer) : Integer; { Validate index into array } { --------------------------------------------------------------------------------------- } Begin { Validate_Array_Index } If F_Index >= 0 Then Begin { then } Result := F_Index mod F_Array_Size; End { then } Else Begin { else } Result := ((F_Index mod F_Array_Size) + F_Array_Size) mod F_Array_Size; End; { else } End; { Validate_Array_Index } { ####################################################################################### } { ## T_Timer_Thread ## } { ####################################################################################### } { --------------------------------------------------------------------------------------- } Constructor T_Timer_Thread.Create (F_Suspended : Boolean); { Create timer thread } { --------------------------------------------------------------------------------------- } {$IFDEF DEBUG_ERROR} Var Register_Block : T_Register_Block; {$ENDIF} Begin { T_Timer_Thread.Create } Inherited Create (F_Suspended); FreeOnTerminate := FALSE; M_ADS1262 := T_ADS1262.Create (); M_ADS1262.Set_Continuous_Conversion (); M_ADS1262.Start_Conversion (); Sleep (ADS1262_WAIT_TIME_MS_COMMAND); {$IFDEF DEBUG_ERROR} M_ADS1262.Read_All_Registers (Register_Block); {$ENDIF} FillByte (M_Data_X_A [0], DATA_ARRAY_SIZE * SizeOf (TDateTime), $00); FillByte (M_Data_Y_A [0], DATA_ARRAY_SIZE * SizeOf (Int_32), $00); FillByte (M_Data_LP_Y_A [0], DATA_ARRAY_SIZE * SizeOf (Int_32), $00); FillByte (M_Data_Integral_Y_A [0], DATA_ARRAY_SIZE * SizeOf (Int_32), $00); FillByte (M_Data_LP_Integral_Y_A [0], DATA_ARRAY_SIZE * SizeOf (Int_32), $00); M_Data_A_Index := 0; M_Count := 0; M_LP_Span := LP_SPAN_INIT; End; { T_Timer_Thread.Create } { --------------------------------------------------------------------------------------- } Destructor T_Timer_Thread.Destroy; { Free data } { --------------------------------------------------------------------------------------- } Begin { T_Timer_Thread.Destroy } M_ADS1262.Free; Inherited Destroy; End; { T_Timer_Thread.Destroy } { --------------------------------------------------------------------------------------- } Procedure T_Timer_Thread.Execute; { Execute thread } { --------------------------------------------------------------------------------------- } Var A_1 : Double; B_1 : Double; C_1 : Double; C_2 : Double; C_3 : Double; A_1_LP_Integral : Double; B_1_LP_Integral : Double; C_1_LP_Integral : Double; C_2_LP_Integral : Double; C_3_LP_Integral : Double; Begin { T_Timer_Thread.Execute } While (Terminated = FALSE) Do Begin { While } {$IFDEF USE_INTERRUPT} M_ADS1262.DRDY_Pin.Wait_For_Interrupt (ADS1262_INTERRUPT_TIMEOUT_MSEC); {$ELSE} Sleep (DATA_INTERVAL_MS); {$ENDIF} {$IFDEF USE_CRITICAL_SECTION} EnterCriticalSection (Main_F.M_Critical_Section); Try {$ENDIF} M_Data_X_A[M_Data_A_Index] := Now; M_Data_Y_A[M_Data_A_Index] := M_ADS1262.ADC1_Data; A_1 := exp (-SQR_2 * PI / Round (M_LP_Span)); B_1 := 2 * A_1 * cos (SQR_2 * PI / Round (M_LP_Span)); C_2 := B_1; C_3 := -A_1 * A_1; C_1 := 1 - C_2 - C_3; M_Data_LP_Y_A[M_Data_A_Index] := Round ((C_1 * Round (M_Data_Y_A [M_Data_A_Index])) + (C_2 * Round (M_Data_LP_Y_A [Validate_Array_Index (M_Data_A_Index - 1, DATA_ARRAY_SIZE)])) + (C_3 * Round (M_Data_LP_Y_A [Validate_Array_Index (M_Data_A_Index - 2, DATA_ARRAY_SIZE)]))); A_1_LP_Integral := exp (-SQR_2 * PI / Round (LP_INTEGRAL_SPAN)); B_1_LP_Integral := 2 * A_1_LP_Integral * cos (SQR_2 * PI / Round (LP_INTEGRAL_SPAN)); C_2_LP_Integral := B_1_LP_Integral; C_3_LP_Integral := -A_1_LP_Integral * A_1_LP_Integral; C_1_LP_Integral := 1 - C_2_LP_Integral - C_3_LP_Integral; If M_Count > LP_SLOW_SETTLE_FACTOR * LP_SLOW_SPAN Then Begin { then } // M_Data_Integral_Y_A[M_Data_A_Index] := M_Data_Integral_Y_A [Validate_Array_Index (M_Data_A_Index - 1, DATA_ARRAY_SIZE)] + M_Data_Y_A [M_Data_A_Index] - M_Data_LP_Y_A[M_Data_A_Index] - Round (M_Data_LP_Integral_Y_A [Validate_Array_Index (M_Data_A_Index - 1, DATA_ARRAY_SIZE)] / LP_INTEGRAL_CORRECTION_DIVIDER); M_Data_Integral_Y_A[M_Data_A_Index] := M_Data_Integral_Y_A [Validate_Array_Index (M_Data_A_Index - 1, DATA_ARRAY_SIZE)] + M_Data_Y_A [M_Data_A_Index] - Round (M_Data_LP_Integral_Y_A [Validate_Array_Index (M_Data_A_Index - 1, DATA_ARRAY_SIZE)] / LP_INTEGRAL_CORRECTION_DIVIDER); M_Data_LP_Integral_Y_A[M_Data_A_Index] := Round ((C_1_LP_Integral * Round (M_Data_Integral_Y_A [M_Data_A_Index])) + (C_2_LP_Integral * Round (M_Data_LP_Integral_Y_A [Validate_Array_Index (M_Data_A_Index - 1, DATA_ARRAY_SIZE)])) + (C_3_LP_Integral * Round (M_Data_LP_Integral_Y_A [Validate_Array_Index (M_Data_A_Index - 2, DATA_ARRAY_SIZE)]))); End { then } Else Begin { else } M_Data_Integral_Y_A[M_Data_A_Index] := 0; M_Data_LP_Integral_Y_A[M_Data_A_Index] := 0; End; { else } Inc (M_Count); M_Data_A_Index := Validate_Array_Index (M_Data_A_Index + 1, DATA_ARRAY_SIZE); {$IFDEF USE_CRITICAL_SECTION} Finally LeaveCriticalSection (Main_F.M_Critical_Section); End; {$ENDIF} End; { While } End; { T_Timer_Thread.Execute } { ####################################################################################### } { ## TMain_F ## } { ####################################################################################### } {#####################################################################################} { Build form } {#####################################################################################} { --------------------------------------------------------------------------------------- } Procedure TMain_F.FormCreate (Sender : TObject); { Create main from } { --------------------------------------------------------------------------------------- } Var I : Integer; Hour_Chart : TChart; Hour_RMS_BS : TBarSeries; Hour_Data_LS : TLineSeries; Hour_Position_CL : TConstantLine; Begin { TMain_F.FormCreate } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.FormCreate'); {$ENDIF} { Create CriticalSection } {$IFDEF USE_CRITICAL_SECTION} InitializeCriticalSection (M_Critical_Section); {$ENDIF} { Initialize daily chart } M_Hour_Chart_A[0] := Hour_0_C; M_Hour_Chart_A[1] := Hour_1_C; M_Hour_Chart_A[2] := Hour_2_C; M_Hour_Chart_A[3] := Hour_3_C; M_Hour_Chart_A[4] := Hour_4_C; M_Hour_Chart_A[5] := Hour_5_C; M_Hour_Chart_A[6] := Hour_6_C; M_Hour_Chart_A[7] := Hour_7_C; M_Hour_Chart_A[8] := Hour_8_C; M_Hour_Chart_A[9] := Hour_9_C; M_Hour_Chart_A[10] := Hour_10_C; M_Hour_Chart_A[11] := Hour_11_C; M_Hour_Chart_A[12] := Hour_12_C; M_Hour_Chart_A[13] := Hour_13_C; M_Hour_Chart_A[14] := Hour_14_C; M_Hour_Chart_A[15] := Hour_15_C; M_Hour_Chart_A[16] := Hour_16_C; M_Hour_Chart_A[17] := Hour_17_C; M_Hour_Chart_A[18] := Hour_18_C; M_Hour_Chart_A[19] := Hour_19_C; M_Hour_Chart_A[20] := Hour_20_C; M_Hour_Chart_A[21] := Hour_21_C; M_Hour_Chart_A[22] := Hour_22_C; M_Hour_Chart_A[23] := Hour_23_C; M_Hour_RMS_BS_A[0] := Hour_0_RMS_BS; M_Hour_RMS_BS_A[1] := Hour_1_RMS_BS; M_Hour_RMS_BS_A[2] := Hour_2_RMS_BS; M_Hour_RMS_BS_A[3] := Hour_3_RMS_BS; M_Hour_RMS_BS_A[4] := Hour_4_RMS_BS; M_Hour_RMS_BS_A[5] := Hour_5_RMS_BS; M_Hour_RMS_BS_A[6] := Hour_6_RMS_BS; M_Hour_RMS_BS_A[7] := Hour_7_RMS_BS; M_Hour_RMS_BS_A[8] := Hour_8_RMS_BS; M_Hour_RMS_BS_A[9] := Hour_9_RMS_BS; M_Hour_RMS_BS_A[10] := Hour_10_RMS_BS; M_Hour_RMS_BS_A[11] := Hour_11_RMS_BS; M_Hour_RMS_BS_A[12] := Hour_12_RMS_BS; M_Hour_RMS_BS_A[13] := Hour_13_RMS_BS; M_Hour_RMS_BS_A[14] := Hour_14_RMS_BS; M_Hour_RMS_BS_A[15] := Hour_15_RMS_BS; M_Hour_RMS_BS_A[16] := Hour_16_RMS_BS; M_Hour_RMS_BS_A[17] := Hour_17_RMS_BS; M_Hour_RMS_BS_A[18] := Hour_18_RMS_BS; M_Hour_RMS_BS_A[19] := Hour_19_RMS_BS; M_Hour_RMS_BS_A[20] := Hour_20_RMS_BS; M_Hour_RMS_BS_A[21] := Hour_21_RMS_BS; M_Hour_RMS_BS_A[22] := Hour_22_RMS_BS; M_Hour_RMS_BS_A[23] := Hour_23_RMS_BS; M_Hour_Data_LS_A[0] := Hour_0_Data_LS; M_Hour_Data_LS_A[1] := Hour_1_Data_LS; M_Hour_Data_LS_A[2] := Hour_2_Data_LS; M_Hour_Data_LS_A[3] := Hour_3_Data_LS; M_Hour_Data_LS_A[4] := Hour_4_Data_LS; M_Hour_Data_LS_A[5] := Hour_5_Data_LS; M_Hour_Data_LS_A[6] := Hour_6_Data_LS; M_Hour_Data_LS_A[7] := Hour_7_Data_LS; M_Hour_Data_LS_A[8] := Hour_8_Data_LS; M_Hour_Data_LS_A[9] := Hour_9_Data_LS; M_Hour_Data_LS_A[10] := Hour_10_Data_LS; M_Hour_Data_LS_A[11] := Hour_11_Data_LS; M_Hour_Data_LS_A[12] := Hour_12_Data_LS; M_Hour_Data_LS_A[13] := Hour_13_Data_LS; M_Hour_Data_LS_A[14] := Hour_14_Data_LS; M_Hour_Data_LS_A[15] := Hour_15_Data_LS; M_Hour_Data_LS_A[16] := Hour_16_Data_LS; M_Hour_Data_LS_A[17] := Hour_17_Data_LS; M_Hour_Data_LS_A[18] := Hour_18_Data_LS; M_Hour_Data_LS_A[19] := Hour_19_Data_LS; M_Hour_Data_LS_A[20] := Hour_20_Data_LS; M_Hour_Data_LS_A[21] := Hour_21_Data_LS; M_Hour_Data_LS_A[22] := Hour_22_Data_LS; M_Hour_Data_LS_A[23] := Hour_23_Data_LS; M_Hour_Position_CL_A[0] := Hour_0_Position_CL; M_Hour_Position_CL_A[1] := Hour_1_Position_CL; M_Hour_Position_CL_A[2] := Hour_2_Position_CL; M_Hour_Position_CL_A[3] := Hour_3_Position_CL; M_Hour_Position_CL_A[4] := Hour_4_Position_CL; M_Hour_Position_CL_A[5] := Hour_5_Position_CL; M_Hour_Position_CL_A[6] := Hour_6_Position_CL; M_Hour_Position_CL_A[7] := Hour_7_Position_CL; M_Hour_Position_CL_A[8] := Hour_8_Position_CL; M_Hour_Position_CL_A[9] := Hour_9_Position_CL; M_Hour_Position_CL_A[10] := Hour_10_Position_CL; M_Hour_Position_CL_A[11] := Hour_11_Position_CL; M_Hour_Position_CL_A[12] := Hour_12_Position_CL; M_Hour_Position_CL_A[13] := Hour_13_Position_CL; M_Hour_Position_CL_A[14] := Hour_14_Position_CL; M_Hour_Position_CL_A[15] := Hour_15_Position_CL; M_Hour_Position_CL_A[16] := Hour_16_Position_CL; M_Hour_Position_CL_A[17] := Hour_17_Position_CL; M_Hour_Position_CL_A[18] := Hour_18_Position_CL; M_Hour_Position_CL_A[19] := Hour_19_Position_CL; M_Hour_Position_CL_A[20] := Hour_20_Position_CL; M_Hour_Position_CL_A[21] := Hour_21_Position_CL; M_Hour_Position_CL_A[22] := Hour_22_Position_CL; M_Hour_Position_CL_A[23] := Hour_23_Position_CL; For I := 0 To HOUR_CHART_N - 1 Do Begin { For } Hour_Chart := M_Hour_Chart_A [I]; Hour_RMS_BS := M_Hour_RMS_BS_A [I]; Hour_Data_LS := M_Hour_Data_LS_A [I]; Hour_Position_CL := M_Hour_Position_CL_A [I]; With Hour_Chart Do Begin { With } Extent.XMax := 0; Extent.XMin := 60; Extent.UseXMax := TRUE; Extent.UseXMin := TRUE; ExtentSizeLimit.XMax := 0; ExtentSizeLimit.XMin := 60; ExtentSizeLimit.UseXMax := TRUE; ExtentSizeLimit.UseXMin := TRUE; Extent.YMax := DATA_CHART_EXTEND_Y; Extent.YMin := -DATA_CHART_EXTEND_Y; Extent.UseYMax := TRUE; Extent.UseYMin := TRUE; ExtentSizeLimit.YMax := DATA_CHART_EXTEND_Y; ExtentSizeLimit.YMin := -DATA_CHART_EXTEND_Y; ExtentSizeLimit.UseYMax := TRUE; ExtentSizeLimit.UseYMin := TRUE; LeftAxis.Marks.LabelFont.Size := HOUR_CHART_FONT_SIZE; BottomAxis.Marks.LabelFont.Size := HOUR_CHART_FONT_SIZE; End; { With } Clear_Hour_RMS_BS (Hour_RMS_BS); Clear_Hour_Data_LS (Hour_Data_LS); With Hour_Position_CL Do Begin { With } Active := FALSE; SeriesColor := POSITION_COLOR; Pen.Width := POSITION_WIDTH; Position := 0; End; { With } End; { For } M_Old_Data_Time := Now; M_Old_Data_Hour := 0; M_Old_Data_Minute := 0; M_Old_Data_Second := 0; M_Last_Saved_Minute := 0; { Position main form } Left := FORM_LEFT; Top := FORM_TOP; Width := FORM_WIDTH; Height := FORM_HEIGHT; { Initialize current chart } Current_LS.Clear; Current_LP_LS.Clear; Current_EMA_LS.Clear; Current_RMS_LS.Clear; Current_Integral_LS.Clear; Current_Integral_LP_LS.Clear; Current_Chart_C.Extent.UseXMin := TRUE; Current_Chart_C.Extent.UseXMax := TRUE; Current_Chart_C.Extent.UseYMin := TRUE; Current_Chart_C.Extent.UseYMax := TRUE; Current_Chart_C.ExtentSizeLimit.YMax := DATA_CHART_EXTEND_Y_MAX * 2; Current_Chart_C.ExtentSizeLimit.YMin := -DATA_CHART_EXTEND_Y_MAX * 2; Current_Chart_C.ExtentSizeLimit.UseYMax := TRUE; Current_Chart_C.ExtentSizeLimit.UseYMin := TRUE; Current_Chart_C.AxisList.Axes[0].LabelSize := DATA_CHART_LABEL_SIZE; Current_Chart_C.AxisList.Axes[0].Marks.Format := DATA_CHART_UNIT_FORMAT; M_Data_Start_Index := 0; M_Data_End_Index := 0; M_Transfer_Process := TProcess.Create (NIL); {$IFDEF USE_TIMER_THREAD} M_Timer_Thread := T_Timer_Thread.Create (TRUE); M_Timer_Thread.ADS1262.Set_OFCAL (StrToInt (Input_OFCAL_Value_E.Text)); {$ELSE} M_Count := 0; {$ENDIF} Reset_BClick (Sender); End; { TMain_F.FormCreate } { --------------------------------------------------------------------------------------- } Procedure TMain_F.FormDestroy (Sender : TObject); { Free data } { --------------------------------------------------------------------------------------- } Begin { TMain_F.FormDestroy } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.FormDestroy'); {$ENDIF} Chart_T.Enabled := FALSE; M_Transfer_Process.Free; {$IFDEF USE_TIMER_THREAD} M_Timer_Thread.Terminate; Sleep (CLOSE_WAIT_TIME_MSEC); M_Timer_Thread.Free; {$ENDIF} { Free CriticalSection } {$IFDEF USE_CRITICAL_SECTION} DeleteCriticalSection (M_Critical_Section); {$ENDIF} End; { TMain_F.FormDestroy } { --------------------------------------------------------------------------------------- } Procedure TMain_F.FormShow (Sender : TObject); { Show main form } { --------------------------------------------------------------------------------------- } Begin { TMain_F.FormShow } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.FormShow'); {$ENDIF} Input_X_Axis_Extend_EEditingDone (NIL); M_Data_A_Index_0 := 0; M_Data_A_Index_1 := 0; M_Start_Time := Now; {$IFDEF USE_TIMER_THREAD} M_Timer_Thread.Start; {$ENDIF} { Display data } Chart_T.Enabled := TRUE; End; { TMain_F.FormShow } {#####################################################################################} { Buttons and edit components } {#####################################################################################} { --------------------------------------------------------------------------------------- } Procedure TMain_F.Output_Current_Data (F_Measurement_N : Integer; F_Zero_Crossings_N : Integer; F_End_Time : TDateTime); { --------------------------------------------------------------------------------------- } Var I : Integer; Bit_N_Max : Double; Begin { TMain_F.Output_Current_Data } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Output_Current_Data'); {$ENDIF} Bit_N_Max := 0; For I := 0 To BIT_N_RANGE - 1 Do Begin { For } // Bit_N_Max := Max (Bit_N_Max, Log2 (Max (Abs (M_Timer_Thread.M_Data_Y_A [Validate_Array_Index (M_Data_A_Size - 1 - I, DATA_ARRAY_SIZE)]), 1))); End; { For } Output_NPS_E.Text := FormatFloat ('#,##0.0', Double (F_Measurement_N) / (Double (MilliSecondSpan (M_Start_Time, F_End_Time)) / 1000)); {$IFDEF USE_TIMER_THREAD} Output_Counter_E.Text := FormatFloat ('#,##0', M_Timer_Thread.Count); {$ELSE} Output_Counter_E.Text := FormatFloat ('#,##0', M_Count); {$ENDIF} Output_Bits_E.Text := FormatFloat ('#,##0.0', Bit_N_Max); Output_Freq_E.Text := FormatFloat ('#,##0.0', F_Zero_Crossings_N / 2 / Double (MilliSecondSpan (M_Start_Time, F_End_Time)) * 1000); M_Start_Time := F_End_Time; End; { TMain_F.Output_Current_Data } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Output_Current_Time; { --------------------------------------------------------------------------------------- } Var Time_Value : TDateTime; Begin { TMain_F.Output_Current_Time } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Output_Current_Time'); {$ENDIF} Time_Value := Now; Status_L.Caption := CURRENT_TIME_FORMAT_00_S + FormatDateTime ('DD.MM.YYYY', Time_Value) + CURRENT_TIME_FORMAT_01_S + FormatDateTime ('hh:nn:ss', Time_Value); Repaint; Application.ProcessMessages; End; { TMain_F.Output_Current_Time } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Close_BClick (Sender : TObject); { Close button pressed } { --------------------------------------------------------------------------------------- } Begin { TMain_F.Close_BClick } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Close_BClick'); {$ENDIF} Chart_T.Enabled := FALSE; Sleep (CLOSE_WAIT_TIME_MSEC); Close; End; { TMain_F.Close_BClick } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Start_Stop_BClick (Sender : TObject); { Start/Stop button pressed } { --------------------------------------------------------------------------------------- } Begin { TMain_F.Start_Stop_BClick } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Start_Stop_BClick'); {$ENDIF} Chart_T.Enabled := not Chart_T.Enabled; End; { TMain_F.Start_Stop_BClick } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Reset_BClick (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Reset_BClick } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Reset_BClick'); {$ENDIF} Current_Chart_C.Extent.XMin := Now - (StrToInt (Input_X_Axis_Extend_E.Text) / 24 / 60 / 60); Current_Chart_C.Extent.XMax := Now; Current_Chart_C.Extent.YMax := DATA_CHART_EXTEND_Y; Current_Chart_C.Extent.YMin := -DATA_CHART_EXTEND_Y; End; { TMain_F.Reset_BClick } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Input_Sensivity_Bits_EEditingDone (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Input_Sensivity_Bits_EEditingDone } {$IFDEF USE_TIMER_THREAD} Try M_Timer_Thread.ADS1262.Sensivity := StrToInt (Input_Sensivity_Bits_E.Text); Except M_Timer_Thread.ADS1262.Sensivity := ADS1262_INITIAL_SENSIVITY; End; { Try } {$ENDIF} End; { TMain_F.Input_Sensivity_Bits_EEditingDone } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Input_OFCAL_Value_EEditingDone (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Input_OFCAL_Value_EEditingDone } {$IFDEF USE_TIMER_THREAD} Try M_Timer_Thread.ADS1262.Set_OFCAL (StrToInt (Input_OFCAL_Value_E.Text)); Except M_Timer_Thread.ADS1262.Set_OFCAL (ADS1262_INITIAL_OFCAL); End; { Try } {$ENDIF} End; { TMain_F.Input_OFCAL_Value_EEditingDone } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Input_LP_Span_EEditingDone (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Input_LP_Span_EEditingDone } {$IFDEF USE_TIMER_THREAD} M_Timer_Thread.LP_Span := StrToInt (Input_LP_Span_E.Text); {$ENDIF} End; { TMain_F.Input_LP_Span_EEditingDone } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Input_X_Axis_Extend_EEditingDone (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Input_X_Axis_Extend_EEditingDone } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Input_X_Axis_Extend_EEditingDone'); {$ENDIF} Current_Chart_C.Extent.XMin := Now - (StrToInt (Input_X_Axis_Extend_E.Text) / 24 / 60 / 60); Current_Chart_C.Extent.XMax := Now; Chart_T.Interval := Round (StrToFloat (Input_X_Axis_Extend_E.Text) * 1000); End; { TMain_F.Input_X_Axis_Extend_EEditingDone } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Save_BClick (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Save_BClick } Case T_Chart_Kind (Main_PC.TabIndex) Of CURRENT_CHART_CK : Begin { CURRENT_CHART_CK } Save_Data (TrimFilename (ExtractFilePath (Application.Exename) + CURRENT_IMAGE_FILE_NAME), Main_P); End; { CURRENT_CHART_CK } DAILY_CHART_CK : Begin { DAILY_CHART_CK } Save_Data (TrimFilename (ExtractFilePath (Application.Exename) + DAILY_IMAGE_FILE_NAME), Main_P); End; { DAILY_CHART_CK } End; { Case } End; { TMain_F.Save_BClick } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Transfer_TTimer (Sender : TObject); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Transfer_TTimer } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Transfer_TTimer'); {$ENDIF} Transfer_T.Enabled := FALSE; Transfer_File (M_Transfer_Command); End; { TMain_F.Transfer_TTimer } {#####################################################################################} { Utilities } {#####################################################################################} { --------------------------------------------------------------------------------------- } Procedure TMain_F.Debug_Output (F_Text : String); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Debug_Output } {$IFDEF DEBUG_INFORMATION} WriteLn (FormatDateTime ('DD.MM.YYYY - hh:nn:ss - ', Now) + F_Text); {$ENDIF} End; { TMain_F.Debug_Output } { --------------------------------------------------------------------------------------- } Function TMain_F.Calculate_Velocity (F_Data : Int_32) : Double; { Calculate voltage from raw data } { --------------------------------------------------------------------------------------- } Begin { TMain_F.Calculate_Velocity } Result := F_Data * VOLTAGE_LIMIT / $7FFFFFFF / SM24_VELOCITY_FACTOR * 1000; End; { TMain_F.Calculate_Velocity } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Save_Data (F_Filename : String; F_Panel : TPanel); { --------------------------------------------------------------------------------------- } Var B : TBitmap; jpgb : TJPEGImage; P : TPanel; Begin { TMain_F.Save_Data } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Save_Data'); {$ENDIF} B := TBitmap.Create; jpgb := TJPEGImage.Create; P := F_Panel; B.Width := P.Width; B.Height := P.Height; Try P.PaintTo (B.Canvas, 0, 0); jpgb.Assign (B); jpgb.CompressionQuality := 90; jpgb.SaveToFile (F_Filename); Except End; { Try } jpgb.Free; B.Free; End; { TMain_F.Save_Data } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Transfer_File (F_Command : String); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Transfer_File } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Transfer_File'); {$ENDIF} { Transfer file to Internet server } {$PUSH} {$WARNINGS OFF} M_Transfer_Process.CommandLine := F_Command; {$POP} M_Transfer_Process.Execute; End; { TMain_F.Transfer_File } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Read_Array_Data (F_Index : Integer; Var F_X : TDateTime; Var F_Y : Int_32; Var F_LP_Y : Int_32); { --------------------------------------------------------------------------------------- } Begin { TMain_F.Read_Array_Data } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Read_Array_Data'); {$ENDIF} {$IFDEF USE_CRITICAL_SECTION} EnterCriticalSection (Main_F.M_Critical_Section); Try {$ENDIF} {$IFDEF USE_TIMER_THREAD} F_X := M_Timer_Thread.Data_X_A [F_Index]; F_Y := M_Timer_Thread.Data_Y_A [F_Index]; F_LP_Y := M_Timer_Thread.Data_LP_Y_A [F_Index]; {$ELSE} F_X := Now; F_Y := Random (RANDOM_MAX); F_LP_Y := Random (RANDOM_MAX); {$ENDIF} {$IFDEF USE_CRITICAL_SECTION} Finally LeaveCriticalSection (Main_F.M_Critical_Section); End; {$ENDIF} End; { TMain_F.Read_Array_Data } {#####################################################################################} { Chart } {#####################################################################################} { --------------------------------------------------------------------------------------- } Procedure TMain_F.Clear_Hour_Data_LS (F_Hour_Data_LS : TLineSeries); { --------------------------------------------------------------------------------------- } Var J : Integer; Begin { TMain_F.Clear_Hour_Data_LS } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Clear_Hour_Data_LS'); {$ENDIF} With F_Hour_Data_LS Do Begin { With } Clear; SeriesColor := DATA_COLOR; LinePen.Width := DATA_PIN_WIDTH; For J := 0 To VALUES_PER_HOUR - 1 Do Begin { For } AddXY (Round (J) / 60, 0); AddXY (Round (J) / 60, 0); End; { For } End; { With } End; { TMain_F.Clear_Hour_Data_LS } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Clear_Hour_RMS_BS (F_Hour_RMS_BS : TBarSeries); { --------------------------------------------------------------------------------------- } Var J : Integer; Begin { TMain_F.Clear_Hour_RMS_BS } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Clear_Hour_RMS_BS'); {$ENDIF} With F_Hour_RMS_BS Do Begin { With } Clear; SeriesColor := RMS_COLOR; BarWidthPercent := RMS_BAR_WIDTH_PERCENT; For J := 0 To VALUES_PER_HOUR - 1 Do Begin { For } AddXY (Round (J) / 60, 0.0); End; { For } End; { With } End; { TMain_F.Clear_Hour_RMS_BS } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Chart_TS_DataPointHintToolHint (ATool : TDataPointHintTool; Const APoint : TPoint; Var AHint : String); { --------------------------------------------------------------------------------------- } Const SPACE_START = ' '; Var Time_Value : TDateTime; Voltage : Double; Begin { TMain_F.Chart_TS_DataPointHintToolHint } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Chart_TS_DataPointHintToolHint'); {$ENDIF} Try Time_Value := TChartSeries (ATool.Series).Source.Item [ATool.PointIndex]^.X; Voltage := TChartSeries (ATool.Series).Source.Item [ATool.PointIndex]^.Y; AHint := SPACE_START + 'X : ' + FormatDateTime ('hh:nn:ss.zzz', Time_Value) + #13 + Format (SPACE_START + 'Y : %.8f', [Voltage]); Except AHint := ''; End; { Try } End; { TMain_F.Chart_TS_DataPointHintToolHint } { --------------------------------------------------------------------------------------- } Procedure TMain_F.Chart_TTimer (Sender : TObject); { Repaint chart } { --------------------------------------------------------------------------------------- } Var Index : Integer; Time_Value : TDateTime; Voltage : Double; Old_Voltage : Double; Integral_Voltage : Double; LP_Integral_Voltage : Double; Zero_Crossings_C : Integer; Current_Extend : TDoubleRect; Extend_Dif : Double; J : Integer; Start_Index : Integer; End_Index : Integer; V : Double; LP_Voltage : Double; Additional_Index : Integer; Data_Time : TDateTime; Data_Hour : Integer; Data_Minute : Integer; Data_Second : Integer; RMS : Double; Upper_Peak : Double; Lower_Peak : Double; Hour_Data_LS : TLineSeries; Hour_Position_CL : TConstantLine; {$IFDEF SAVE_IMAGE} Filename : String; {$ENDIF} Begin { TMain_F.Chart_TTimer } {$IFDEF DEBUG_INFORMATION} Debug_Output ('Begin of: TMain_F.Chart_TTimer'); {$ENDIF} Case T_Chart_Kind (Main_PC.TabIndex) Of CURRENT_CHART_CK : Begin { CURRENT_CHART_CK } {$IFDEF SAVE_IMAGE} Filename := TrimFilename (ExtractFilePath (Application.Exename) + CURRENT_IMAGE_FILE_NAME); {$ENDIF} {$IFDEF TRANSFER_DATA_TO_INTERNET_SERVER} M_Transfer_Command := TRANSFER_FILE_TXT + TrimFilename (ExtractFilePath (Application.Exename) + CURRENT_IMAGE_FILE_NAME); {$ENDIF} Current_LS.Active := Show_Data_CB.Checked; Current_LP_LS.Active := Show_LP_Data_CB.Checked; Current_EMA_LS.Active := Show_EMA_CB.Checked; Current_RMS_LS.Active := Show_RMS_CB.Checked; Current_Integral_LS.Active := Show_Integral_CB.Checked; Current_Integral_LP_LS.Active := Show_LP_Integral_CB.Checked; Current_LS.BeginUpdate; Current_LP_LS.BeginUpdate; Current_EMA_LS.BeginUpdate; Current_RMS_LS.BeginUpdate; Current_Integral_LS.BeginUpdate; Current_Integral_LP_LS.BeginUpdate; Current_LS.Clear; Current_LP_LS.Clear; Current_EMA_LS.Clear; Current_RMS_LS.Clear; Current_Integral_LS.Clear; Current_Integral_LP_LS.Clear; {$IFDEF USE_TIMER_THREAD} M_Data_A_Index_1 := M_Timer_Thread.Data_A_Index; {$ELSE} M_Data_A_Index_1 := RANDOM_N; {$ENDIF} Zero_Crossings_C := 0; Additional_Index := 0; If M_Data_A_Index_1 < M_Data_A_Index_0 Then Begin { then } Start_Index := M_Data_A_Index_0; End_Index := DATA_ARRAY_SIZE - 1; Voltage := 0; Old_Voltage := Voltage; Index := Start_Index; While Index <= End_Index Do Begin { While } {$IFDEF USE_TIMER_THREAD} Time_Value := M_Timer_Thread.Data_X_A [Index]; Voltage := Calculate_Velocity (M_Timer_Thread.Data_Y_A [Index]); LP_Voltage := Calculate_Velocity (M_Timer_Thread.Data_LP_Y_A [Index]); Integral_Voltage := Calculate_Velocity (M_Timer_Thread.Data_Integral_Y_A [Index]); LP_Integral_Voltage := Calculate_Velocity (M_Timer_Thread.Data_LP_Integral_Y_A [Index]); Current_LS.AddXY (Time_Value, Voltage); Current_LP_LS.AddXY (Time_Value, LP_Voltage); Current_Integral_LS.AddXY (Time_Value, Integral_Voltage); Current_Integral_LP_LS.AddXY (Time_Value, LP_Integral_Voltage); Current_EMA_LS.AddXY (Time_Value, Calculate_Velocity (M_Timer_Thread.ADS1262.EMA_Data)); {$ELSE} Time_Value := M_Old_Data_Time + ((Now - M_Old_Data_Time) / End_Index * Index); Voltage := Calculate_Velocity (Random (RANDOM_MAX)); LP_Voltage := Calculate_Velocity (Random (RANDOM_MAX)); Integral_Voltage := Calculate_Velocity (Random (RANDOM_MAX)); LP_Integral_Voltage := Calculate_Velocity (Random (RANDOM_MAX)); Current_LS.AddXY (Time_Value, Voltage); Current_LP_LS.AddXY (Time_Value, LP_Voltage); Current_Integral_LS.AddXY (Time_Value, Integral_Voltage); Current_Integral_LP_LS.AddXY (Time_Value, LP_Integral_Voltage); Current_EMA_LS.AddXY (Time_Value, Calculate_Velocity (Random (RANDOM_MAX))); Inc (M_Count); {$ENDIF} { Calculate RMS } RMS := 0; For J := 0 To StrToInt (Input_LP_Span_E.Text) - 1 Do Begin { For } {$IFDEF USE_TIMER_THREAD} V := Calculate_Velocity (M_Timer_Thread.Data_Y_A [Validate_Array_Index (Index - J, DATA_ARRAY_SIZE)]); {$ELSE} V := Calculate_Velocity (Random (RANDOM_MAX)); {$ENDIF} RMS := RMS + Sqr (V); End; { For } RMS := Sqrt (RMS / (StrToInt (Input_LP_Span_E.Text))); Current_RMS_LS.AddXY (Time_Value, RMS); If (Index > Start_Index) and ((Old_Voltage < 0) and (Voltage > 0) or (Old_Voltage > 0) and (Voltage < 0)) Then Begin { then } Inc (Zero_Crossings_C); End; { then } Old_Voltage := Voltage; Index := Validate_Array_Index (Index + 1, DATA_ARRAY_SIZE); End; { While } Additional_Index := End_Index - Start_Index; M_Data_A_Index_0 := 0; End; { then } Start_Index := M_Data_A_Index_0; End_Index := M_Data_A_Index_1 - 1; Voltage := 0; Old_Voltage := Voltage; Index := Start_Index; While Index <= End_Index Do Begin { While } {$IFDEF USE_TIMER_THREAD} Time_Value := M_Timer_Thread.Data_X_A [Index]; Voltage := Calculate_Velocity (M_Timer_Thread.Data_Y_A [Index]); LP_Voltage := Calculate_Velocity (M_Timer_Thread.Data_LP_Y_A [Index]); Integral_Voltage := Calculate_Velocity (M_Timer_Thread.Data_Integral_Y_A [Index]); LP_Integral_Voltage := Calculate_Velocity (M_Timer_Thread.Data_LP_Integral_Y_A [Index]); Current_LS.AddXY (Time_Value, Voltage); Current_LP_LS.AddXY (Time_Value, LP_Voltage); Current_Integral_LS.AddXY (Time_Value, Integral_Voltage); Current_Integral_LP_LS.AddXY (Time_Value, LP_Integral_Voltage); Current_EMA_LS.AddXY (Time_Value, Calculate_Velocity (M_Timer_Thread.ADS1262.EMA_Data)); {$ELSE} Time_Value := M_Old_Data_Time + ((Now - M_Old_Data_Time) / End_Index * Index); Voltage := Calculate_Velocity (Random (RANDOM_MAX)); LP_Voltage := Calculate_Velocity (Random (RANDOM_MAX)); Integral_Voltage := Calculate_Velocity (Random (RANDOM_MAX)); LP_Integral_Voltage := Calculate_Velocity (Random (RANDOM_MAX)); Current_LS.AddXY (Time_Value, Voltage); Current_LP_LS.AddXY (Time_Value, LP_Voltage); Current_Integral_LS.AddXY (Time_Value, Integral_Voltage); Current_Integral_LP_LS.AddXY (Time_Value, LP_Integral_Voltage); Current_EMA_LS.AddXY (Time_Value, Calculate_Velocity (Random (RANDOM_MAX))); Inc (M_Count); {$ENDIF} { Calculate RMS } RMS := 0; For J := 0 To StrToInt (Input_LP_Span_E.Text) - 1 Do Begin { For } {$IFDEF USE_TIMER_THREAD} V := Calculate_Velocity (M_Timer_Thread.Data_Y_A [Validate_Array_Index (Index - J, DATA_ARRAY_SIZE)]); {$ELSE} V := Calculate_Velocity (Random (RANDOM_MAX)); {$ENDIF} RMS := RMS + Sqr (V); End; { For } RMS := Sqrt (RMS / (StrToInt (Input_LP_Span_E.Text))); Current_RMS_LS.AddXY (Time_Value, RMS); If (Index > Start_Index) and ((Old_Voltage < 0) and (Voltage > 0) or (Old_Voltage > 0) and (Voltage < 0)) Then Begin { then } Inc (Zero_Crossings_C); End; { then } Old_Voltage := Voltage; Index := Validate_Array_Index (Index + 1, DATA_ARRAY_SIZE); End; { While } If Show_Current_Data_CB.Checked = TRUE Then Begin { then } Current_Extend := Current_Chart_C.LogicalExtent; Extend_Dif := Current_Extend.b.X - Current_Extend.a.X; Current_Extend.b.X := Now; Current_Extend.a.X := Current_Extend.b.X - Extend_Dif; Current_Chart_C.LogicalExtent := Current_Extend; Current_Extend := Current_Chart_C.LogicalExtent; Current_Chart_C.LogicalExtent := Current_Extend; End; { then } Current_Integral_LP_LS.EndUpdate; Current_Integral_LS.EndUpdate; Current_RMS_LS.EndUpdate; Current_EMA_LS.EndUpdate; Current_LP_LS.EndUpdate; Current_LS.EndUpdate; {$IFDEF USE_TIMER_THREAD} Time_Value := M_Timer_Thread.Data_X_A [End_Index]; {$ELSE} Time_Value := Now; {$ENDIF} Data_Time := Time_Value; Data_Hour := HourOf (Time_Value); Data_Minute := MinuteOf (Time_Value); Data_Second := SecondOf (Time_Value); End; { CURRENT_CHART_CK } DAILY_CHART_CK : Begin { DAILY_CHART_CK } {$IFDEF SAVE_IMAGE} Filename := TrimFilename (ExtractFilePath (Application.Exename) + DAILY_IMAGE_FILE_NAME); {$ENDIF} {$IFDEF TRANSFER_DATA_TO_INTERNET_SERVER} M_Transfer_Command := TRANSFER_FILE_TXT + TrimFilename (ExtractFilePath (Application.Exename) + DAILY_IMAGE_FILE_NAME); {$ENDIF} { Calculate peak values } {$IFDEF USE_TIMER_THREAD} M_Data_A_Index_1 := M_Timer_Thread.Data_A_Index; {$ELSE} M_Data_A_Index_1 := RANDOM_N; {$ENDIF} Zero_Crossings_C := 0; Additional_Index := 0; Upper_Peak := 0; Lower_Peak := 0; If M_Data_A_Index_1 < M_Data_A_Index_0 Then Begin { then } Start_Index := M_Data_A_Index_0; End_Index := DATA_ARRAY_SIZE - 1; Voltage := 0; Old_Voltage := Voltage; Index := Start_Index; While Index <= End_Index Do Begin { While } {$IFDEF USE_TIMER_THREAD} Voltage := Calculate_Velocity (M_Timer_Thread.Data_Y_A [Index]); {$ELSE} Voltage := Calculate_Velocity (Random (RANDOM_MAX)); Inc (M_Count); {$ENDIF} Upper_Peak := Max (Upper_Peak, Voltage); Lower_Peak := Min (Lower_Peak, Voltage); If (Index > Start_Index) and ((Old_Voltage < 0) and (Voltage > 0) or (Old_Voltage > 0) and (Voltage < 0)) Then Begin { then } Inc (Zero_Crossings_C); End; { then } Old_Voltage := Voltage; Index := Validate_Array_Index (Index + 1, DATA_ARRAY_SIZE); End; { While } Additional_Index := End_Index - Start_Index; M_Data_A_Index_0 := 0; End; { then } Start_Index := M_Data_A_Index_0; End_Index := M_Data_A_Index_1 - 1; Voltage := 0; Old_Voltage := Voltage; Index := Start_Index; While Index <= End_Index Do Begin { While } {$IFDEF USE_TIMER_THREAD} Voltage := Calculate_Velocity (M_Timer_Thread.Data_Y_A [Index]); {$ELSE} Voltage := Calculate_Velocity (Random (RANDOM_MAX)); Inc (M_Count); {$ENDIF} Upper_Peak := Max (Upper_Peak, Voltage); Lower_Peak := Min (Lower_Peak, Voltage); If (Index > Start_Index) and ((Old_Voltage < 0) and (Voltage > 0) or (Old_Voltage > 0) and (Voltage < 0)) Then Begin { then } Inc (Zero_Crossings_C); End; { then } Old_Voltage := Voltage; Index := Validate_Array_Index (Index + 1, DATA_ARRAY_SIZE); End; { While } {$IFDEF USE_TIMER_THREAD} Time_Value := M_Timer_Thread.Data_X_A [End_Index]; {$ELSE} Time_Value := Now; {$ENDIF} Data_Time := Time_Value; Data_Hour := HourOf (Time_Value); Data_Minute := MinuteOf (Time_Value); Data_Second := SecondOf (Time_Value); Index := (Data_Minute * 60) + Data_Second; Hour_Data_LS := M_Hour_Data_LS_A [Data_Hour]; Hour_Position_CL := M_Hour_Position_CL_A [Data_Hour]; M_Hour_Position_CL_A[M_Old_Data_Hour].Active := FALSE; Hour_Position_CL.Position := Index / 60; Hour_Position_CL.Active := TRUE; { Output peak values } Hour_Data_LS.BeginUpdate; { Clear data if new hour starts } If Data_Hour <> M_Old_Data_Hour Then Begin { then } Clear_Hour_Data_LS (Hour_Data_LS); End; { then } Hour_Data_LS.ListSource.Item[Index shl 1]^.Y := Upper_Peak; Hour_Data_LS.ListSource.Item[(Index shl 1) + 1]^.Y := Lower_Peak; Hour_Data_LS.EndUpdate; End; { DAILY_CHART_CK } End; { Case } M_Data_A_Size := (End_Index - Start_Index) + Additional_Index; {$IFDEF USE_TIMER_THREAD} M_Data_A_Index_0 := M_Data_A_Index_1; {$ELSE} M_Data_A_Index_0 := 0; {$ENDIF} Output_Current_Data (M_Data_A_Size, Zero_Crossings_C, Time_Value); Output_Current_Time; If Data_Minute <> M_Old_Data_Minute Then Begin { then } {$IFDEF SAVE_IMAGE} Save_Data (Filename, Main_P); {$ENDIF} {$IFDEF TRANSFER_DATA_TO_INTERNET_SERVER} Transfer_T.Enabled := TRUE; {$ENDIF} End; { then } M_Old_Data_Time := Data_Time; M_Old_Data_Hour := Data_Hour; M_Old_Data_Minute := Data_Minute; M_Old_Data_Second := Data_Second; End; { TMain_F.Chart_TTimer } End.
project_defines.inc
{ ####################################################################################### } { ## ## } { ## Includes ## } { ## ## } { ## Copyright (C) 2018-2019 : Dr. Jürgen Abel ## } { ## Email : juergen@juergen-abel.info ## } { ## Internet : www.seismometer.info ## } { ## ## } { ####################################################################################### } { ####################################################################################### } { ## ## } { ## Global defines ## } { ## ## } { ####################################################################################### } {$PACKRECORDS C} { ####################################################################################### } { ## ## } { ## Following Defines can be enabled or disabled ## } { ## ## } { ####################################################################################### } { $DEFINE DEBUG_GPIO_OUTPUT} { $DEFINE DEBUG_SPI_OUTPUT} { $DEFINE DEBUG_ADS1262_OUTPUT} { $DEFINE DEBUG_MAIN_OUTPUT} { $DEFINE DEBUG_ERROR} { $DEFINE DEBUG_ADC1_DATA} { $DEFINE DEBUG_INFORMATION} {$DEFINE SELF_CALIBRATION_ON} {$DEFINE USE_INTERRUPT} { $DEFINE SAVE_IMAGE} { $DEFINE TRANSFER_DATA_TO_INTERNET_SERVER} { $DEFINE USE_CRITICAL_SECTION} {$DEFINE USE_TIMER_THREAD}
Leave a Reply
You must be logged in to post a comment.