1 /*
2 * Copyright (C) 2020 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.navigation.inertial.calibration.noise;
17
18 import com.irurueta.navigation.LockedException;
19 import com.irurueta.navigation.inertial.BodyKinematics;
20 import com.irurueta.navigation.inertial.calibration.AccelerationTriad;
21 import com.irurueta.navigation.inertial.calibration.AccelerometerNoiseRootPsdSource;
22 import com.irurueta.navigation.inertial.calibration.AngularSpeedTriad;
23 import com.irurueta.navigation.inertial.calibration.GyroscopeNoiseRootPsdSource;
24 import com.irurueta.navigation.inertial.calibration.TimeIntervalEstimator;
25 import com.irurueta.units.Acceleration;
26 import com.irurueta.units.AccelerationUnit;
27 import com.irurueta.units.AngularSpeed;
28 import com.irurueta.units.AngularSpeedUnit;
29 import com.irurueta.units.Time;
30 import com.irurueta.units.TimeConverter;
31 import com.irurueta.units.TimeUnit;
32
33 import java.util.LinkedList;
34
35 /**
36 * Estimates accelerometer and angular speed noise variances and PSD's
37 * (Power Spectral Densities) along with their average values for a windowed
38 * amount of samples.
39 * This estimator must be used when the body where the accelerometer and
40 * gyroscope are attached remains static on the same position with zero
41 * velocity and constant (or zero) angular speed while capturing data.
42 * To compute PSD's, this estimator assumes that measurement samples are obtained
43 * at a constant provided rate equal to {@link #getTimeInterval()} seconds.
44 * If not available, sampling rate average can be estimated using
45 * {@link TimeIntervalEstimator}.
46 * This estimator does NOT require the knowledge of current location and body
47 * orientation.
48 * Because body location and orientation is not known, estimated average values
49 * cannot be used to determine biases. Only norm of noise estimations
50 * (variance or standard deviation) can be safely used.
51 */
52 @SuppressWarnings("DuplicatedCode")
53 public class WindowedBodyKinematicsNoiseEstimator implements AccelerometerNoiseRootPsdSource,
54 GyroscopeNoiseRootPsdSource {
55 /**
56 * Number of samples to keep within the window by default.
57 * For an accelerometer generating 100 samples/second, this is equivalent to
58 * 1 second.
59 * For an accelerometer generating 50 samples/second, this is equivalent to
60 * 2 seconds.
61 */
62 public static final int DEFAULT_WINDOW_SIZE = WindowedTriadNoiseEstimator.DEFAULT_WINDOW_SIZE;
63
64 /**
65 * Minimum allowed window size.
66 */
67 public static final int MIN_WINDOW_SIZE = WindowedTriadNoiseEstimator.MIN_WINDOW_SIZE;
68
69 /**
70 * Default time interval between accelerometer samples expressed in seconds
71 * (s).
72 */
73 public static final double DEFAULT_TIME_INTERVAL_SECONDS =
74 WindowedTriadNoiseEstimator.DEFAULT_TIME_INTERVAL_SECONDS;
75
76 /**
77 * Length of number of samples to keep within the window being processed.
78 * Window size must always be larger than allowed minimum value.
79 */
80 private int windowSize = DEFAULT_WINDOW_SIZE;
81
82 /**
83 * Time interval expressed in seconds (s) between consecutive accelerometer
84 * samples.
85 */
86 private double timeInterval = DEFAULT_TIME_INTERVAL_SECONDS;
87
88 /**
89 * Keeps the list of body kinematics samples that remain within the window.
90 */
91 private final LinkedList<BodyKinematics> windowedSamples = new LinkedList<>();
92
93 /**
94 * Listener to handle events raised by this estimator.
95 */
96 private WindowedBodyKinematicsNoiseEstimatorListener listener;
97
98 /**
99 * Estimated average of x coordinate of specific force expressed in
100 * meters per squared second (m/s^2).
101 */
102 private double avgSpecificForceX;
103
104 /**
105 * Estimated average of y coordinate of specific force expressed in
106 * meters per squared second (m/s^2).
107 */
108 private double avgSpecificForceY;
109
110 /**
111 * Estimated average of z coordinate of specific force expressed in
112 * meters per squared second (m/s^2).
113 */
114 private double avgSpecificForceZ;
115
116 /**
117 * Estimated average of x coordinate of angular rate expressed in
118 * radians per second (rad/s).
119 */
120 private double avgAngularRateX;
121
122 /**
123 * Estimated average of y coordinate of angular rate expressed in
124 * radians per second (rad/s).
125 */
126 private double avgAngularRateY;
127
128 /**
129 * Estimated average of z coordinate of angular rate expressed in
130 * radians per second (rad/s).
131 */
132 private double avgAngularRateZ;
133
134 /**
135 * Estimated variance of x coordinate of specific force expressed
136 * in (m^2/s^4).
137 */
138 private double varianceSpecificForceX;
139
140 /**
141 * Estimated variance of y coordinate of specific force expressed
142 * in (m^2/s^4).
143 */
144 private double varianceSpecificForceY;
145
146 /**
147 * Estimated variance of z coordinate of specific force expressed
148 * in (m^2/s^4).
149 */
150 private double varianceSpecificForceZ;
151
152 /**
153 * Estimated variance of x coordinate of angular rate expressed
154 * in (rad^2/s^2).
155 */
156 private double varianceAngularRateX;
157
158 /**
159 * Estimated variance of y coordinate of angular rate expressed
160 * in (rad^2/s^2).
161 */
162 private double varianceAngularRateY;
163
164 /**
165 * Estimated variance of z coordinate of angular rate expressed
166 * in (rad^2/s^2).
167 */
168 private double varianceAngularRateZ;
169
170 /**
171 * Number of processed acceleration triad samples.
172 */
173 private int numberOfProcessedSamples;
174
175 /**
176 * Indicates whether estimator is running or not.
177 */
178 private boolean running;
179
180 /**
181 * Constructor.
182 */
183 public WindowedBodyKinematicsNoiseEstimator() {
184 }
185
186 /**
187 * Constructor.
188 *
189 * @param listener listener to handle events raised by this estimator.
190 */
191 public WindowedBodyKinematicsNoiseEstimator(final WindowedBodyKinematicsNoiseEstimatorListener listener) {
192 this.listener = listener;
193 }
194
195 /**
196 * Gets length of number of samples to keep within the window being processed.
197 * Window size must always be larger than allowed minimum value.
198 *
199 * @return length of number of samples to keep within the window.
200 */
201 public int getWindowSize() {
202 return windowSize;
203 }
204
205 /**
206 * Sets length of number of samples to keep within the window being processed.
207 * Window size must always be larger than allowed minimum value.
208 * When window size is modified, instance state is reset.
209 *
210 * @param windowSize length of number of samples to keep within the window.
211 * @throws IllegalArgumentException if provided value is not valid.
212 * @throws LockedException if estimator is currently running.
213 */
214 public void setWindowSize(final int windowSize) throws LockedException {
215 if (running) {
216 throw new LockedException();
217 }
218
219 // check that window is larger than minimum allowed value
220 if (windowSize < MIN_WINDOW_SIZE) {
221 throw new IllegalArgumentException();
222 }
223
224 this.windowSize = windowSize;
225 reset();
226 }
227
228 /**
229 * Gets time interval between body kinematics samples expressed in
230 * seconds (s).
231 *
232 * @return time interval between accelerometer triad samples.
233 */
234 public double getTimeInterval() {
235 return timeInterval;
236 }
237
238 /**
239 * Sets time interval between body kinematics samples expressed in
240 * seconds (s).
241 *
242 * @param timeInterval time interval between accelerometer triad samples.
243 * @throws IllegalArgumentException if provided value is negative.
244 * @throws LockedException if estimator is currently running.
245 */
246 public void setTimeInterval(final double timeInterval) throws LockedException {
247 if (running) {
248 throw new LockedException();
249 }
250
251 if (timeInterval < 0.0) {
252 throw new IllegalArgumentException();
253 }
254
255 this.timeInterval = timeInterval;
256 }
257
258 /**
259 * Gets time interval between body kinematics samples.
260 *
261 * @return time interval between accelerometer triad samples.
262 */
263 public Time getTimeIntervalAsTime() {
264 return new Time(timeInterval, TimeUnit.SECOND);
265 }
266
267 /**
268 * Gets time interval between body kinematics samples.
269 *
270 * @param result instance where time interval will be stored.
271 */
272 public void getTimeIntervalAsTime(final Time result) {
273 result.setValue(timeInterval);
274 result.setUnit(TimeUnit.SECOND);
275 }
276
277 /**
278 * Sets time interval between body kinematics samples.
279 *
280 * @param timeInterval time interval between accelerometer triad samples.
281 * @throws LockedException if estimator is currently running.
282 */
283 public void setTimeInterval(final Time timeInterval) throws LockedException {
284 setTimeInterval(TimeConverter.convert(timeInterval.getValue().doubleValue(), timeInterval.getUnit(),
285 TimeUnit.SECOND));
286 }
287
288 /**
289 * Gets listener to handle events raised by this estimator.
290 *
291 * @return listener to handle events raised by this estimator.
292 */
293 public WindowedBodyKinematicsNoiseEstimatorListener getListener() {
294 return listener;
295 }
296
297 /**
298 * Sets listener to handle events raised by this estimator.
299 *
300 * @param listener listener to handle events raised by this estimator.
301 * @throws LockedException if this estimator is running.
302 */
303 public void setListener(final WindowedBodyKinematicsNoiseEstimatorListener listener) throws LockedException {
304 if (running) {
305 throw new LockedException();
306 }
307
308 this.listener = listener;
309 }
310
311 /**
312 * Gets first provided body kinematics within the window.
313 *
314 * @return first provided body kinematics within the window or null if not
315 * available.
316 */
317 public BodyKinematics getFirstWindowedBodyKinematics() {
318 return windowedSamples.isEmpty() ? null : windowedSamples.getFirst();
319 }
320
321 /**
322 * Gets first provided body kinematics within the window.
323 *
324 * @param result instance where first provided body kinematics will be stored.
325 * @return true if result instance was updated, false otherwise.
326 */
327 public boolean getFirstWindowedBodyKinematics(final BodyKinematics result) {
328 if (windowedSamples.isEmpty()) {
329 return false;
330 } else {
331 result.copyFrom(windowedSamples.getFirst());
332 return true;
333 }
334 }
335
336 /**
337 * Gets last provided body kinematics within the window.
338 *
339 * @return last provided body kinematics within the window or null if not
340 * available.
341 */
342 public BodyKinematics getLastWindowedBodyKinematics() {
343 return windowedSamples.isEmpty() ? null : windowedSamples.getLast();
344 }
345
346 /**
347 * Gets last provided body kinematics within the window.
348 *
349 * @param result instance where last provided body kinematics will be stored.
350 * @return true if result instance was updated, false otherwise.
351 */
352 public boolean getLastWindowedBodyKinematics(final BodyKinematics result) {
353 if (windowedSamples.isEmpty()) {
354 return false;
355 } else {
356 result.copyFrom(windowedSamples.getLast());
357 return true;
358 }
359 }
360
361 /**
362 * Gets estimated average of x coordinate of accelerometer sensed specific force
363 * expressed in meters per squared second (m/s^2).
364 * This value will depend of body location and orientation, hence it should never
365 * be used as a calibration bias.
366 *
367 * @return average of x coordinate of sensed specific force.
368 */
369 public double getAvgSpecificForceX() {
370 return avgSpecificForceX;
371 }
372
373 /**
374 * Gets estimated average of x coordinate of accelerometer sensed specific force.
375 * This value will depend of body location and orientation, hence it should never
376 * be used as a calibration bias.
377 *
378 * @return average of x coordinate of sensed specific force.
379 */
380 public Acceleration getAvgSpecificForceXAsMeasurement() {
381 return new Acceleration(avgSpecificForceX, AccelerationUnit.METERS_PER_SQUARED_SECOND);
382 }
383
384 /**
385 * Gets estimated average of x coordinate of accelerometer sensed specific force.
386 * This value will depend of body location and orientation, hence it should never
387 * be used as a calibration bias.
388 *
389 * @param result instance where average of x coordinate of sensed specific force
390 * will be stored.
391 */
392 public void getAvgSpecificForceXAsMeasurement(final Acceleration result) {
393 result.setValue(avgSpecificForceX);
394 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
395 }
396
397 /**
398 * Gets estimated average of y coordinate of accelerometer sensed specific force
399 * expressed in meters per squared second (m/s^2).
400 * This value will depend of body location and orientation, hence it should never
401 * be used as a calibration bias.
402 *
403 * @return average of y coordinate of sensed specific force.
404 */
405 public double getAvgSpecificForceY() {
406 return avgSpecificForceY;
407 }
408
409 /**
410 * Gets estimated average of y coordinate of accelerometer sensed specific force.
411 * This value will depend of body location and orientation, hence it should never
412 * be used as a calibration bias.
413 *
414 * @return average of y coordinate of sensed specific force.
415 */
416 public Acceleration getAvgSpecificForceYAsMeasurement() {
417 return new Acceleration(avgSpecificForceY, AccelerationUnit.METERS_PER_SQUARED_SECOND);
418 }
419
420 /**
421 * Gets estimated average of y coordinate of accelerometer sensed specific force.
422 * This value will depend of body location and orientation, hence it should never
423 * be used as a calibration bias.
424 *
425 * @param result instance where average of y coordinate of sensed specific force
426 * will be stored.
427 */
428 public void getAvgSpecificForceYAsMeasurement(final Acceleration result) {
429 result.setValue(avgSpecificForceY);
430 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
431 }
432
433 /**
434 * Gets estimated average of z coordinate of accelerometer sensed specific force
435 * expressed in meters per squared second (m/s^2).
436 * This value will depend of body location and orientation, hence it should never
437 * be used as a calibration bias.
438 *
439 * @return average of z coordinate of sensed specific force.
440 */
441 public double getAvgSpecificForceZ() {
442 return avgSpecificForceZ;
443 }
444
445 /**
446 * Gets estimated average of z coordinate of accelerometer sensed specific force.
447 * This value will depend of body location and orientation, hence it should never
448 * be used as a calibration bias.
449 *
450 * @return average of z coordinate of sensed specific force.
451 */
452 public Acceleration getAvgSpecificForceZAsMeasurement() {
453 return new Acceleration(avgSpecificForceZ, AccelerationUnit.METERS_PER_SQUARED_SECOND);
454 }
455
456 /**
457 * Gets estimated average of z coordinate of accelerometer sensed specific force.
458 * This value will depend of body location and orientation, hence it should never
459 * be used as a calibration bias.
460 *
461 * @param result instance where average of z coordinate of sensed specific force
462 * will be stored.
463 */
464 public void getAvgSpecificForceZAsMeasurement(final Acceleration result) {
465 result.setValue(avgSpecificForceZ);
466 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
467 }
468
469 /**
470 * Gets estimated average of accelerometer sensed specific force as a measurement
471 * triad.
472 *
473 * @return average accelerometer triad.
474 */
475 public AccelerationTriad getAvgSpecificForceAsTriad() {
476 return new AccelerationTriad(AccelerationUnit.METERS_PER_SQUARED_SECOND,
477 avgSpecificForceX, avgSpecificForceY, avgSpecificForceZ);
478 }
479
480 /**
481 * Gets estimated average of accelerometer sensed specific force as a measurement
482 * triad.
483 *
484 * @param result instance where average accelerometer triad will be stored.
485 */
486 public void getAvgSpecificForceAsTriad(final AccelerationTriad result) {
487 result.setValueCoordinatesAndUnit(avgSpecificForceX, avgSpecificForceY, avgSpecificForceZ,
488 AccelerationUnit.METERS_PER_SQUARED_SECOND);
489 }
490
491 /**
492 * Gets norm of estimated average acceleration expressed in meters per squared
493 * second (m/s^2). This value is independent of body orientation.
494 *
495 * @return norm of estimated average acceleration.
496 */
497 public double getAvgSpecificForceNorm() {
498 return Math.sqrt(avgSpecificForceX * avgSpecificForceX + avgSpecificForceY * avgSpecificForceY
499 + avgSpecificForceZ * avgSpecificForceZ);
500 }
501
502 /**
503 * Gets norm of estimated average acceleration within current window.
504 *
505 * @return norm of estimated average acceleration.
506 */
507 public Acceleration getAvgSpecificForceNormAsMeasurement() {
508 return new Acceleration(getAvgSpecificForceNorm(), AccelerationUnit.METERS_PER_SQUARED_SECOND);
509 }
510
511 /**
512 * Gets norm of estimated average acceleration.
513 *
514 * @param result instance where norm of estimated average acceleration will be stored.
515 */
516 public void getAvgSpecificForceNormAsMeasurement(final Acceleration result) {
517 result.setValue(getAvgSpecificForceNorm());
518 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
519 }
520
521 /**
522 * Gets estimated average of x coordinate of gyroscope sensed angular rate
523 * expressed in radians per second (rad/s).
524 * This value will depend of body location and orientation, hence it should
525 * never be used as a calibration bias.
526 *
527 * @return average of x coordinate of sensed angular rate.
528 */
529 public double getAvgAngularRateX() {
530 return avgAngularRateX;
531 }
532
533 /**
534 * Gets estimated average of x coordinate of gyroscope sensed angular rate.
535 * This value will depend of body location and orientation, hence it should never
536 * be used as a calibration bias.
537 *
538 * @return average of x coordinate of sensed angular rate.
539 */
540 public AngularSpeed getAvgAngularRateXAsMeasurement() {
541 return new AngularSpeed(avgAngularRateX, AngularSpeedUnit.RADIANS_PER_SECOND);
542 }
543
544 /**
545 * Gets estimated average of x coordinate of gyroscope sensed angular rate.
546 * This value will depend of body location and orientation, hence it should never
547 * be used as a calibration bias.
548 *
549 * @param result instance where average of x coordinate of sensed angular rate
550 * will be stored.
551 */
552 public void getAvgAngularRateXAsMeasurement(final AngularSpeed result) {
553 result.setValue(avgAngularRateX);
554 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
555 }
556
557 /**
558 * Gets estimated average of y coordinate of gyroscope sensed angular rate
559 * expressed in radians per second (rad/s).
560 * This value will depend of body location and orientation, hence it should never
561 * be used as a calibration bias.
562 *
563 * @return average of y coordinate of sensed angular rate.
564 */
565 public double getAvgAngularRateY() {
566 return avgAngularRateY;
567 }
568
569 /**
570 * Gets estimated average of y coordinate of gyroscope sensed angular rate.
571 * This value will depend of body location and orientation, hence it should never
572 * be used as a calibration bias.
573 *
574 * @return average of y coordinate of sensed angular rate.
575 */
576 public AngularSpeed getAvgAngularRateYAsMeasurement() {
577 return new AngularSpeed(avgAngularRateY, AngularSpeedUnit.RADIANS_PER_SECOND);
578 }
579
580 /**
581 * Gets estimated average of y coordinate of gyroscope sensed angular rate.
582 * This value will depend of body location and orientation, hence it should never
583 * be used as a calibration bias.
584 *
585 * @param result instance where average of y coordinate of sensed angular rate
586 * will be stored.
587 */
588 public void getAvgAngularRateYAsMeasurement(final AngularSpeed result) {
589 result.setValue(avgAngularRateY);
590 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
591 }
592
593 /**
594 * Gets estimated average of z coordinate of gyroscope sensed angular rate
595 * expressed in radians per second (rad/s).
596 * This value will depend of body location and orientation, hence it should never
597 * be used as a calibration bias.
598 *
599 * @return average of z coordinate of sensed angular rate.
600 */
601 public double getAvgAngularRateZ() {
602 return avgAngularRateZ;
603 }
604
605 /**
606 * Gets estimated average of z coordinate of gyroscope sensed angular rate.
607 * This value will depend of body location and orientation, hence it should never
608 * be used as a calibration bias.
609 *
610 * @return average of z coordinate of sensed angular rate.
611 */
612 public AngularSpeed getAvgAngularRateZAsMeasurement() {
613 return new AngularSpeed(avgAngularRateZ, AngularSpeedUnit.RADIANS_PER_SECOND);
614 }
615
616 /**
617 * Gets estimated average of z coordinate of gyroscope sensed angular rate.
618 * This value will depend of body location and orientation, hence it should never
619 * be used as a calibration bias.
620 *
621 * @param result instance where average of z coordinate of sensed angular rate
622 * will be stored.
623 */
624 public void getAvgAngularRateZAsMeasurement(final AngularSpeed result) {
625 result.setValue(avgAngularRateZ);
626 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
627 }
628
629 /**
630 * Gets estimated average of gyroscope sensed angular speed as a measurement
631 * triad.
632 *
633 * @return average angular speed triad.
634 */
635 public AngularSpeedTriad getAvgAngularRateTriad() {
636 return new AngularSpeedTriad(AngularSpeedUnit.RADIANS_PER_SECOND,
637 avgAngularRateX, avgAngularRateY, avgAngularRateZ);
638 }
639
640 /**
641 * Gets estimated average of gyroscope sensed angular speed as a measurement
642 * triad.
643 *
644 * @param result instance where average angular speed triad will be stored.
645 */
646 public void getAvgAngularRateTriad(final AngularSpeedTriad result) {
647 result.setValueCoordinatesAndUnit(avgAngularRateX, avgAngularRateY, avgAngularRateZ,
648 AngularSpeedUnit.RADIANS_PER_SECOND);
649 }
650
651 /**
652 * Gets norm of estimated average angular speed expressed in radians per
653 * second (rad/s). This value is independent of body orientation.
654 *
655 * @return norm of estimated average angular speed.
656 */
657 public double getAvgAngularRateNorm() {
658 return Math.sqrt(avgAngularRateX * avgAngularRateX
659 + avgAngularRateY * avgAngularRateY
660 + avgAngularRateZ * avgAngularRateZ);
661 }
662
663 /**
664 * Gets norm of estimated average angular speed.
665 * This value is independent of body orientation.
666 *
667 * @return norm of estimated average angular speed.
668 */
669 public AngularSpeed getAvgAngularRateNormAsMeasurement() {
670 return new AngularSpeed(getAvgAngularRateNorm(), AngularSpeedUnit.RADIANS_PER_SECOND);
671 }
672
673 /**
674 * Gets norm of estimated average angular speed.
675 * This value is independent of body orientation.
676 *
677 * @param result instance where norm of estimated average angular speed will be stored.
678 */
679 public void getAvgAngularRateNormAsMeasurement(final AngularSpeed result) {
680 result.setValue(getAvgAngularRateNorm());
681 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
682 }
683
684 /**
685 * Gets estimated average of body kinematics.
686 *
687 * @return estimated average of body kinematics.
688 */
689 public BodyKinematics getAvgBodyKinematics() {
690 final var result = new BodyKinematics();
691 getAvgBodyKinematics(result);
692 return result;
693 }
694
695 /**
696 * Gets estimated average of body kinematics.
697 *
698 * @param result instance where estimated average of body kinematics will be stored.
699 */
700 public void getAvgBodyKinematics(final BodyKinematics result) {
701 result.setSpecificForceCoordinates(getAvgSpecificForceX(), getAvgSpecificForceY(), getAvgSpecificForceZ());
702 result.setAngularRateCoordinates(getAvgAngularRateX(), getAvgAngularRateY(), getAvgAngularRateZ());
703 }
704
705 /**
706 * Gets estimated variance of x coordinate of accelerometer sensed specific force
707 * expressed in (m^2/s^4).
708 *
709 * @return estimated variance of x coordinate of sensed specific force.
710 */
711 public double getVarianceSpecificForceX() {
712 return varianceSpecificForceX;
713 }
714
715 /**
716 * Gets estimated variance of y coordinate of accelerometer sensed specific
717 * force expressed in (m^2/s^4).
718 *
719 * @return estimated variance of y coordinate of sensed specific force.
720 */
721 public double getVarianceSpecificForceY() {
722 return varianceSpecificForceY;
723 }
724
725 /**
726 * Gets estimated variance of z coordinate of accelerometer sensed specific
727 * force expressed in (m^2/s^4).
728 *
729 * @return estimated variance of z coordinate of sensed specific force.
730 */
731 public double getVarianceSpecificForceZ() {
732 return varianceSpecificForceZ;
733 }
734
735 /**
736 * Gets estimated variance of x coordinate of gyroscope sensed angular rate
737 * expressed in (rad^2/s^2).
738 *
739 * @return estimated variance of x coordinate of sensed angular rate.
740 */
741 public double getVarianceAngularRateX() {
742 return varianceAngularRateX;
743 }
744
745 /**
746 * Gets estimated variance of y coordinate of gyroscope sensed angular rate
747 * expressed in (rad^2/s^2).
748 *
749 * @return estimated variance of y coordinate of sensed angular rate.
750 */
751 public double getVarianceAngularRateY() {
752 return varianceAngularRateY;
753 }
754
755 /**
756 * Gets estimated variance of z coordinate of gyroscope sensed angular rate
757 * expressed in (rad^2/s^2).
758 *
759 * @return estimated variance of z coordinate of sensed angular rate.
760 */
761 public double getVarianceAngularRateZ() {
762 return varianceAngularRateZ;
763 }
764
765 /**
766 * Gets estimated standard deviation of x coordinate of accelerometer
767 * sensed specific force expressed in meters per squared second (m/s^2).
768 *
769 * @return estimated standard deviation of x coordinate of sensed specific
770 * force.
771 */
772 public double getStandardDeviationSpecificForceX() {
773 return Math.sqrt(varianceSpecificForceX);
774 }
775
776 /**
777 * Gets estimated standard deviation of x coordinate of accelerometer
778 * sensed specific force.
779 *
780 * @return estimated standard deviation of x coordinate of sensed specific
781 * force.
782 */
783 public Acceleration getStandardDeviationSpecificForceXAsMeasurement() {
784 return new Acceleration(getStandardDeviationSpecificForceX(), AccelerationUnit.METERS_PER_SQUARED_SECOND);
785 }
786
787 /**
788 * Gets estimated standard deviation of x coordinate of accelerometer
789 * sensed specific force.
790 *
791 * @param result instance where estimated standard deviation of x
792 * coordinate of sensed specific force will be stored.
793 */
794 public void getStandardDeviationSpecificForceXAsMeasurement(final Acceleration result) {
795 result.setValue(getStandardDeviationSpecificForceX());
796 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
797 }
798
799 /**
800 * Gets estimated standard deviation of y coordinate of accelerometer
801 * sensed specific force expressed in meters per squared second (m/s^2).
802 *
803 * @return estimated standard deviation of y coordinate of sensed specific
804 * force.
805 */
806 public double getStandardDeviationSpecificForceY() {
807 return Math.sqrt(varianceSpecificForceY);
808 }
809
810 /**
811 * Gets estimated standard deviation of y coordinate of accelerometer
812 * sensed specific force.
813 *
814 * @return estimated standard deviation of y coordinate of sensed specific
815 * force.
816 */
817 public Acceleration getStandardDeviationSpecificForceYAsMeasurement() {
818 return new Acceleration(getStandardDeviationSpecificForceY(), AccelerationUnit.METERS_PER_SQUARED_SECOND);
819 }
820
821 /**
822 * Gets estimated standard deviation of y coordinate of accelerometer
823 * sensed specific force.
824 *
825 * @param result instance where estimated standard deviation of y
826 * coordinate of sensed specific force will be stored.
827 */
828 public void getStandardDeviationSpecificForceYAsMeasurement(final Acceleration result) {
829 result.setValue(getStandardDeviationSpecificForceY());
830 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
831 }
832
833 /**
834 * Gets estimated standard deviation of z coordinate of accelerometer
835 * sensed specific force expressed in meters per squared second (m/s^2).
836 *
837 * @return estimated standard deviation of z coordinate of sensed specific
838 * force.
839 */
840 public double getStandardDeviationSpecificForceZ() {
841 return Math.sqrt(varianceSpecificForceZ);
842 }
843
844 /**
845 * Gets estimated standard deviation of z coordinate of accelerometer
846 * sensed specific force.
847 *
848 * @return estimated standard deviation of z coordinate of sensed specific
849 * force.
850 */
851 public Acceleration getStandardDeviationSpecificForceZAsMeasurement() {
852 return new Acceleration(getStandardDeviationSpecificForceZ(), AccelerationUnit.METERS_PER_SQUARED_SECOND);
853 }
854
855 /**
856 * Gets estimated standard deviation of z coordinate of accelerometer
857 * sensed specific force.
858 *
859 * @param result instance where estimated standard deviation of z
860 * coordinate of sensed specific force will be stored.
861 */
862 public void getStandardDeviationSpecificForceZAsMeasurement(final Acceleration result) {
863 result.setValue(getStandardDeviationSpecificForceZ());
864 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
865 }
866
867 /**
868 * Gets estimated standard deviation triad of accelerometer measurements.
869 *
870 * @return estimated standard deviation triad of accelerometer measurements.
871 */
872 public AccelerationTriad getStandardDeviationSpecificForceTriad() {
873 return new AccelerationTriad(AccelerationUnit.METERS_PER_SQUARED_SECOND,
874 getStandardDeviationSpecificForceX(),
875 getStandardDeviationSpecificForceY(),
876 getStandardDeviationSpecificForceZ());
877 }
878
879 /**
880 * Gets estimated standard deviation triad of accelerometer measurements.
881 *
882 * @param result instance where estimated standard deviation triad of
883 * accelerometer measurements will be stored.
884 */
885 public void getStandardDeviationSpecificForceTriad(final AccelerationTriad result) {
886 result.setValueCoordinatesAndUnit(getStandardDeviationSpecificForceX(),
887 getStandardDeviationSpecificForceY(),
888 getStandardDeviationSpecificForceZ(),
889 AccelerationUnit.METERS_PER_SQUARED_SECOND);
890 }
891
892 /**
893 * Gets norm of estimated standard deviation of accelerometer measurements
894 * expressed in meters per squared second (m/s^2).
895 *
896 * @return norm of estimated standard deviation of accelerometer
897 * measurements.
898 */
899 public double getStandardDeviationSpecificForceNorm() {
900 final var fx = getStandardDeviationSpecificForceX();
901 final var fy = getStandardDeviationSpecificForceY();
902 final var fz = getStandardDeviationSpecificForceZ();
903 return Math.sqrt(fx * fx + fy * fy + fz * fz);
904 }
905
906 /**
907 * Gets norm of estimated standard deviation of accelerometer measurements.
908 *
909 * @return norm of estimated standard deviation of measurements.
910 */
911 public Acceleration getStandardDeviationSpecificForceNormAsMeasurement() {
912 return new Acceleration(getStandardDeviationSpecificForceNorm(), AccelerationUnit.METERS_PER_SQUARED_SECOND);
913 }
914
915 /**
916 * Gets norm of estimated standard deviation of accelerometer measurements.
917 *
918 * @param result instance where norm of estimated standard deviation will be
919 * stored.
920 */
921 public void getStandardDeviationSpecificForceNormAsMeasurement(final Acceleration result) {
922 result.setValue(getStandardDeviationSpecificForceNorm());
923 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
924 }
925
926 /**
927 * Gets average of estimated standard deviation coordinates of accelerometer
928 * measurements expressed in meters per squared second (m/s^2).
929 *
930 * @return average of estimated standard deviation coordinates.
931 */
932 public double getAverageStandardDeviationSpecificForce() {
933 final var fx = getStandardDeviationSpecificForceX();
934 final var fy = getStandardDeviationSpecificForceY();
935 final var fz = getStandardDeviationSpecificForceZ();
936 return (fx + fy + fz) / 3.0;
937 }
938
939 /**
940 * Gets average of estimated standard deviation coordinates of accelerometer
941 * measurements.
942 *
943 * @return average of estimated standard deviation coordinates.
944 */
945 public Acceleration getAverageStandardDeviationSpecificForceAsMeasurement() {
946 return new Acceleration(getAverageStandardDeviationSpecificForce(), AccelerationUnit.METERS_PER_SQUARED_SECOND);
947 }
948
949 /**
950 * Gets average of estimated standard deviation coordinates of accelerometer
951 * measurements.
952 *
953 * @param result instance where average of estimated standard deviation coordinates
954 * will be stored.
955 */
956 public void getAverageStandardDeviationSpecificForceAsMeasurement(final Acceleration result) {
957 result.setValue(getAverageStandardDeviationSpecificForce());
958 result.setUnit(AccelerationUnit.METERS_PER_SQUARED_SECOND);
959 }
960
961 /**
962 * Gets estimated standard deviation of x coordinate of gyroscope
963 * expressed in radians per second (rad/s).
964 *
965 * @return estimated standard deviation of x coordinate of gyroscope.
966 */
967 public double getStandardDeviationAngularRateX() {
968 return Math.sqrt(varianceAngularRateX);
969 }
970
971 /**
972 * Gets estimated standard deviation of x coordinate of gyroscope.
973 *
974 * @return estimated standard deviation of x coordinate of gyroscope.
975 */
976 public AngularSpeed getStandardDeviationAngularRateXAsMeasurement() {
977 return new AngularSpeed(getStandardDeviationAngularRateX(), AngularSpeedUnit.RADIANS_PER_SECOND);
978 }
979
980 /**
981 * Gets estimated standard deviation of x coordinate of gyroscope.
982 *
983 * @param result estimated standard deviation of x coordinate of gyroscope.
984 */
985 public void getStandardDeviationAngularRateXAsMeasurement(final AngularSpeed result) {
986 result.setValue(getStandardDeviationAngularRateX());
987 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
988 }
989
990 /**
991 * Gets estimated standard deviation of y coordinate of gyroscope
992 * expressed in radians per second (rad/s).
993 *
994 * @return estimated standard deviation of y coordinate of gyroscope.
995 */
996 public double getStandardDeviationAngularRateY() {
997 return Math.sqrt(varianceAngularRateY);
998 }
999
1000 /**
1001 * Gets estimated standard deviation of y coordinate of gyroscope.
1002 *
1003 * @return estimated standard deviation of y coordinate of gyroscope.
1004 */
1005 public AngularSpeed getStandardDeviationAngularRateYAsMeasurement() {
1006 return new AngularSpeed(getStandardDeviationAngularRateY(), AngularSpeedUnit.RADIANS_PER_SECOND);
1007 }
1008
1009 /**
1010 * Gets estimated standard deviation of y coordinate of gyroscope.
1011 *
1012 * @param result estimated standard deviation of y coordinate of gyroscope.
1013 */
1014 public void getStandardDeviationAngularRateYAsMeasurement(final AngularSpeed result) {
1015 result.setValue(getStandardDeviationAngularRateY());
1016 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
1017 }
1018
1019 /**
1020 * Gets estimated standard deviation of z coordinate of gyroscope
1021 * expressed in radians per second (rad/s).
1022 *
1023 * @return estimated standard deviation of z coordinate of gyroscope.
1024 */
1025 public double getStandardDeviationAngularRateZ() {
1026 return Math.sqrt(varianceAngularRateZ);
1027 }
1028
1029 /**
1030 * Gets estimated standard deviation of z coordinate of gyroscope.
1031 *
1032 * @return estimated standard deviation of z coordinate of gyroscope.
1033 */
1034 public AngularSpeed getStandardDeviationAngularRateZAsMeasurement() {
1035 return new AngularSpeed(getStandardDeviationAngularRateZ(), AngularSpeedUnit.RADIANS_PER_SECOND);
1036 }
1037
1038 /**
1039 * Gets estimated standard deviation of z coordinate of gyroscope.
1040 *
1041 * @param result estimated standard deviation of z coordinate of gyroscope.
1042 */
1043 public void getStandardDeviationAngularRateZAsMeasurement(final AngularSpeed result) {
1044 result.setValue(getStandardDeviationAngularRateZ());
1045 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
1046 }
1047
1048 /**
1049 * Gets estimated standard deviation triad of angular speed measurements.
1050 *
1051 * @return estimated standard deviation triad of angular speed measurements.
1052 */
1053 public AngularSpeedTriad getStandardDeviationAngularSpeedTriad() {
1054 return new AngularSpeedTriad(AngularSpeedUnit.RADIANS_PER_SECOND,
1055 getStandardDeviationAngularRateX(),
1056 getStandardDeviationAngularRateY(),
1057 getStandardDeviationAngularRateZ());
1058 }
1059
1060 /**
1061 * Gets estimated standard deviation triad of angular speed measurements.
1062 *
1063 * @param result instance where estimated standard deviation triad of
1064 * gyroscope measurements will be stored.
1065 */
1066 public void getStandardDeviationAngularSpeedTriad(final AngularSpeedTriad result) {
1067 result.setValueCoordinatesAndUnit(getStandardDeviationAngularRateX(),
1068 getStandardDeviationAngularRateY(),
1069 getStandardDeviationAngularRateZ(),
1070 AngularSpeedUnit.RADIANS_PER_SECOND);
1071 }
1072
1073 /**
1074 * Gets norm of estimated standard deviation of gyroscope measurements
1075 * expressed in radians per second (rad/s).
1076 *
1077 * @return norm of estimated standard deviation of gyroscope
1078 * measurements.
1079 */
1080 public double getStandardDeviationAngularSpeedNorm() {
1081 final var wx = getStandardDeviationAngularRateX();
1082 final var wy = getStandardDeviationAngularRateY();
1083 final var wz = getStandardDeviationAngularRateZ();
1084 return Math.sqrt(wx * wx + wy * wy + wz * wz);
1085 }
1086
1087 /**
1088 * Gets norm of estimated standard deviation of gyroscope measurements.
1089 *
1090 * @return norm of estimated standard deviation of measurements.
1091 */
1092 public AngularSpeed getStandardDeviationAngularSpeedNormAsMeasurement() {
1093 return new AngularSpeed(getStandardDeviationAngularSpeedNorm(), AngularSpeedUnit.RADIANS_PER_SECOND);
1094 }
1095
1096 /**
1097 * Gets norm of estimated standard deviation of gyroscope measurements.
1098 *
1099 * @param result instance where norm of estimated standard deviation will be
1100 * stored.
1101 */
1102 public void getStandardDeviationAngularSpeedNormAsMeasurement(final AngularSpeed result) {
1103 result.setValue(getStandardDeviationAngularSpeedNorm());
1104 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
1105 }
1106
1107 /**
1108 * Gets average of estimated standard deviation coordinates of gyroscope
1109 * measurements expressed in radians per second (rad/s).
1110 *
1111 * @return average of estimated standard deviation coordinates.
1112 */
1113 public double getAverageStandardDeviationAngularSpeed() {
1114 final var wx = getStandardDeviationAngularRateX();
1115 final var wy = getStandardDeviationAngularRateY();
1116 final var wz = getStandardDeviationAngularRateZ();
1117 return (wx + wy + wz) / 3.0;
1118 }
1119
1120 /**
1121 * Gets average of estimated standard deviation coordinates of gyroscope
1122 * measurements.
1123 *
1124 * @return average of estimated standard deviation coordinates.
1125 */
1126 public AngularSpeed getAverageStandardDeviationAngularSpeedAsMeasurement() {
1127 return new AngularSpeed(getAverageStandardDeviationAngularSpeed(), AngularSpeedUnit.RADIANS_PER_SECOND);
1128 }
1129
1130 /**
1131 * Gets average of estimated standard deviation coordinates of gyroscope
1132 * measurements.
1133 *
1134 * @param result instance where average of estimated standard deviation coordinates
1135 * will be stored.
1136 */
1137 public void getAverageStandardDeviationAngularSpeedAsMeasurement(final AngularSpeed result) {
1138 result.setValue(getAverageStandardDeviationAngularSpeed());
1139 result.setUnit(AngularSpeedUnit.RADIANS_PER_SECOND);
1140 }
1141
1142 /**
1143 * Gets estimated standard deviations of accelerometer and gyroscope components
1144 * as a body kinematics instance.
1145 *
1146 * @return a body kinematics instance containing standard deviation values.
1147 */
1148 public BodyKinematics getStandardDeviationAsBodyKinematics() {
1149 return new BodyKinematics(getStandardDeviationSpecificForceX(),
1150 getStandardDeviationSpecificForceY(),
1151 getStandardDeviationSpecificForceZ(),
1152 getStandardDeviationAngularRateX(),
1153 getStandardDeviationAngularRateY(),
1154 getStandardDeviationAngularRateZ());
1155 }
1156
1157 /**
1158 * Gets estimated standard deviations of accelerometer and gyroscope components
1159 * as a body kinematics instance.
1160 *
1161 * @param result instance where data will be stored.
1162 */
1163 public void getStandardDeviationAsBodyKinematics(final BodyKinematics result) {
1164 result.setSpecificForceCoordinates(getStandardDeviationSpecificForceX(),
1165 getStandardDeviationSpecificForceY(),
1166 getStandardDeviationSpecificForceZ());
1167 result.setAngularRateCoordinates(getStandardDeviationAngularRateX(),
1168 getStandardDeviationAngularRateY(),
1169 getStandardDeviationAngularRateZ());
1170 }
1171
1172 /**
1173 * Gets accelerometer noise PSD (Power Spectral Density) on x axis expressed
1174 * in (m^2 * s^-3).
1175 *
1176 * @return accelerometer noise PSD on x axis.
1177 */
1178 public double getSpecificForcePsdX() {
1179 return varianceSpecificForceX * timeInterval;
1180 }
1181
1182 /**
1183 * Gets accelerometer noise PSD (Power Spectral Density) on y axis expressed
1184 * in (m^2 * s^-3).
1185 *
1186 * @return accelerometer noise PSD on y axis.
1187 */
1188 public double getSpecificForcePsdY() {
1189 return varianceSpecificForceY * timeInterval;
1190 }
1191
1192 /**
1193 * Gets accelerometer noise PSD (Power Spectral Density) on z axis expressed
1194 * in (m^2 * s^-3).
1195 *
1196 * @return accelerometer noise PSD on z axis.
1197 */
1198 public double getSpecificForcePsdZ() {
1199 return varianceSpecificForceZ * timeInterval;
1200 }
1201
1202 /**
1203 * Gets gyroscope noise PSD (Power Spectral Density) on x axis expressed
1204 * in (rad^2/s).
1205 *
1206 * @return gyroscope noise PSD on x axis.
1207 */
1208 public double getAngularRatePsdX() {
1209 return varianceAngularRateX * timeInterval;
1210 }
1211
1212 /**
1213 * Gets gyroscope noise PSD (Power Spectral Density) on y axis expressed
1214 * in (rad^2/s).
1215 *
1216 * @return gyroscope noise PSD on y axis.
1217 */
1218 public double getAngularRatePsdY() {
1219 return varianceAngularRateY * timeInterval;
1220 }
1221
1222 /**
1223 * Gets gyroscope noise PSD (Power Spectral Density) on z axis expressed
1224 * in (rad^2/s).
1225 *
1226 * @return gyroscope noise PSD on z axis.
1227 */
1228 public double getAngularRatePsdZ() {
1229 return varianceAngularRateZ * timeInterval;
1230 }
1231
1232 /**
1233 * Gets accelerometer noise root PSD (Power Spectral Density) on x axis
1234 * expressed in (m * s^-1.5).
1235 *
1236 * @return accelerometer noise root PSD on x axis.
1237 */
1238 public double getSpecificForceRootPsdX() {
1239 return Math.sqrt(getSpecificForcePsdX());
1240 }
1241
1242 /**
1243 * Gets accelerometer noise root PSD (Power Spectral Density) on y axis
1244 * expressed in (m * s^-1.5).
1245 *
1246 * @return accelerometer noise root PSD on y axis.
1247 */
1248 public double getSpecificForceRootPsdY() {
1249 return Math.sqrt(getSpecificForcePsdY());
1250 }
1251
1252 /**
1253 * Gets accelerometer noise root PSD (Power Spectral Density) on z axis
1254 * expressed in (m * s^-1.5).
1255 *
1256 * @return accelerometer noise root PSD on z axis.
1257 */
1258 public double getSpecificForceRootPsdZ() {
1259 return Math.sqrt(getSpecificForcePsdZ());
1260 }
1261
1262 /**
1263 * Gets gyroscope noise root PSD (Power Spectral Density) on x axis
1264 * expressed in (rad * s^-0.5).
1265 *
1266 * @return gyroscope noise root PSD on x axis.
1267 */
1268 public double getAngularRateRootPsdX() {
1269 return Math.sqrt(getAngularRatePsdX());
1270 }
1271
1272 /**
1273 * Gets gyroscope noise root PSD (Power Spectral Density) on y axis
1274 * expressed in (rad * s^-0.5).
1275 *
1276 * @return gyroscope noise root PSD on y axis.
1277 */
1278 public double getAngularRateRootPsdY() {
1279 return Math.sqrt(getAngularRatePsdY());
1280 }
1281
1282 /**
1283 * Gets gyroscope noise root PSD (Power Spectral Density) on z axis
1284 * expressed in (rad * s^-0.5).
1285 *
1286 * @return gyroscope noise root PSD on z axis.
1287 */
1288 public double getAngularRateRootPsdZ() {
1289 return Math.sqrt(getAngularRatePsdZ());
1290 }
1291
1292 /**
1293 * Gets average accelerometer noise PSD (Power Spectral Density) among
1294 * x,y,z components expressed as (m^2/s^-3).
1295 *
1296 * @return average accelerometer noise PSD.
1297 */
1298 public double getAvgSpecificForceNoisePsd() {
1299 return (getSpecificForcePsdX() + getSpecificForcePsdY() + getSpecificForcePsdZ()) / 3.0;
1300 }
1301
1302 /**
1303 * Gets norm of noise root PSD (Power Spectral Density) among x,y,z
1304 * components expressed as (m * s^-1.5).
1305 *
1306 * @return norm of noise root PSD.
1307 */
1308 public double getSpecificForceNoiseRootPsdNorm() {
1309 return Math.sqrt(getSpecificForcePsdX() + getSpecificForcePsdY() + getSpecificForcePsdZ());
1310 }
1311
1312 /**
1313 * Gets average gyroscope noise PSD (Power Spectral Density) among
1314 * x,y,z components expressed in (rad^2/s).
1315 *
1316 * @return average gyroscope noise PSD.
1317 */
1318 public double getAvgAngularRateNoisePsd() {
1319 return (getAngularRatePsdX() + getAngularRatePsdY() + getAngularRatePsdZ()) / 3.0;
1320 }
1321
1322 /**
1323 * Gets norm of noise root PSD (Power Spectral Density) among x,y,z
1324 * components expressed as (rad * s^-0.5).
1325 *
1326 * @return norm of noise root PSD.
1327 */
1328 public double getAngularRateNoiseRootPsdNorm() {
1329 return Math.sqrt(getAngularRatePsdX() + getAngularRatePsdY() + getAngularRatePsdZ());
1330 }
1331
1332 /**
1333 * Gets number of samples that have been processed so far.
1334 *
1335 * @return number of samples that have been processed so far.
1336 */
1337 public int getNumberOfProcessedSamples() {
1338 return numberOfProcessedSamples;
1339 }
1340
1341 /**
1342 * Gets number of currently windowed samples.
1343 *
1344 * @return number of samples within the window.
1345 */
1346 public int getNumberOfSamplesInWindow() {
1347 return windowedSamples.size();
1348 }
1349
1350 /**
1351 * Indicates whether estimator is currently running or not.
1352 *
1353 * @return true if estimator is running, false otherwise.
1354 */
1355 public boolean isRunning() {
1356 return running;
1357 }
1358
1359 /**
1360 * Indicates whether window of samples is filled or not.
1361 *
1362 * @return true if window is filled, false otherwise.
1363 */
1364 public boolean isWindowFilled() {
1365 return getNumberOfSamplesInWindow() == windowSize;
1366 }
1367
1368 /**
1369 * Adds a body kinematics measurement and processes current window.
1370 *
1371 * @param specificForceX x coordinate of specific force expressed in meters per squared second (m/s^2).
1372 * @param specificForceY y coordinate of specific force expressed in meters per squared second (m/s^2).
1373 * @param specificForceZ z coordinate of specific force expressed in meters per squared second (m/s^2).
1374 * @param angularRateX x coordinate of angular rate expressed in radians per second (rad/s).
1375 * @param angularRateY y coordinate of angular rate expressed in radians per second (rad/s).
1376 * @param angularRateZ z coordinate of angular rate expressed in radians per second (rad/s).
1377 * @return true if provided kinematics instance has been processed, false if it has
1378 * been ignored.
1379 * @throws LockedException if estimator is currently running.
1380 */
1381 public boolean addBodyKinematicsAndProcess(
1382 final double specificForceX, final double specificForceY, final double specificForceZ,
1383 final double angularRateX, final double angularRateY, final double angularRateZ) throws LockedException {
1384 return addBodyKinematicsAndProcess(new BodyKinematics(specificForceX, specificForceY, specificForceZ,
1385 angularRateX, angularRateY, angularRateZ));
1386 }
1387
1388 /**
1389 * Adds a body kinematics measurement and processes current window.
1390 *
1391 * @param specificForceX x coordinate of specific force.
1392 * @param specificForceY y coordinate of specific force.
1393 * @param specificForceZ z coordinate of specific force.
1394 * @param angularRateX x coordinate of angular rate.
1395 * @param angularRateY y coordinate of angular rate.
1396 * @param angularRateZ z coordinate of angular rate.
1397 * @return true if provided kinematics instance has been processed, false if it has
1398 * been ignored.
1399 * @throws LockedException if estimator is currently running.
1400 */
1401 public boolean addBodyKinematicsAndProcess(
1402 final Acceleration specificForceX, final Acceleration specificForceY, final Acceleration specificForceZ,
1403 final AngularSpeed angularRateX, final AngularSpeed angularRateY, final AngularSpeed angularRateZ)
1404 throws LockedException {
1405 return addBodyKinematicsAndProcess(new BodyKinematics(specificForceX, specificForceY, specificForceZ,
1406 angularRateX, angularRateY, angularRateZ));
1407 }
1408
1409 /**
1410 * Adds a body kinematics measurement and processes current window.
1411 *
1412 * @param specificForce specific force triad.
1413 * @param angularSpeed angular speed triad.
1414 * @return true if provided kinematics instance has been processed, false if it has
1415 * been ignored.
1416 * @throws LockedException if estimator is currently running.
1417 */
1418 public boolean addBodyKinematicsAndProcess(
1419 final AccelerationTriad specificForce, final AngularSpeedTriad angularSpeed) throws LockedException {
1420 return addBodyKinematicsAndProcess(new BodyKinematics(specificForce, angularSpeed));
1421 }
1422
1423 /**
1424 * Adds a body kinematics measurement and processes current window.
1425 *
1426 * @param kinematics body kinematics to be added and processed.
1427 * @return true if provided kinematics instance has been processed, false if it has
1428 * been ignored.
1429 * @throws LockedException if estimator is currently running.
1430 */
1431 public boolean addBodyKinematicsAndProcess(final BodyKinematics kinematics) throws LockedException {
1432 return internalAdd(kinematics, true);
1433 }
1434
1435 /**
1436 * Adds a body kinematics measurement.
1437 *
1438 * @param specificForceX x coordinate of specific force expressed in meters per squared second (m/s^2).
1439 * @param specificForceY y coordinate of specific force expressed in meters per squared second (m/s^2).
1440 * @param specificForceZ z coordinate of specific force expressed in meters per squared second (m/s^2).
1441 * @param angularRateX x coordinate of angular rate expressed in radians per second (rad/s).
1442 * @param angularRateY y coordinate of angular rate expressed in radians per second (rad/s).
1443 * @param angularRateZ z coordinate of angular rate expressed in radians per second (rad/s).
1444 * @throws LockedException if estimator is currently running.
1445 */
1446 public void addBodyKinematics(
1447 final double specificForceX, final double specificForceY, final double specificForceZ,
1448 final double angularRateX, final double angularRateY, final double angularRateZ) throws LockedException {
1449 addBodyKinematics(new BodyKinematics(specificForceX, specificForceY, specificForceZ,
1450 angularRateX, angularRateY, angularRateZ));
1451 }
1452
1453 /**
1454 * Adds a body kinematics measurement.
1455 *
1456 * @param specificForceX x coordinate of specific force.
1457 * @param specificForceY y coordinate of specific force.
1458 * @param specificForceZ z coordinate of specific force.
1459 * @param angularRateX x coordinate of angular rate.
1460 * @param angularRateY y coordinate of angular rate.
1461 * @param angularRateZ z coordinate of angular rate.
1462 * @throws LockedException if estimator is currently running.
1463 */
1464 public void addBodyKinematics(
1465 final Acceleration specificForceX, final Acceleration specificForceY, final Acceleration specificForceZ,
1466 final AngularSpeed angularRateX, final AngularSpeed angularRateY, final AngularSpeed angularRateZ)
1467 throws LockedException {
1468 addBodyKinematics(new BodyKinematics(specificForceX, specificForceY, specificForceZ,
1469 angularRateX, angularRateY, angularRateZ));
1470 }
1471
1472 /**
1473 * Adds a body kinematics measurement.
1474 *
1475 * @param specificForce specific force triad.
1476 * @param angularSpeed angular speed triad.
1477 * @throws LockedException if estimator is currently running.
1478 */
1479 public void addBodyKinematics(
1480 final AccelerationTriad specificForce, final AngularSpeedTriad angularSpeed) throws LockedException {
1481 addBodyKinematics(new BodyKinematics(specificForce, angularSpeed));
1482 }
1483
1484 /**
1485 * Adds a body kinematics measurement.
1486 *
1487 * @param kinematics body kinematics to be added.
1488 * @throws LockedException if estimator is currently running.
1489 */
1490 public void addBodyKinematics(final BodyKinematics kinematics) throws LockedException {
1491 internalAdd(kinematics, false);
1492 }
1493
1494 /**
1495 * Resets current estimator.
1496 *
1497 * @return true if estimator was successfully reset, false if no reset was needed.
1498 * @throws LockedException if estimator is currently running.
1499 */
1500 public boolean reset() throws LockedException {
1501 if (running) {
1502 throw new LockedException();
1503 }
1504
1505 if (numberOfProcessedSamples == 0) {
1506 return false;
1507 }
1508
1509 windowedSamples.clear();
1510 avgSpecificForceX = 0.0;
1511 avgSpecificForceY = 0.0;
1512 avgSpecificForceZ = 0.0;
1513 avgAngularRateX = 0.0;
1514 avgAngularRateY = 0.0;
1515 avgAngularRateZ = 0.0;
1516 varianceSpecificForceX = 0.0;
1517 varianceSpecificForceY = 0.0;
1518 varianceSpecificForceZ = 0.0;
1519 varianceAngularRateX = 0.0;
1520 varianceAngularRateY = 0.0;
1521 varianceAngularRateZ = 0.0;
1522 numberOfProcessedSamples = 0;
1523
1524 if (listener != null) {
1525 listener.onReset(this);
1526 }
1527
1528 return true;
1529 }
1530
1531 /**
1532 * Internally adds a body kinematics measurement and processes current window if indicated.
1533 *
1534 * @param kinematics body kinematics to be added.
1535 * @param process true if window of samples must also be processed, false otherwise.
1536 * @return true if result values were updated, false if not enough samples are available yet
1537 * and no average or variance values have been computed yet.
1538 * @throws LockedException if estimator is currently running.
1539 */
1540 private boolean internalAdd(final BodyKinematics kinematics, boolean process) throws LockedException {
1541 if (running) {
1542 throw new LockedException();
1543 }
1544
1545 running = true;
1546
1547 if (windowedSamples.isEmpty() && listener != null) {
1548 listener.onStart(this);
1549 }
1550
1551 final var wasFilled = isWindowFilled();
1552 if (wasFilled) {
1553 // remove first sample
1554 windowedSamples.removeFirst();
1555 }
1556
1557 windowedSamples.addLast(new BodyKinematics(kinematics));
1558
1559 // process window
1560 final var result = process && processWindow();
1561
1562 running = false;
1563
1564 if (listener != null) {
1565 listener.onBodyKinematicsAdded(this);
1566
1567 if (!wasFilled && isWindowFilled()) {
1568 listener.onWindowFilled(this);
1569 }
1570 }
1571
1572 return result;
1573 }
1574
1575 /**
1576 * Processes current windowed samples.
1577 *
1578 * @return true if sample was processed, false it there are not enough samples to
1579 * process current window.
1580 */
1581 private boolean processWindow() {
1582 numberOfProcessedSamples++;
1583
1584 final var n = windowedSamples.size();
1585 if (n <= 1) {
1586 return false;
1587 }
1588
1589 // compute averages
1590 var avgFx = 0.0;
1591 var avgFy = 0.0;
1592 var avgFz = 0.0;
1593 var avgWx = 0.0;
1594 var avgWy = 0.0;
1595 var avgWz = 0.0;
1596 for (final var kinematics : windowedSamples) {
1597 final var fx = kinematics.getFx();
1598 final var fy = kinematics.getFy();
1599 final var fz = kinematics.getFz();
1600 final var wx = kinematics.getAngularRateX();
1601 final var wy = kinematics.getAngularRateY();
1602 final var wz = kinematics.getAngularRateZ();
1603
1604 avgFx += fx;
1605 avgFy += fy;
1606 avgFz += fz;
1607 avgWx += wx;
1608 avgWy += wy;
1609 avgWz += wz;
1610 }
1611
1612 avgFx /= n;
1613 avgFy /= n;
1614 avgFz /= n;
1615 avgWx /= n;
1616 avgWy /= n;
1617 avgWz /= n;
1618
1619 // compute variances
1620 var varFx = 0.0;
1621 var varFy = 0.0;
1622 var varFz = 0.0;
1623 var varWx = 0.0;
1624 var varWy = 0.0;
1625 var varWz = 0.0;
1626 for (final var kinematics : windowedSamples) {
1627 final var fx = kinematics.getFx();
1628 final var fy = kinematics.getFy();
1629 final var fz = kinematics.getFz();
1630 final var wx = kinematics.getAngularRateX();
1631 final var wy = kinematics.getAngularRateY();
1632 final var wz = kinematics.getAngularRateZ();
1633
1634 final var diffFx = fx - avgFx;
1635 final var diffFy = fy - avgFy;
1636 final var diffFz = fz - avgFz;
1637 final var diffWx = wx - avgWx;
1638 final var diffWy = wy - avgWy;
1639 final var diffWz = wz - avgWz;
1640
1641 final var diffFx2 = diffFx * diffFx;
1642 final var diffFy2 = diffFy * diffFy;
1643 final var diffFz2 = diffFz * diffFz;
1644 final var diffWx2 = diffWx * diffWx;
1645 final var diffWy2 = diffWy * diffWy;
1646 final var diffWz2 = diffWz * diffWz;
1647
1648 varFx += diffFx2;
1649 varFy += diffFy2;
1650 varFz += diffFz2;
1651 varWx += diffWx2;
1652 varWy += diffWy2;
1653 varWz += diffWz2;
1654 }
1655
1656 final var nMinusOne = n - 1;
1657
1658 varFx /= nMinusOne;
1659 varFy /= nMinusOne;
1660 varFz /= nMinusOne;
1661 varWx /= nMinusOne;
1662 varWy /= nMinusOne;
1663 varWz /= nMinusOne;
1664
1665 avgSpecificForceX = avgFx;
1666 avgSpecificForceY = avgFy;
1667 avgSpecificForceZ = avgFz;
1668 avgAngularRateX = avgWx;
1669 avgAngularRateY = avgWy;
1670 avgAngularRateZ = avgWz;
1671
1672 varianceSpecificForceX = varFx;
1673 varianceSpecificForceY = varFy;
1674 varianceSpecificForceZ = varFz;
1675 varianceAngularRateX = varWx;
1676 varianceAngularRateY = varWy;
1677 varianceAngularRateZ = varWz;
1678
1679 return true;
1680 }
1681
1682 /**
1683 * Gets accelerometer base noise level root PSD (Power Spectral Density)
1684 * expressed in (m * s^-1.5).
1685 *
1686 * @return accelerometer base noise level root PSD.
1687 */
1688 @Override
1689 public double getAccelerometerBaseNoiseLevelRootPsd() {
1690 return getSpecificForceNoiseRootPsdNorm();
1691 }
1692
1693 /**
1694 * Gets gyroscope base noise level root PSD (Power Spectral Density)
1695 * expressed in (rad * s^-0.5)
1696 *
1697 * @return gyroscope base noise level root PSD.
1698 */
1699 @Override
1700 public double getGyroscopeBaseNoiseLevelRootPsd() {
1701 return getAngularRateNoiseRootPsdNorm();
1702 }
1703 }