41#include "models/FGFCS.h"
42#include "input_output/FGXMLElement.h"
43#include "input_output/FGLog.h"
54FGSensor::FGSensor(FGFCS* fcs, Element* element)
55 : FGFCSComponent(fcs, element), generator(fcs->GetExec()->GetRandomGenerator())
59 bits = quantized = divisions = 0;
60 PreviousInput = PreviousOutput = 0.0;
61 min = max = bias = gain = noise_variance = lag = drift_rate = drift = span = 0.0;
64 fail_low = fail_high = fail_stuck =
false;
66 Element* quantization_element = element->FindElement(
"quantization");
67 if ( quantization_element) {
68 if ( quantization_element->FindElement(
"bits") ) {
69 bits = (int)quantization_element->FindElementValueAsNumber(
"bits");
71 divisions = (1<<bits);
72 if ( quantization_element->FindElement(
"min") ) {
73 min = quantization_element->FindElementValueAsNumber(
"min");
75 if ( quantization_element->FindElement(
"max") ) {
76 max = quantization_element->FindElementValueAsNumber(
"max");
78 quant_property = quantization_element->GetAttributeValue(
"name");
80 granularity = span/divisions;
82 if ( element->FindElement(
"bias") ) {
83 bias = element->FindElementValueAsNumber(
"bias");
85 if ( element->FindElement(
"gain") ) {
86 gain = element->FindElementValueAsNumber(
"gain");
88 if ( element->FindElement(
"drift_rate") ) {
89 drift_rate = element->FindElementValueAsNumber(
"drift_rate");
91 if ( element->FindElement(
"lag") ) {
92 lag = element->FindElementValueAsNumber(
"lag");
93 double denom = 2.00 + dt*lag;
95 cb = (2.00 - dt*lag) / denom;
97 if ( element->FindElement(
"noise") ) {
98 noise_variance = element->FindElementValueAsNumber(
"noise");
99 string variation = element->FindElement(
"noise")->GetAttributeValue(
"variation");
100 if (variation ==
"PERCENT") {
101 NoiseType = ePercent;
102 }
else if (variation ==
"ABSOLUTE") {
103 NoiseType = eAbsolute;
105 NoiseType = ePercent;
106 FGLogging log(LogLevel::ERROR);
107 log <<
"Unknown noise type in sensor: " << Name
108 <<
"\n defaulting to PERCENT.\n";
110 string distribution = element->FindElement(
"noise")->GetAttributeValue(
"distribution");
111 if (distribution ==
"UNIFORM") {
112 DistributionType = eUniform;
113 }
else if (distribution ==
"GAUSSIAN") {
114 DistributionType = eGaussian;
116 DistributionType = eUniform;
117 FGLogging log(LogLevel::ERROR);
118 log <<
"Unknown random distribution type in sensor: " << Name
119 <<
"\n defaulting to UNIFORM.\n";
123 bind(element, fcs->GetPropertyManager().get());
137void FGSensor::ResetPastStates(
void)
139 FGFCSComponent::ResetPastStates();
141 PreviousOutput = PreviousInput = Output = 0.0;
146bool FGSensor::Run(
void)
148 Input = InputNodes[0]->getDoubleValue();
150 ProcessSensorSignal();
159void FGSensor::ProcessSensorSignal(
void)
166 if (lag != 0.0) Lag();
167 if (noise_variance != 0.0) Noise();
168 if (drift_rate != 0.0) Drift();
169 if (gain != 0.0) Gain();
170 if (bias != 0.0) Bias();
172 if (delay != 0) Delay();
174 if (fail_low) Output = -HUGE_VAL;
175 if (fail_high) Output = HUGE_VAL;
177 if (bits != 0) Quantize();
185void FGSensor::Noise(
void)
187 double random_value=0.0;
189 if (DistributionType == eUniform)
190 random_value = generator->GetUniformRandomNumber();
192 random_value = generator->GetNormalRandomNumber();
194 switch( NoiseType ) {
196 Output *= (1.0 + noise_variance*random_value);
200 Output += noise_variance*random_value;
207void FGSensor::Bias(
void)
214void FGSensor::Gain(
void)
221void FGSensor::Drift(
void)
223 drift += drift_rate*dt;
229void FGSensor::Quantize(
void)
231 if (Output < min) Output = min;
232 if (Output > max) Output = max;
233 double portion = Output - min;
234 quantized = (int)(portion/granularity);
235 Output = quantized*granularity + min;
240void FGSensor::Lag(
void)
243 Output = ca * (Output + PreviousInput) + PreviousOutput * cb;
245 PreviousOutput = Output;
246 PreviousInput = Input;
251void FGSensor::bind(Element* el, FGPropertyManager* PropertyManager)
255 FGFCSComponent::bind(el, PropertyManager);
257 if (Name.find(
"/") == string::npos) {
258 tmp =
"fcs/" + PropertyManager->mkPropertyName(Name,
true);
260 const string tmp_low = tmp +
"/malfunction/fail_low";
261 const string tmp_high = tmp +
"/malfunction/fail_high";
262 const string tmp_stuck = tmp +
"/malfunction/fail_stuck";
263 const string tmp_randomseed = tmp +
"/randomseed";
265 PropertyManager->Tie( tmp_low,
this, &FGSensor::GetFailLow, &FGSensor::SetFailLow);
266 PropertyManager->Tie( tmp_high,
this, &FGSensor::GetFailHigh, &FGSensor::SetFailHigh);
267 PropertyManager->Tie( tmp_stuck,
this, &FGSensor::GetFailStuck, &FGSensor::SetFailStuck);
268 PropertyManager->Tie( tmp_randomseed,
this, &FGSensor::GetNoiseRandomSeed, &FGSensor::SetNoiseRandomSeed);
270 if (!quant_property.empty()) {
271 if (quant_property.find(
"/") == string::npos) {
272 string qprop =
"fcs/" + PropertyManager->mkPropertyName(quant_property,
true);
275 XMLLogException err(el);
276 err <<
"Property " << tmp <<
" has already been successfully bound (late).\n";
280 PropertyManager->Tie(qprop,
this, &FGSensor::GetQuantized);
289void FGSensor::SetNoiseRandomSeed(
int sr)
292 generator = std::make_shared<RandomNumberGenerator>(*RandomSeed);
295int FGSensor::GetNoiseRandomSeed(
void)
const
300 return fcs->GetExec()->SRand();
322void FGSensor::Debug(
int from)
324 if (debug_lvl <= 0)
return;
327 FGLogging log(LogLevel::DEBUG);
329 if (!InputNodes.empty())
330 log <<
" INPUT: " << InputNodes[0]->GetNameWithSign() << fixed
331 << setprecision(4) <<
"\n";
333 if (quant_property.empty())
334 log <<
" Quantized output\n";
336 log <<
" Quantized output (property: " << quant_property <<
")\n";
338 log <<
" Bits: " << bits <<
"\n";
339 log <<
" Min value: " << min <<
"\n";
340 log <<
" Max value: " << max <<
"\n";
341 log <<
" (span: " << span <<
", granularity: " << granularity <<
")\n";
343 if (bias != 0.0) log <<
" Bias: " << bias <<
" \n";
344 if (gain != 0.0) log <<
" Gain: " << gain <<
" \n";
345 if (drift_rate != 0) log <<
" Sensor drift rate: " << drift_rate <<
" \n";
346 if (lag != 0) log <<
" Sensor lag: " << lag <<
" \n";
347 if (noise_variance != 0) {
348 if (NoiseType == eAbsolute) {
349 log <<
" Noise variance (absolute): " << noise_variance <<
" \n";
350 }
else if (NoiseType == ePercent) {
351 log <<
" Noise variance (percent): " << noise_variance <<
" \n";
353 log <<
" Noise variance type is invalid\n";
355 if (DistributionType == eUniform) {
356 log <<
" Random noise is uniformly distributed.\n";
357 }
else if (DistributionType == eGaussian) {
358 log <<
" Random noise is gaussian distributed.\n";
361 for (
auto node: OutputNodes)
362 log <<
" OUTPUT: " << node->getNameString() <<
"\n";
365 if (debug_lvl & 2 ) {
366 FGLogging log(LogLevel::DEBUG);
367 if (from == 0) log <<
"Instantiated: FGSensor\n";
368 if (from == 1) log <<
"Destroyed: FGSensor\n";
370 if (debug_lvl & 4 ) {
372 if (debug_lvl & 8 ) {
374 if (debug_lvl & 16) {
376 if (debug_lvl & 64) {
A node in a property tree.
bool isTied() const
Test whether this node is bound to an external data source.
Main namespace for the JSBSim Flight Dynamics Model.