diff --git a/commonFunctions/sensors/Sensor1D.m b/commonFunctions/sensors/Sensor1D.m index 5b4d50908367dea6039cdbbed37672b3aef98524..8470de04db30177b2c4bf318142938a329bb8087 100644 --- a/commonFunctions/sensors/Sensor1D.m +++ b/commonFunctions/sensors/Sensor1D.m @@ -87,10 +87,10 @@ classdef Sensor1D < handle if found obj.noiseType = vect(ii).noise_type; - if isa(obj,"Sensor1D") || isa(obj,"SensorFault") + if strcmp("Sensor1D", class(obj)) || strcmp("SensorFault", class(obj)) obj.noiseDataTrack1 = vect(ii).track1; obj.noiseFactor = vect(ii).factor; - elseif isa(obj,"Sensor3D") || isa(obj,"SensorGPS") + elseif strcmp("Sensor3D", class(obj)) || strcmp("SensorGPS", class(obj)) obj.noiseDataTrack1 = vect(ii).track1; obj.noiseDataTrack2 = vect(ii).track2; obj.noiseDataTrack3 = vect(ii).track3; @@ -99,9 +99,9 @@ classdef Sensor1D < handle error("Sensor not defined") end else - if isa(obj,"Sensor1D") || isa(obj,"SensorFault") + if strcmp("Sensor1D", class(obj)) || strcmp("SensorFault", class(obj)) obj.noiseDataTrack1 = []; - elseif isa(obj,"Sensor3D") || isa(obj,"SensorGPS") + elseif strcmp("Sensor3D", class(obj)) || strcmp("SensorGPS", class(obj)) obj.noiseDataTrack1 = []; obj.noiseDataTrack2 = []; obj.noiseDataTrack3 = []; diff --git a/commonFunctions/sensors/SensorFault.m b/commonFunctions/sensors/SensorFault.m index c201e86d8a8019940ea47d7ae1b97fe53a142ecc..6c4138289febd75bd98b7bf095c0267714926d12 100644 --- a/commonFunctions/sensors/SensorFault.m +++ b/commonFunctions/sensors/SensorFault.m @@ -1,46 +1,22 @@ -classdef SensorFault < handle - - % Author: Jan Hammelman - % Skyward Experimental Rocketry | ELC-SCS Dept | electronics@skywarder.eu - % email: jan.hammelmann@skywarder.eu,alessandro.delduca@skywarder.eu - % Release date: 01/03/2021 - - %SENSOR Super call for all sensor - % Inherit from handle to have state variables which can be changed - % inside a method - % update: Alessandro Donadi, 31/08/2023 - %NOTE ON THE UPDATE: - % Added fault simulation capabilities from the faliure simulator made - % by Angelo G. Gaillet and released on 31/07/2022 - properties (Access='public') - minMeasurementRange; % Max limit of sensor - maxMeasurementRange; % Min limit of sensor - - bit; % number of bits for the sensor ( if available) - resolution; % resolution of the sensor - - % noises - noiseType; % White (default) or Pink - noiseDataTrack1; - noiseFactor; - noiseVariance; % Varianze for the gaussian white noise - - offset; % Offset in all directions - - tempOffset; % Coefficent for temperature depending offset - - dt; % Sampling time - - error2dOffset; % first column: inputArg, second column: relativeArg, third column: error +classdef SensorFault < Sensor1D + + % Author: Stefano Belletti, Samuel Flore + % Skyward Experimental Rocketry | AVN - GNC + % email: stefano.belletti@skywarder.eu + % Release date: 18/11/2024 + % + % Sensor class for SensorFault + % + % Creating a new sensor: [obj] = Sensor1D() + properties (Access='public') fault_time; % if set to -1 it will be randomly chosen between a min and a max time in seconds max_fault_time; %upper bound of the time window where the fault can occur in case it's randomly chosen min_fault_time; %lower bound of the time window where the fault can occur in case it's randomly chosen - end - properties (Access = public) %attributes used for fault simulation + % attributes used for fault simulation failureType; fault_offset; lambda; @@ -231,191 +207,33 @@ classdef SensorFault < handle methods (Access='protected') - function outputArg = saturation(obj,inputArg) - %SATURATION Includes saturation to the sensor model - % inputArg is limited to minMeasurementRange at the lower end and maxMeasurementRange at the upper end - % - % Necessary properties: - % minMeasurementRange: Max limit of sensor - % maxMeasurementRange: Min limit of sensor - % - % Inputs: - % inputArg: sensor data - % - % Outputs: - % outputArg: sensor data with saturation - - % checks if sensor data is higher than max possible value - if (~isempty(obj.maxMeasurementRange)) - inputArg(inputArg>obj.maxMeasurementRange)=obj.maxMeasurementRange; - end - - % checks if sensor data is lower than min possible value - if (~isempty(obj.minMeasurementRange)) - inputArg(inputArg<obj.minMeasurementRange)=obj.minMeasurementRange; - end - - outputArg = inputArg; - end - - - function outputArg = quantization(obj,inputArg) - %QUATIZATION Quantize the sensor data - % Quantizes the signal with the resolution properie of the object - % - % Necessary properties: - % resolution: resolution of the sensor - % - % Inputs: - % inputArg: sensor data - % - % Outputs: - % outputArg: quantized sensor data - - if (~isempty(obj.resolution)) - inputArg = obj.resolution*round(inputArg/obj.resolution); - end - outputArg = inputArg; - end - - - function outputArg = addNoise(obj,inputArg,t) - %WHITE_NOISE Includes gaussian white noise to the sensor data - % Adds gaussian white noise with variance noiseVariance - % - % Necessary properties: - % noiseVariance: Varianze for the gaussian white noise - % - % Inputs: - % inputArg: sensor data - % - % Outputs: - % outputArg: sensor data with white noise - - % if (~isempty(obj.noiseVariance)) - % %inputArg=inputArg+ones(size(inputArg)).*sqrt(obj.noiseVariance).*randn(1,1);, - % inputArg=inputArg+sqrt(obj.noiseVariance).*randn(size(inputArg)); - % end - % outputArg = inputArg; - - if ~isempty(obj.noiseVariance) % check for old results - inputArg = inputArg + sqrt(obj.noiseVariance).*randn(length(inputArg),1); - elseif ~isempty(obj.noiseDataTrack1) - if strcmp(obj.noiseType, "white") - inputArg = inputArg + sqrt(obj.noiseDataTrack1*obj.noiseFactor).*randn(length(inputArg),1); - elseif strcmp(obj.noiseType, "pink") - for ii = 1:length(obj.noiseDataTrack1.peaks_vect_f) - inputArg = inputArg + obj.noiseDataTrack1.peaks_vect_val(ii)*obj.noiseFactor*sin(2*pi*obj.noiseDataTrack1.peaks_vect_f(ii)*t + randn(1)); - end - inputArg = inputArg + sqrt(obj.noiseDataTrack1.variance*obj.noiseFactor).*randn(length(inputArg),1); - else - error("This noise is not defined") - end - end - - outputArg = inputArg; - end - - - function outputArg = addOffset(obj,inputArg) - %ADD_OFFSET Adds an offset to the signal - % adds the propertie offset to the input signal - % - % Necessary properties: - % offset: Offset in all directions - % - % Inputs: - % inputArg: sensor data - % - % Outputs: - % outputArg: sensor data plus offset - - if (~isempty(obj.offset)) - inputArg=inputArg+ones(size(inputArg)).*obj.offset; - end - outputArg = inputArg; - end - - - function outputArg = addTempOffset(obj,inputArg,temp) - %ADD_Temp_OFFSET Adds an temperature dependen offset to the signal - % adds the propertie tempOffset multiplied by the temperature input temp to the input signal - % - % Necessary properties: - % tempOffset: Coefficent for temperature depending offset - % - % Inputs: - % inputArg: sensor data - % temp: temperature of the sensor - % - % Outputs: - % outputArg: sensor data plus temerature depending offset - - if (~isempty(obj.tempOffset)) - inputArg=inputArg+ones(size(inputArg)).*temp*obj.tempOffset; - end - outputArg = inputArg; - end - - - function outputArg = add2DOffset(obj,inputArg,temp) - %ADD_2D_OFFSET Adds a offset that depends on the inputArg and temp - % The offset is linear interpolated with the data in matrice error2dOffset - % - % Necessary properties: - % error2dOffset: data for offset with first column: inputArg, second column: relativeArg, third column: error - % - % Inputs: - % inputArg: sensor data - % temp: temperature of the sensor - % - % Outputs: - % outputArg: sensor data plus 2D depending offset - - if (~isempty(obj.error2dOffset)) - inputArg=inputArg+... - griddata(obj.error2dOffset(:,1),obj.error2dOffset(:,2),obj.error2dOffset(:,3),inputArg,temp); - end - outputArg = inputArg; - end - function obj = reset(obj) %method - obj.failureType = 'None'; - obj.fault_offset = 0; - obj.lambda = 0; - obj.sigmaDeg = 0; - obj.sigmaIS = 0; - obj.tError = 0; - obj.gain = 1; - obj.value = 0; - obj.likelihoodFS = 0; - obj.likelihoodIS = 0; - obj.alsoNegSpikes = false; - obj.severity = 0; - obj.randomSpikeAmpl = false; - obj.satMax = inf; - obj.satMin = -inf; - obj.settings.saturateFlag = false; - obj.settings.bias = false; - obj.settings.drift = false; - obj.settings.degradation = false; - obj.settings.freezing = false; - obj.settings.calerr = false; - obj.settings.fs = false; - obj.settings.is = false; - - obj.frozenValue = nan; - end + obj.failureType = 'None'; + obj.fault_offset = 0; + obj.lambda = 0; + obj.sigmaDeg = 0; + obj.sigmaIS = 0; + obj.tError = 0; + obj.gain = 1; + obj.value = 0; + obj.likelihoodFS = 0; + obj.likelihoodIS = 0; + obj.alsoNegSpikes = false; + obj.severity = 0; + obj.randomSpikeAmpl = false; + obj.satMax = inf; + obj.satMin = -inf; + obj.settings.saturateFlag = false; + obj.settings.bias = false; + obj.settings.drift = false; + obj.settings.degradation = false; + obj.settings.freezing = false; + obj.settings.calerr = false; + obj.settings.fs = false; + obj.settings.is = false; - - end - - methods (Access = private) - - function data = saturate(data) - data = max(obj.satMin, min(obj.satMax, data)); + obj.frozenValue = nan; end - end end diff --git a/data/2024_Lyra_Portugal_October/initSensors2024_Lyra_Portugal_October.m b/data/2024_Lyra_Portugal_October/initSensors2024_Lyra_Portugal_October.m index 3ba053896f09f3b3f1ca595c04541792f1e04c67..8de0bb415ba191482240ca27d6d4e33f6221c7b2 100644 --- a/data/2024_Lyra_Portugal_October/initSensors2024_Lyra_Portugal_October.m +++ b/data/2024_Lyra_Portugal_October/initSensors2024_Lyra_Portugal_October.m @@ -13,9 +13,9 @@ sensorSettings.barometer1 = SensorFault(); sensorSettings.barometer1.maxMeasurementRange = 1000; % 1100, 1300 in mbar sensorSettings.barometer1.minMeasurementRange = 0; % 300, 10 in mbar sensorSettings.barometer1.bit = 24; % adc on rocket is 24 bits -sensorSettings.barometer1.resolution = (sensorSettings.barometer1.maxMeasurementRange -sensorSettings.barometer1.minMeasurementRange)/(2^sensorSettings.barometer1.bit); +% sensorSettings.barometer1.resolution = (sensorSettings.barometer1.maxMeasurementRange -sensorSettings.barometer1.minMeasurementRange)/(2^sensorSettings.barometer1.bit); -sensorSettings.barometer1 = loadSensorNoiseData(sensorSettings.barometer1, Lyra_Port_sensor_vect, "main_Main_StaticPressureData1.csv", 1); +% sensorSettings.barometer1 = loadSensorNoiseData(sensorSettings.barometer1, Lyra_Port_sensor_vect, "main_Main_StaticPressureData1.csv", 1); % sensorSettings.barometer1.noiseVariance = 1; % mbar^2 sensorSettings.barometer1.fault_time = 9; % if negative it will be generated at random between a max and a min value @@ -38,15 +38,17 @@ switch settings.fault_sim.fault_type(1) otherwise end +sensorSettings.barometer1.update(Lyra_Port_sensor_vect, "main_Main_StaticPressureData1.csv", 1); + %% barometer2 - static measure (HSCMAND001BAAA5) % NOTE: pressure in mbar, temp should be in C° sensorSettings.barometer2 = SensorFault(); sensorSettings.barometer2.maxMeasurementRange = 1000; % 1100, 1300 in mbar sensorSettings.barometer2.minMeasurementRange = 0; % 300, 10 in mbar sensorSettings.barometer2.bit = 24; % adc on rocket is 24 bits -sensorSettings.barometer2.resolution = (sensorSettings.barometer2.maxMeasurementRange -sensorSettings.barometer2.minMeasurementRange)/(2^sensorSettings.barometer2.bit); +% sensorSettings.barometer2.resolution = (sensorSettings.barometer2.maxMeasurementRange -sensorSettings.barometer2.minMeasurementRange)/(2^sensorSettings.barometer2.bit); -sensorSettings.barometer2 = loadSensorNoiseData(sensorSettings.barometer2, Lyra_Port_sensor_vect, "main_Main_StaticPressureData2.csv", 1); +% sensorSettings.barometer2 = loadSensorNoiseData(sensorSettings.barometer2, Lyra_Port_sensor_vect, "main_Main_StaticPressureData2.csv", 1); % sensorSettings.barometer2.noiseVariance = 1; % mbar^2 sensorSettings.barometer2.fault_time = -1; % if negative it will be generated at random between a max and a min value @@ -69,15 +71,17 @@ switch settings.fault_sim.fault_type(2) otherwise end +sensorSettings.barometer2.update(Lyra_Port_sensor_vect, "main_Main_StaticPressureData2.csv", 1); + %% barometer3 - digital measure (LPS28DFWTR) % NOTE: pressure in mbar, temp should be in C° sensorSettings.barometer3 = SensorFault(); sensorSettings.barometer3.maxMeasurementRange = 4060; % 1100, 1300 in mbar sensorSettings.barometer3.minMeasurementRange = 260; % 300, 10 in mbar sensorSettings.barometer3.bit = 24; -sensorSettings.barometer3.resolution = (sensorSettings.barometer3.maxMeasurementRange -sensorSettings.barometer3.minMeasurementRange)/(2^sensorSettings.barometer3.bit); +% sensorSettings.barometer3.resolution = (sensorSettings.barometer3.maxMeasurementRange -sensorSettings.barometer3.minMeasurementRange)/(2^sensorSettings.barometer3.bit); -sensorSettings.barometer3 = loadSensorNoiseData(sensorSettings.barometer3, Lyra_Port_sensor_vect, "main_Boardcore_LPS28DFWData.csv", 1); +% sensorSettings.barometer3 = loadSensorNoiseData(sensorSettings.barometer3, Lyra_Port_sensor_vect, "main_Boardcore_LPS28DFWData.csv", 1); % sensorSettings.barometer3.noiseVariance = 4.06; % guess in mbar sensorSettings.barometer3.fault_time = -1; % if negative it will be generated at random between a max and a min value @@ -100,6 +104,8 @@ switch settings.fault_sim.fault_type(3) otherwise end +sensorSettings.barometer3.update(Lyra_Port_sensor_vect, "main_Boardcore_LPS28DFWData.csv", 1); + %% accelerometer (6 dof imu - LSM6DSRXTR) % NOTE: acceleration in mg sensorSettings.accelerometer = Sensor3D();