Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Development of the Data Acquisition and CommunicationsSystem of a Wave Energy Conversion Buoy for
Oceanographic Applications
Leandro Henrique Costa Sousa
Thesis to obtain the Master of Science Degree in
Engineering and Energy Management
Supervisors: Prof. João Carlos de Campos HenriquesProf. Luís Manuel de Carvalho Gato
Examination Committee
Chairperson: Prof. Jorge de Saldanha Gonçalves MatosSupervisor: Prof. João Carlos de Campos Henriques
Member of the Committee: Prof. Paulo José da Costa Branco
November 2018
ii
Dedicated to my mother, brother and grandparents.
iii
iv
Acknowledgements
I would like to thank my supervisor, Prof. João Carlos de Campos Henriques for his guidance. I am also
grateful to Prof. Luís Manuel De Carvalho Gato for his interest. For all the support, I also thank Prof.
José Maria Campos da Silva André.
A special thanks to all the people from the Mecânica IV building that helped me through this journey.
To all my friends and companions from school, university and internship, thank you.
This dissertation would not be possible without the support of my mother, brother and grandparents who
deserve all the credit for their love and advice.
v
vi
Resumo
O objetivo deste projeto é construir um sistema de aquisição de dados que integre uma bóia de conver-
são de energia das ondas, utilizando sensores e computador de baixo custo. Esta dissertação começa
por identificar alguns dos importantes parâmetros a medir, os principais conceitos e a estruturação
teórica de um sistema de aquisição de dados. Foram utilizados sensores de temperatura, humidade,
aceleração, velocidade angular e campo magnético.
Dado que os sinais adquiridos através dos sensores incorporam ruído, foi implementado um filtro
Legendre-based. Este filtro foi desenvolvido no âmbito deste projeto. Um filtro em cascata composto
por vários Legendre-based obteve uma melhor atenuação do que os filtros elementares e uma largura
de banda de transição mais estreita. Analisando este filtro, obteve-se um filtro Sinc com uma janela
Gaussiana.
Para a calibração do acelerómetro e giroscópio, foram aplicados vários métodos utilizando um pêndulo,
um inclinómetro e um encoder que mede a posição angular. Depois de se melhorar a resolução deste
último relacionou-se a aceleração e a velocidade angular com a posição. O giroscópio tem um erro na
ordem dos 1.6%. O método utilizado para a calibração do acelerómetro, apesar de não permitir uma
estimativa do erro com grande exatidão, apresenta bons resultados com desvios médios registados na
ordem dos 0.0044 g.
O resultado do projeto consiste num sistema robusto e inovador que consegue medir parâmetros físicos
com uma boa exatidão e que irá fazer parte de um sistema de aquisição de dados marítimo.
Palavras-chave: ODAS, Readonly filesystem, filtro Gaussian Sinc, IoT, Análise de dados
vii
viii
Abstract
This project aims to build a data acquisition system integrated into a wave energy conversion buoy,
using low-cost sensors and computer. This dissertation starts by identifying some of the most important
parameters to measure and the main concepts and theoretical structure of a data acquisition system.
Sensors of temperature, humidity, acceleration angular velocity and magnetic field.
Given that the acquired signals from the sensors incorporate noise, a Legendre based cascade filter
was implemented. This filter was developed for this project. The cascade filter achieved a better atten-
uation than the elementary filters and a very narrow transition bandwidth. Analysing this filter, a Gauss
windowed Sinc filter was obtained.
For the calibration of the accelerometer and the gyroscope, several approaches were executed using
a pendulum, an inclinometer and an encoder which measures the angular position (after improving its
signal resolution). It is possible to relate the acceleration and the angular velocity with the angular
position. The gyroscope will have an error in the order of 1.6%. Although the method used for the
accelerometer calibration does not allow a very accurate prediction of the absolute error, it presents
good results with mean deviations in the order of 0.0044 g.
The result of the project consists of a robust and innovative system that measures physical parameters
with good accuracy and will integrate an ocean data acquisition system.
Keywords: ODAS, Readonly filesystem, Gaussian Sinc filter, IoT, Data analysis
ix
x
Contents
Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
List of Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv
List of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
Nomenclature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
1 Introduction 1
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Wave energy converters overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Ocean data acquisition systems overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5 Thesis Outline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Data Acquisition Systems 7
2.1 Sensors and transducers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Signal conditioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3 Field wiring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.4 Plug-in data acquisition boards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.5 DAQ computer and operating system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3 Hardware 17
3.1 Development board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Micro SD-card . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.3 Analogue to Digital Converter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.4 RTC DS1307 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.5 MPU 9150 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.6 LM35 DZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.7 HIH-4000 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
xi
4 Signal Filtering 23
4.1 Savitzky-Golay filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.2 Legendre-based filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2.1 Integration of the Legendre polynomials . . . . . . . . . . . . . . . . . . . . . . . . 28
4.2.2 Filter gain for a constant signal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.3 Cascade filtering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.4 Gaussian Sinc filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.5 Filter comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5 Read-only filesystem 37
5.1 Robustness Improvement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6 Programming Structure 41
6.1 Clock Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.2 Data Acquisition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.3 Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.3.1 Analogue to Digital Converter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.3.2 MPU-9150 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7 Calibration 49
7.1 Optical rotary encoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
7.2 Gyroscope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.3 Accelerometer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8 Results 61
8.1 Filter Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.2 Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
8.2.1 Gyroscope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
8.2.2 Accelerometer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
8.3 DAQ system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9 Conclusions 71
9.1 Achievements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Bibliography 75
A Programs 77
A.1 Main DAQ program in bash script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
A.2 MPU-9150 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
A.2.1 Main MPU-9150 program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
A.2.2 MPU-9150 functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
A.2.3 MPU-9150 registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
xii
A.3 ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
A.3.1 Main ADC program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
A.3.2 ADC functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
A.4 Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
A.5 Encoder parabolization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
A.5.1 Main parabolization program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
A.5.2 Import csv data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
A.5.3 Collect left points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
A.5.4 Parabola coefficients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
A.5.5 Interval points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
xiii
xiv
List of Tables
7.1 Relation between the channel states sequence and the rotation direction. . . . . . . . . . 50
7.2 X axis - inclination data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7.3 Y axis - inclination data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7.4 Z axis - inclination data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
xv
xvi
List of Figures
1.1 A backward bent duct buoy based on the oscillating water column working principle. . . . 2
1.2 WECs over the world and time. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Products and installations for ocean data acquisition. . . . . . . . . . . . . . . . . . . . . . 5
2.1 Data Acquisition System process. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Piezoresistive accelerometer. [9] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Capacitive accelerometer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4 Capacitive gyroscope. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Microscopic photograph of two gyroscope seismic masses. [10] . . . . . . . . . . . . . . . 11
2.6 Hall effect. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.1 Banana Pi M3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2 Banana Pi M3 GPIO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.3 I2C communications. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.4 Data acquisition board. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.5 BPI-M3, ADC, RTC and platform of connections with the DAQ board. . . . . . . . . . . . . 19
3.6 Micro-SD card. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.7 ADC board. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.8 RTC DS1307 module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.9 MPU 9150 module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.10 LM35 DZ IC Temperature Sensor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.11 HIH-4000 Humidity Sensor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.1 Signal filtering using a non-causal filter with three points. . . . . . . . . . . . . . . . . . . . 24
4.2 Piecewise function, fl , with NT = 11, NL = 7 and NR = 3. . . . . . . . . . . . . . . . . . . . 27
4.3 Obtaining a two layer cascade filter coefficients. . . . . . . . . . . . . . . . . . . . . . . . . 30
4.4 Cascade filter obtained using Legendre filter of degree 16 with windows of 211, 205, 201,
189 and 179 points. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.5 Legendre-based and cascade filters coefficients. . . . . . . . . . . . . . . . . . . . . . . . 31
4.6 Gaussian Sinc filter response in frequency. . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.7 Legendre-based, Gaussian Sinc and cascade filters coefficients. . . . . . . . . . . . . . . 35
4.8 Legendre-based, Gaussian Sinc and cascade filters in frequency domain. . . . . . . . . . 35
xvii
6.1 Main DAQ program. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.2 Circular buffer representation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.3 Device program. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.4 Data reading thread. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.5 Data writing thread. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.1 Pendulum. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.2 Rotary optical encoder. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
7.3 Channels A and B signals in counter-clockwise rotation. . . . . . . . . . . . . . . . . . . . 51
7.4 Parabolization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.5 Smoothed and not smoothed step sine wave shape in pendulum motion. . . . . . . . . . . 53
7.6 Angular position from the encoder signal in fast motion. . . . . . . . . . . . . . . . . . . . 53
7.7 Difference between consecutive angular positions from the encoder signal in fast motion. 54
7.8 X - peaks parabolic regression. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.9 Y - peaks parabolic regression. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.10 Z - peaks parabolic regression. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
7.11 X - calibrated accelerometer fit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
7.12 Y - calibrated accelerometer fit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
7.13 Z - calibrated accelerometer fit. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.1 Filter response. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
8.2 Centred data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
8.3 Filtered and unfiltered data comparison. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
8.4 Filtered data in frequency domain. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
8.5 X - calibrated gyroscope and encoder angular velocity comparison. . . . . . . . . . . . . . 65
8.6 -Y - calibrated gyroscope and encoder angular velocity comparison. . . . . . . . . . . . . 66
8.7 Z - calibrated gyroscope and encoder angular velocity comparison. . . . . . . . . . . . . . 67
8.8 -x vertical axis acceleration measurement. . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
8.9 -y vertical axis acceleration measurement. . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
8.10 z vertical axis acceleration measurement. . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
xviii
Nomenclature
Acronyms
ODAS Ocean Data Acquisition System
WEC Wave Energy Converter
OWC Oscillating Wave Column
DAQ Data Acquisition
MEMS Micro Electro Mechanical Systems
RTC Real Time Clock
ADC Analogue to Digital Converter
DAC Digital to Analogue Converter
SNR Signal to Noise Ratio
I/O Input/Output
CPU Central Process Unit
SPI Serial Peripheral Interface
I2C Inter Integrated Circuit
USB Universal Serial Bus
RTOS Real Time Operating System
BPI-M3 Banana Pi M3
SATA Serial AT Attachment
SDA Serial Data
SCL Serial Clock
GPIO General Purpose Input Output
PGA Programmable Gain Amplifier
SPS Samples per Second
xix
dps degrees per second
RH Relative Humidity
BW Bandwidth
SSH Secure Shell protocol
FIFO First In First Out
LSB Least Significant Bit
LED Light Emitting Diode
Ch Channel
CPR Counts per Rotation
LB Legendre-based
SG Savitzky Golay
Roman symbols
R Resistance
l Length
As Area of the cross section
E Young’s modulus
m Mass
C Capacitance
K Permittivity
Ac Area of the capacitor plate
r Radius
v Linear velocity
aC Coriolis acceleration
VH Hall voltage
I Electric current
B Magnetic field
n Charge carrier density
e Charge of an electron
xx
g Acceleration of gravity
fc Cut-off frequency
f Frequency
a Second order coefficient in a quadratic function
b First order coefficient in a quadratic function
c Zero order coefficient in a quadratic function
x , y , z Accelerations
ex; ey; ez Not calibrated accelerations
Im Moment of inertia
Greek symbols
Resistivity
∆R Resistance variation
� Poisson ratio
" Strain
"0 Vacuum permittivity
ff Standard deviation
„ Angular position
„ Angular velocitye„ Not calibrated angular velocity
„ Angular acceleration
∆PE Potential energy variation
Indexes
f Frequency domain
l Left
x; y ; z Directions
0 Peak
xxi
xxii
Glossary
CAPEX Investment necessary to acquire an asset or to prolong its lifespan
DAQ system The whole hardware and software used for the data acquisition system
DAQ board The board which contains all the sensors used
DAQ routine The main software that controls the data acquisition operations
xxiii
xxiv
Chapter 1
Introduction
The presented dissertation aims to develop a data acquisition and communications system for a wave
energy conversion (WEC) moored buoy that will be launched on the Atlantic Ocean. The system will ac-
quire both oceanographic and turbine/generator data. Its power supply will come from the wave energy
conversion. This work is included in the Instituto Superior Técnico’s Wave Energy Group participation
on the national project, WAVEBUOY, financed by the Portuguese Science Foundation (Fundação para
a Ciência e Tecnologia).
The buoy will use a technology called Oscillating Water Column (OWC) to convert the energy from the
waves into electricity. As shown in figure 1.1, the wave excites the water column inside the buoy structure
compressing and expanding the air entrapped in a chamber. The pressure difference between the air
chamber and the atmosphere is used to drive a self-rectifying air turbine. One big advantage of OWC
over other types of WECs is the reliability because an OWC uses fewer moving parts installed above the
water line, does not need a gearbox because it uses an air turbine, and the working fluid is compressible
thus reducing the instantaneous peak loads. [1]
1.1 Motivation
Acquiring data in the ocean is often very difficult and expensive. The environment can be very adverse,
due to the waves, wind, currents and seawater corrosion. Ocean data acquisition systems (ODAS) are
defined as an installation, platform, buoy or any other device with appropriate equipment to acquire
data in the sea about the marine environment or the atmosphere [2]. Usually, ODAS exist on drifting or
moored buoys, fixed platforms, ice drifters, island stations, coastal stations or profiling floats. From all
the presented mechanisms, the moored buoy is considered as the most capable of acquiring real-time
data of a fixed geographical region at an adequate rate. It can give good reference values for properties
measured in satellites and has the advantage (over ships and drifting buoys) of remaining in the same
geographical place. On the other hand, the CAPEX investment on moored buoys – which goes from the
expenditures in the buoy’s construction until the deployment and mooring – is very high. Costs can be
reduced through the reutilisation of the buoy, more durable materials in its construction and better power
1
Figure 1.1: A backward bent duct buoy based on the oscillating water column working principle.
supplies such as battery banks, solar or wind power and wave energy, as in the WAVEBUOY project.
One major problem of moored buoys ODAS is the fact that they often have periods when they lack
sufficient power supply. For example, the use of solar panels combined with an insufficient energy
storage capability. This might cause the data acquisition and transmission to be intermittent. Because
the wave energy availability on the ocean is high during day or night, a buoy that extracts energy from
the waves will have an advantage over other ODAS. Having so much energy stored in the ocean for
sustainable extraction, it is reasonable that the global economy agents will turn their attention to the
sea. Not only buoys but other technologies such as Autonomous Underwater Vehicles (AUVs), floating
stations, meteorological and environmental observation platforms are seen as an opportunity to explore
the ocean. In a world where the population is expected to rise above 11 billion people by the end of the
century, the sea can prove itself to be a solution for the energy deficit. The WEC is a greener way to
obtain energy, hopefully in the future, at large a scale.
Another important feature about this project is the fact that it is integrated into a contemporary techno-
logical tendency and need which is the Internet of Things (IoT). More and more often, the developed
products must be autonomous, communicative and intelligent. In other words, the machines must know
how to communicate between themselves and with humans. That is the objective of the data acquisition
system that is presented in this project. It will allow an observer to analyse the buoy and its environment
at a distance, knowing that the buoy will be in a remote location subject from severe conditions. ODAS
that are not auto-sufficient and that do not offer the possibility of real-time communication are usually
deployed for a short period and need maintenance more often.
1.2 Wave energy converters overview
The first WEC was patented in 1799, by Monsieur Girard and son [3]. At the beginning of the Napoleonic
era, its purpose was not to produce electricity, but to power simple pumps and sawmills. During the 19th
2
(a) Courtney’s whistling buoy. [4] (b) Uraga light buoy Tokyo Bay. [4] (c) Pico power plant. [1]
Figure 1.2: WECs over the world and time.
century, a WEC buoy was patented in New York by J. M. Courtney [4]. Its purpose was to produce a
whistle sound. The whistling buoys are still used to signal specific sea regions for boats and ships to
mind their location, contributing for safe navigation. The sound of whistle buoys can reach a distance of
24 kilometres. The rougher the sea is, the louder the sound will be.
The electricity production applications were only developed in the middle of the 20th century by Yoshio
Masuda. Yoshio Masuda [4], a former Japanese navy officer who is nowadays regarded as the father
of the modern WECs. In 1947, he designed and deployed the first WEC buoy that produces electricity
using the OWC technology. The energy from the waves would be converted into electricity to fill a set of
rechargeable batteries. The batteries would power a light emitter to signal regions on the sea that would
help the navigation of boats and ships. These buoys were sold in Japan and the USA.
Inspired by Yoshio Masuda, many organisations tried to replicate and improve WECs for electricity pro-
duction. During the 80s and 90s, several WECs fixed at shore using the OWC were built in many
countries. Shoreline has the advantage of being closer to the end product users, which means that the
energy transport is cheaper, easier, safer and more efficient. On the other hand, the available wave
energy near the shore is not as abundant as in the high sea.
1.3 Ocean data acquisition systems overview
Nowadays it is important for technologies to communicate between themselves and with their users
autonomously. For example, a cellphone communicates with its user when its power is low, fire alarms
communicate with other machines so that fire-fighters may be alerted, etc. All the communications
dependent on physical events rely on data acquisition (DAQ) systems. The DAQ system will measure a
physical property and store and transmit that information.
In oceanography, data acquisition systems are especially important to collect data from the ocean for en-
vironmental and biological studies. Studying the sea has been important since pre-historic times. Until a
3
few centuries ago, the purpose of oceanography was to understand the tides and currents for navigation
and fishery. Today, understanding maritime ecosystems, forecasting the weather and understanding the
geological, physical and chemical properties of the sea also integrate this science.
The design of ODAS is a challenge. It must address the challenging environment that the ODAS will be
subject to so that they can be reliable in data acquisition, storage and transmission. ODAS are essential
for maritime weather forecast and oceanography studies. ODAS are also a useful tool to measure
environmental properties that would be impossible otherwise and contribute to the safe and convenient
use of maritime equipment.
According to the Joint Technical Commission for Oceanography and Marine Meteorology (JCOMM), the
main oceanographic properties to measure are [5]:
• Wind speed.
• Air temperature.
• Water temperature.
• Salinity.
• Barometric pressure.
• Relative humidity.
• Precipitation.
• Radiation.
• Ocean current.
• Wave spectre.
• Horizontal visibility.
Figure 1.3 shows examples of systems specifically designed for ocean data acquisition. All of them
measure multiple properties. The Oceanic Platform of the Canary Islands (PLOCAN) (figure 1.3(a)) is
a fixed installation. The AXYS buoys (figure 1.3(b)) are floating moored structures, while the Saildrone
(figure 1.3(c)) is a floating moving structure.
1.4 Objectives
One of the main purposes of the WAVEBUOY project is to test a WEC on real sea conditions. The DAQ
system will help to know what kind of conditions the buoy will face.
The DAQ system uses a temperature sensor, an accelerometer, a gyroscope, a magnetometer and a
relative humidity sensor. The accelerometer, gyroscope and magnetometer can help to track the buoy
while it is in the sea. The accelerometer and gyroscope also have the function to assist in the calculation
of forces that can be applied to a buoy by the waves. The humidity and temperature can be used
for measuring the operational environment and control significantly high-temperature zones or water
infiltrations that might cause problems. In other words, the DAQ system assesses the interactions of the
buoy with its environment. The quality of the signal measured and its accuracy is also addressed. The
robustness of the system is also essential.
4
(a) PLOCAN platform (b) AXYS buoys
(c) Saildrone
Figure 1.3: Products and installations for ocean data acquisition.
1.5 Thesis Outline
This dissertation starts by explaining the theoretical structure and main concepts of a DAQ system. It
describes several methods to acquire a signal. In the following chapter, the hardware used is presented.
The hardware consists on low cost components which can be easily installed because of their small
dimensions (such as MEMS sensors).
The next step is to design a filter for the acquired data. Several filters were study and the one that
showed the best performance was used. Python was the programming language used for the filter.
After that, the robustness of the system is addressed and a way to improve its reliability. This chapter
will focus on the main problem that could happen while the ODAS is in operations which is the possibility
of it becoming inaccessible.
The structure of the programs designed for the DAQ system is described. It uses techniques such as
multithreading and a circular buffer. The programs designed for the data acquisition were C and Bash
Script.
The calibration of the gyroscope and accelerometer is explained afterwards. These sensors are the most
critical and are deeply affected by noise. The readings, using the manufacturers calibration factors, may
not be precise. For that reason, further calibration is needed. It was used a pendulum for that purpose.
Finally, the results of the filter implementation and the calibration of the sensors are presented. This will
allow an assessment of the work completed.
The purposed outcome of this project was a precise, safe, robust and reliable Ocean Data Acquisition
System that will monitor the Atlantic Ocean.
5
6
Chapter 2
Data Acquisition Systems
Data Acquisition is defined by a process in which a physical phenomenon is transformed into an electrical
signal so that it can be converted into a digital format, analysed and stored by a computer [6]. This stored
information can be useful for multiple purposes. Acquiring data follows the path of figure 2.1.
Figure 2.1: Data Acquisition System process.
The model of the figure 2.1 is observed in most data acquisition systems, nowadays.
2.1 Sensors and transducers
The physical phenomenon emits a signal that has energy or power. Transducers are devices that convert
a form of energy or power from a physical source into another useful energy form that will make the input
signal readable. There are six types of signals: mechanical, thermal, magnetic, electric, chemical, and
radiation.
Sensors are not necessarily transducers, or vice-versa. A sensor’s output signal is always electric.
A transducer implies the conversion of a signal from one type to another, while a sensor does not.
Transducers can also be actuators. In DAQs, sensors are mostly used, because electric output signals
have many advantages in signal conditioning, information transmission, storage and analysis. Sensors
do not have to gather a big portion of the phenomena’s energy. They rather take a small amount that can
be amplified in the signal conditioning step. Many sensors already integrate some signal conditioning in
their package. [7]
7
There are several ways to classify sensors:
• Active / Passive:
Active sensors are made of two components: an emitter and a receiver. The emitter sends a signal
that can have some interference from the physical phenomenon to measure before it reaches the
receiver. Active sensors require an external power source. Passive sensors use the energy from
the physical phenomena itself and do not need an external power source. Instead of measuring
the interference of an emitted signal by a physical phenomenon, the passive sensors measure the
physical property itself which changes a value of component from the electric network, such as a
resistor [8].
• Analogue / Digital:
Analogue sensors convert the magnitude of certain property to measure into a voltage or current
magnitude in the domain of time. There is a relation between these two dimensions (e.g., if the
input signal temperature increases, the output signal voltage also increases). In a digital sensor,
there are only two possible output signals (states): high or low. It is the sequence of pulses (digital
pulse train) in the frequency domain that can be translated into something readable. To be used in
computers, analogue signals must be converted to digital by Analogue to Digital converters (ADC).
[6]
• Contact / Non-Contact:
Contact sensors require physical contact to the environment in which the physical phenomenon
happens (e.g., strain gauges, temperature sensors). Non-contact sensors do not need to be in
contact with the physical phenomenon (e.g., optical and magnetic sensors).
• Absolute / Relative:
Absolute sensors read properties on their absolute scale (e.g., thermistors), while relative sensors
read them based on a reference value (e.g., thermocouple).
• Deflection / Null:
Deflection sensors produced a similar but opposed effect related to the property being measured.
For example, in dynamometers, a force causes a deflection on a spring that can be measured and
converted into force units. Null deflection sensors do not produce a deflection (e.g., a weighing
scale).
• Variable component in the sensor:
Comprises resistors, capacitances, inductances, p-n junctions, optical variables, etc.
To choose a sensor for a specific environment there are several criteria to consider [6]:
• Accuracy: If the measure is close to the actual property value. The manufacturers usually give
Sensor’s accuracy error.
• Sensitivity: The variation of the output signal per change of the input signal.
8
Figure 2.2: Piezoresistive accelerometer. [9] a) Top view. b) A-cut view
• Repeatability: If several measures made at identical conditions reproduce the same value.
• Range: The minimum and maximum measures that can be taken.
Other criteria such as cost and size are also important. Nowadays, sensors like accelerometers can
be extremely small, cheap, have more than one axis and integrate signal conditioning and Analogue to
Digital Converters. These kind of sensors are called micro-electro-mechanical systems (MEMS).
There are multiple possible working principles of the MEMS devices: [9]:
• Piezoresistive accelerometer
The piezoresistive accelerometer’s working principle lies on the fact that when a force is applied on
a resistor material, it can stretch or compress. Defining resistance as in Eq. (2.1), the resistance
depends linearly on the length of the resistor
R = l
As: (2.1)
There is a seismic mass that moves when a force is applied to the accelerometer. The seismic
mass is connected to a fixed frame by a beam. When the mass moves, the resistor in the beam
is stretched or compressed, changing its resistance. From the variation of the resistance, the
acceleration is obtained. The main problems with this kind of accelerometers are the difficulty in
protecting the technology from over-ranging and in reducing damping. Also, the temperature may
affect the strain of the material, which implies further corrections to the readings.
• Capacitive accelerometer
Capacitive accelerometers also use a seismic mass that moves when there is an acceleration.
The mass has several plates and moves back and forward when there is an acceleration, varying
the distance between the plates and the stationary electrodes.
The capacitor plates constitute a movable electrode. In figure 2.3, the green electrodes are electri-
cally connected, as well as the blue electrodes. When the seismic mass moves, the capacitances
between the movable plate and the green plate and between the movable plate and blue plate
9
Figure 2.3: Capacitive accelerometer.
vary. For that reason, the voltage will so. Because the seismic mass material is elastic, there is
a linear relationship between the force applied to the accelerometer and the variation of the dis-
tance between plates. The capacitance is described in Eq. 2.2. Since the capacitance is inversely
proportional to the voltage, the voltage will be proportional to the distance between plates
C ="0 K Ac
l: (2.2)
The measurement range of a capacitive accelerometer is smaller than in piezoresistive accelerom-
eters. On the other hand, capacitive MEMS accelerometers have a higher resolution, stability and
a lower sensitivity to dirt and temperature variations. The cost of mass production of this type of
accelerometers is quite low. The damping can be reduced by poking holes in the seismic mass.
• Capacitive gyroscope
Similarly to the capacitive accelerometer, the capacitive gyroscope uses the displacement of a
seismic mass to vary the capacitance between plates. The difference is that the displacement
is not caused by the sensor’s acceleration, but by the Coriolis acceleration. When an object is
rotating, the velocity near the centre is smaller than the velocity near its edge. If a rotating mass
within the object is projected from the extremity to the centre, because there is conservation of the
angular momentum, the radius will decrease which means that the velocity must increase
m r v = constant: (2.3)
This means that the mass will suffer a deflection. In the gyroscope, because the mass is constantly
vibrating, the rotation of the module will cause a Coriolis force, perpendicular to the oscillation
direction, which is responsible for the deflection. The Coriolis acceleration is measured in the
same way as the capacitive accelerometer. If the seismic mass oscillation velocity, v, is known, the
calculation of the angular velocity is made with the equation
aC = v „: (2.4)
10
Figure 2.4: Capacitive gyroscope.
One of the characteristics of the gyroscope is the fact that its signals are very weak. For this
reason, protection from interference is critical. Because of the size and the resonant frequencies
requirements, MEMS gyroscopes are very difficult to produce. The seismic mass also suffers from
damping when it is moving.
Figure 2.5: Microscopic photograph of two gyroscope seismic masses. [10]
• Magnetometer
Magnetometers measure a magnetic field using the Hall effect. They use a thin conductive plate
which has current flowing through it. If there is a magnetic field source in the environment, there
will be a disturbance in the current and, because of the Lorenz force, positive and negative charges
will be separated to opposite sides of the semiconductor. The sensor reads the voltage between
these charges
VH =I B
n d e: (2.5)
• Real time clock
Usually, the working principle of an RTC is explained by a crystal oscillator. If a voltage is applied
to a small crystal (e.g., Quartz), it produces a mechanical oscillation at a certain frequency (piezo-
electric effect). In other words, the crystal acts as a transducer that transforms electrical energy
into mechanical energy. Knowing the crystal frequency, the number of oscillations gives the time
11
Figure 2.6: Hall effect.
elapsed of a certain event.
2.2 Signal conditioning
The data acquisition computers that are used are, often, not prepared to receive the signals from the
sensors. For example, a computer without analogue inputs will not accept an analogue signal if it has
not been converted to digital. Also, signals contain noise which will worsen the measurements. These
problems can be attenuated by signal conditioning. There are five main tasks that are usually performed
during the signal conditioning [6]:
• Filtering
The purpose of filtering is to remove the noise from the signal. Noise can have multiple sources. If
the source of the noise is within the circuit, it is called intrinsic noise. Otherwise, if the noise source
is external, it is called extrinsic noise. Intrinsic noise sources include thermal (the free electrons
from the current cause temperature variations which may cause resistance variations), the bound-
ary between two materials where the current flows through which may be imperfect or the flow of
the current when it faces barriers such as p-n junctions. Extrinsic noise may have several sources
such as external magnetic fields, radiation, thermal sources, etc. For example, a frequent exter-
nal source of noise during the laboratory experiments of the MPU-9150’s accelerometers were
the mechanical vibrations of its surrounding structures. The signal noise is commonly transduced
from its original form to an electronic signal in three different ways: by conductive coupling, where
devices can share a signal (e.g., ground) causing fluctuations between each other; by capacitive
coupling, caused by external electric fields; or magnetic coupling, caused by external magnetic
fields. Usually, filters eliminate data at frequencies that diverge from the physical phenomena.
There are important characteristics of a filter to consider such as cut-off frequency (frequency at
which the filter starts to attenuate the signal), roll-off (the slope of the attenuation of the data at
12
the transition band) and quality factor (the gain of the filter at the resonance frequency). There are
different types of filters:
– Low pass: eliminate noise at high frequencies.
– High pass: eliminate noise at low frequencies.
– Bandpass: eliminate noise outside of a range of frequencies.
– Band stop: eliminate noise in a range of frequencies.
– Butterworth: contains several low pass filters.
• Amplification
Amplification of the signal is important to increase the resolution of the signal, making the maximum
range of the signal equal to the maximum range of components such as the ADC. It can also
increase the signal to noise ratio (SNR). By amplifying the signal, a subsequent noise will be more
negligible.
• Linearization
For sensors that do not have a linear relationship between the physical phenomenon and the
output signal.
• Isolation
Isolation is a protective measure for the DAQ hardware. In analogue signals, electrostatic dis-
charges, lighting or failure events can lead to high voltage variations which could deteriorate the
hardware. Isolation can prevent these events from happening. They include optic, magnetic or
capacitive isolation.
• Excitation
To provide external voltage or current signals.
Commercialised sensors often contain some form of signal conditioning.
2.3 Field wiring
Usually, signals are transmitted in the form of voltage. For long wire transmissions, to avoid voltage drop,
signals may be sent in the form of current and later converted into voltage just before the DAQ hardware.
Voltage signals are divided into two categories:
• Grounded signals: where the measurement is taken between the positive signal source and the
system ground (the reference). It is important to mention the fact that the system ground may not
be the absolute reference of the earth’s potential. For that reason, the signal that comes from this
type of wiring may need further signal conditioning.
13
• Floating signals: the measurements for floating signals are taken between two different source
points where neither of them is the ground (no absolute reference). Batteries are a good example
of floating signal sources.
Wiring does not depend only on how a sensor sends the signals but also on how the DAQ and signal
conditioning boards must receive them. These requirements can be divided into two types of measure-
ments:
• Single-ended: just as grounded signals, the measurement is taken with the system ground as an
absolute measurement. Only one line from the sensor is required.
• Differential: the voltage measurement taken does not have a fixed reference. It is taken between
two points where neither of them is fixed. Two lines must be received.
Cables used in field wiring may be susceptible to the environment conditions which induce noise. For
that reason, isolation may be important. [6]
2.4 Plug-in data acquisition boards
Some components may not exist in the DAQ computer. For that reason, plug-in data acquisition boards
that integrate a variety of components to fulfil their purposes can be used. For example: [6]
• Analogue input (ADC) boards: they comprise a multiplexer (for an ADC with multiple inputs, only
one can be read at a time. The multiplexer switches the input channel to be read), an amplifier, a
buffer, the analogue to digital converter (ADC), sample and hold circuits, the expansion bus and a
timing system. First, the ADC samples the continuous signal through time into a discrete function.
Then it uses the process of quantisation to map values from a large set of reading to truncate or
round a real number into one that can fit the possible length (e.g., 8-bit, 16-bit, etc.).
• Analogue output (DAC) boards: they are similar to the ADC board but do the opposite (they convert
digital signals to analogue).
• Digital I/O boards: digital inputs read a signal state (high or low). Digital outputs send a signal with
a determined state.
• Counter/timer I/O boards.
These boards can be connected to the computer if the expansion bus is compatible.
2.5 DAQ computer and operating system
Choosing the computer for real-time data acquisition implies several criteria that require analysing.
Things such as the CPU processor, the memory, the storage, the interrupts and power supply are
fundamental. It is essential to know which and how many input/output ports are needed for the devices
14
that will be used such as keyboard, mouse, screen and ports to receive and transmit data to sensors
(serial, SPI, I2C, USB, etc.).
The operating system to be used is also important. The most used are DOS, Windows or Unix. There
are also real-time operating systems (RTOS) that can be used for real-time data acquisition. Many of
the RTOS are developed based on the three main operating systems.
15
16
Chapter 3
Hardware
This chapter presents the material used to develop the DAQ system. The development board consists
of the single-board computer used to control the devices and process the data. The ADC, RTC and
sensors are described in this chapter. The total cost of the developed ODAS in this dissertation is
approximately 210 Euro. The dimensions of the system (without the DAQ board) in Fig. 3.5 are 92mm x
67mm x 60mm. It weights approximately 70 grams.
3.1 Development board
The development board used in this project was the Banana Pi M3 (BPI-M3) which costs 85 Euro. It
contains an octa-core ARM Cortex-A7 processor. Its random-access-memory (RAM) can hold up to 2
GB. One of its biggest advantages over similar boards (such as the Raspberry Pi or the ASUS Tinker
Board) is the fact that it has a SATA 2.0 port (more specifically, a USB-SATA bridge). It allows the
integration of storage devices such as hard drives, optical disks or SSD. Due to the amount of data
that will be stored, an SSD will be essential and, for that reason, the SATA port is essential. It can
also support other kinds of storage such as a micro SD-card. A micro SD-card was used to install the
operating system. Signals input and output are handled through the 40 pins GPIO (general purpose
input output), from Fig. 3.2.
Figure 3.1: Banana Pi M3.
17
Figure 3.2: Banana Pi M3 GPIO.
The digital sensors and the ADC were connected using the I2C protocol. The main reason for that
was the fact that some of the sensors that were already possessed could only be integrated by I2C
and because I2C signal transmission is very easy to handle. The Inter-Integrated Circuit (I2C) is a bus
that connects one or several masters (the data logger – BPI-M3) to the slaves (the sensors and ADC)
transmitting digital information. A handy advantage of the I2C over other buses is the fact that it only
uses two pins from the BPI-M3. All the slaves can be parallel connected.
Figure 3.3: I2C communications.
The sensors were placed in the DAQ board of Fig. 3.4 and will be described further on this chapter.
18
Figure 3.4: Data acquisition board.
Figure 3.5: BPI-M3, ADC, RTC and platform of connections with the DAQ board.
3.2 Micro SD-card
The sole purpose of the micro SD-card is to store the operative system. The operating system used for
the BPI-M3 is a Raspbian Jessie tailored specifically for the BPI-M3 (Raspbian is made for Raspberry Pi).
The Raspbian is an operating system based on the Debian Linux and integrates a working environment
similar to the UNIX systems. The SD card used costed 8 Euro.
Figure 3.6: Micro-SD card.
3.3 Analogue to Digital Converter
The chosen ADC was the MCP 2434. One ADC board contains two MCP 2434 chips with four analogue
channels each and costs 20 Euro. Since it is a differential ADC, it measures the difference between two
signals, which must be inside a range of ±2.048 V. Being a differential ADC does not mean that it is
not allowed to use a reference. If one of the signals is grounded, the measurement will be between the
signal that comes from the analogue sensor and the system ground. This is a very common technique
for situations where a fixed reference is important.
19
Figure 3.7: ADC board byte.
3.4 RTC DS1307
The DS1307 is a real-time clock (RTC). Its purpose is to keep track of the time. On the BPI-M3, the clock
time and date are set using the internet. Using the RTC, a more accurate and reliable clock setting will
be achieved. Since the RTC can keep track of time at high precision, its purpose is to set the system’s
date and time. Because it uses an alternative power source (usually a battery), if something happens to
the system, the RTC will still know the correct time to set. The RTC has low power consumption, and its
MEMS dimensions allow a better resistance to shock and vibration. The RTC used costed 30 Euro.
Figure 3.8: RTC DS1307 module.
3.5 MPU 9150
The MPU 9150 is a multi-chip module (MCM) that measures three different properties for every axis (it
has three). It integrates a capacitive accelerometer, a capacitive gyroscope and a magnetometer which
are very important for motion tracking systems. The MPU 9150 measures each property analogically and
the signal is digitalised by an ADC for each axis (16bit resolution for the gyroscope and accelerometer
and 13bit for the magnetometer), meaning that the output is digital. Since these sensors require an
external excitation, they are classified as active sensors. All of them are non-contact and measure
absolute values. While the accelerometer and the gyroscope are deflection sensors, the magnetometer
is not. The MPU 9150 costs 40 Euro.
20
Figure 3.9: MPU 9150 module.
3.6 LM35 DZ
The LM35 DZ is an integrated circuit (IC) temperature transducer that provides a grounded signal with a
voltage proportional to the absolute temperature. The temperature changes in the environment cause a
change in the resistance (similarly to thermistors). The advantage of the integrated circuit is the signal
by linearization. It is a non-contact and null deflection sensor. The LM35 DZ is one of the analogue
sensors connected to the ADC. This sensor costs 2 Euro.
Figure 3.10: LM35 DZ IC Temperature Sensor.
3.7 HIH-4000
The HIH-4000 is a capacitive relative humidity sensor. It uses a hygroscopic dielectric material between
two electrodes, which, based on the conditions of temperature and water vapour pressure, can absorb
the moisture increasing the capacitance. The HIH-4000 sends an analogue signal to be converted into
digital by the MCP2434. The HIH-4000 costs 20 Euro.
Figure 3.11: HIH-4000 Humidity Sensor.
21
22
Chapter 4
Signal Filtering
Noise defines an unwanted electrical signal blended with a measurement. The undesired effects of
noise are called interference. [6]
Any data acquisition system receives unwanted informations, due to the noise that is blended with the
signal, causing random fluctuations in the final measurement. It is not possible to remove the noise from
an environment, but it can be attenuated it in magnitude so that it will be negligible in relation to the
signal.
An approach to attenuate the noise is filtering the signal. The filter acts by attenuating the signal at
frequencies where noise happens. The frequency from which the filter is designed to attenuate is called
the cut-off frequency. Most filters are not capable of dropping from a unitary gain to zero exactly at the
cut-off frequency. There is a region around the cut-off frequency called transition-band where the gain
gradually drops. The region of frequencies where the gain is unitary is called pass-band. The region of
frequencies where the gain is null (or approximately zero) is called stop-band. The roll-off defines the
steepness of this transition.
The filter is a weight function with several coefficients that is combined with the signal that comes from
the sensor. These functions are windowed if they are finite. The filter and sensor signals are both
discrete. The operation of combining both functions is called convolution. In convolution, there is no
impediment for both signals to have a different number of points. Usually, the number of points of the
filter (the kernel) is smaller than the number of points of the unfiltered signal. There two main categories
of filters: the causal and the non-causal. The causal filters only use present and past data (in relation
to the measured instant) and may be used in real-time. Non-causal filters use past, present and future
information about the sensor’s signal to filter the present point, and can only be used in post-processing.
Data resulting from causal filters usually have a phase lag. In the present thesis, the non-causal filters
will be the only considered.
Each point of the filter is a coefficient and works as a weight. For that reason, the sum of all coefficients
of a filter must be one. Figure 4.1 shows how a convolution is made, where bj is a filter coefficient, zi is
a point from the unfiltered signal and fi is a point from the filtered signal. The filtered points values can
23
Figure 4.1: Signal filtering using a non-causal filter with three points.
be obtained by
fi = zi−1 b−1 + zi b0 + zi+1 b1: (4.1)
4.1 Savitzky-Golay filters
In 1964 Savitsky and Golay (SG) proposed a class of smoothing filters based on least-squares fitting of
a nth-degree polynomial in a prescribed window data [11]. These filters were devised for spectroscopy
applications but nowadays are commonly used for smoothing experimental noisy data with zero-phase.
Later, the idea of a "continuous analogue" of the SG filters based on Legendre polynomials was intro-
duced by Persson and Strang [12, 13]. An undesired property of these Legendre-based (LB) filters is
the non-unitary gain for constant signals. A common drawback of both SG and LB filters is the poor
stop-band attenuation properties due to excessive ripple amplitude.
The SG filters try to locally fit the unfiltered signal in an nth-degree polynomial. If the signal is modelled
using less points that the total, the polynomial cannot follow every point, but it will follow a tendency,
resulting in a smoothed signal.
24
The unfiltered signal f[i] can be approximated by a polynomial p[i], where:
pi =NXk=0
ak ik : (4.2)
To find the polynomial coefficients ak , the following operation is performed:26666664i0k ::: i0 1
i1k ::: i1 1
::: ::: ::: :::
ink ::: in 1
37777775
26666664a0
a1
:::
ak
37777775 =
26666664f1
f2
:::
fn
37777775 : (4.3)
The matrix of the Eq. (4.3) on the left-hand side is called Vandermond matrix. In other notation, this
equation can be represented by:
Ay = f : (4.4)
To solve this equation, AT is multiplied in both sides on the left.
AT Ay = AT f : (4.5)
The polynomial coefficients in vector y are given by:
y =`AT A
´−1AT f : (4.6)
The filter depends only on the degree of the polynomial and the size of the window. The higher the
degree of the polynomial, the higher will the steepness of the roll-off be, a desirable property.
On polynomial interpolation problems, when the degree of approximation is very high, the resulting
Vandermonde matrices are known to become very ill-conditioned. In the case of least squares prob-
lems, it becomes even very difficult to compute accurately the polynomial coefficients. To show this, let
us remember the definition of conditioning number of a matrix
cond (A) = ‖A‖‖A−1‖: (4.7)
The conditioning number of the matrix of Eq. (4.5) is
cond`ATA
´= ‖ATA‖‖
`ATA
´−1 ‖ = ‖ATA‖‖A−1A−T ‖
∼ ‖AT ‖‖A‖‖A−1‖‖A−T ‖
∼ ‖A‖2‖A−1‖2 = cond(A)2
(4.8)
In Durão’s thesis [14] he studies several signal filters, finishing with the Savitzky-Golay. The present
25
work uses it as a starting point to obtain a better filter.
4.2 Legendre-based filters
To overcome the instability problems of computing coefficients using the least squares method with high-
order polynomials, a different solution based on Legendre polynomials is purposed. The idea is to use
the orthogonality property of the polynomials to simplify the computations. As such, let us approximate
of a function f (fi) with a set of n + 1 Legendre polynomials, Pi ,
f (fi) =nXi=0
aiPi (fi): (4.9)
such that fi ∈ [−1;1]. To compute the parameters ai of the polynomial approximation using least-squares,
one must minimize the error function
E(a0; : : : ;an) =
Z 1
−1
nXi=0
aiPi (fi)− f (fi)
!2
dfi: (4.10)
The minimum with respect to ak occurs at
@
@akE(a0; : : : ;an) = 0; (4.11)
giving
2
Z 1
−1Pk(fi)
nXi=0
aiPi (fi)− f (fi)
!dfi = 0: (4.12)
Rearranging, yields Z 1
−1Pk(fi)
nXi=0
aiPi (fi)
!dfi =
Z 1
−1Pk(fi)f (fi)dfi: (4.13)
Due to the orthogonality of the Legendre polynomials, Eq. (4.13) simplifies to
ak
Z 1
−1Pk(fi)2 dfi =
Z 1
−1Pk(fi) f (fi)dfi: (4.14)
The value of the integral on the left-hand side is given by
Z 1
−1Pk(fi)2 dfi =
2
2k + 1: (4.15)
As a result, the value of the coefficient ak is obtained as
ak =2k + 1
2
Z 1
−1Pk(fi) f (fi) dfi: (4.16)
For the sake of simplicity, let us assume a uniform discretization of the time interval fi ∈ [−1;1] in NT
26
Figure 4.2: Piecewise function, fl , with NT = 11, NL = 7 and NR = 3.
time intervals Il , l ∈ {−NL; : : : ;NR}, such that
NT = NL + NR + 1: (4.17)
Defining the centre of the time interval Il by fil ,
Il =ˆfi−l ; fi
+l
˜; (4.18)
where
fi±l = fil ±∆; (4.19)
and
∆ =1
NT: (4.20)
The Legendre polynomials are continuous functions but the digital data represents f (fi) only at discrete
points. As a first approximation,a piecewise constant representation of the function f (fi) in each time
interval Il can be used, such that
ak =2k + 1
2
NRXl=−NL
fl
ZIl
Pk(fi) dfi: (4.21)
The value f of the filtered function at the centre
fi0 =NL − NRNT
; (4.22)
of the time interval I0 is computed using
f0 =nXi=0
ai Pi (fi0) =nXi=0
2i + 1
2
NRX
l=−NL
fl
ZIl
Pi (fi) dfi
!Pi (fi0): (4.23)
The idea is illustrated in figure 4.2 where NT = 11 and NL = 7 and NR = 3. Writing (4.23) as a weighted
27
sum of the function values, fl , gives
f0 =NRX
l=−NL
bl fl ; (4.24)
where the coefficients of the filter are determined by
bl =nXi=0
2i + 1
2Pi (fi0)
ZIl
Pi (fi) dfi: (4.25)
Evaluating analytically the integrals of (4.25) (see subsection 4.2.1) ,
bl = ∆ +1
2
nXi=1
Pi (fi0)`Pi+1
`fi+l´− Pi+1
`fi−l´− Pi−1
`fi+l´
+ Pi−1`fi−l´´: (4.26)
Similarly, the value of m-th derivative dm f =dfim of the filtered function at the centre of the time interval I0
is computed using
dm f0dfim
=nXi=0
aidmPidfim
(fi0) =nXi=0
2i + 1
2
NRX
l=−NL
fl
ZIl
Pi (fi) dfi
!dmPidfim
(fi0); (4.27)
which yieldsdm f0dfim
=NRX
l=−NL
c(m)l fl ; (4.28)
where the coefficients of the filter are given by, for m > 0,
c(m)l =
1
2
nXi=1
dmPidfim
(fi0)`Pi+1
`fi+l´− Pi+1
`fi−l´− Pi−1
`fi+l´
+ Pi−1`fi−l´´: (4.29)
4.2.1 Integration of the Legendre polynomials
The Legendre polynomials are known to satisfy the following relation, for i > 0,
(2i + 1)Pi (fi) =d
dfi(Pi+1(fi)− Pi−1(fi)) : (4.30)
Integrating (4.30) in Il ,
ZIl
Pi (fi) dfi =1
2i + 1
Z fi+l
fi−l
d
dfi(Pi+1(fi)− Pi−1(fi)) dfi
=1
2i + 1
`Pi+1
`fi+l´− Pi+1
`fi−l´− Pi−1
`fi+l´
+ Pi−1`fi−l´´:
(4.31)
For i = 0, Z fi+l
fi−l
P0(fi) dfi = 2∆; (4.32)
since P0(fi) = 1.
28
Finally, the integrals that appear in (4.25) can be evaluated analytically using
nXi=0
ZIl
Pi (fi) dfi = 2∆ +nXi=1
1
2i + 1
`Pi+1
`fi+l´− Pi+1
`fi−l´− Pi−1
`fi+l´
+ Pi−1`fi−l´´: (4.33)
The Python code that computes the coefficients of the Legendre filters using symbolical integration and
arbitrary precision arithmetic is shown in list 4.1.
4.2.2 Filter gain for a constant signal
Let us show thatNRX
l=−NL
bl = 1; (4.34)
a condition that must be fulfilled if the function f is constant in fi ∈ [−1;1] in order to guaranty that f0 = f .
Using (4.26), the LHS of (4.34) expands to
nXi=0
2i + 1
2
NRX
l=−NL
ZIl
Pi (fi) dfi
!Pi (fi0); (4.35)
which simplifies to
nXi=0
2i + 1
2
Z 1
−1Pi (fi) dfi Pi (fi0)
=1
2
„Z 1
−1P0(fi) dfi
«P0(fi0)| {z }
(A)
+nXi=1
2i + 1
2
„Z 1
−1Pi (fi) dfi
«Pi (fi0)| {z }
(B)
:(4.36)
Term (A) is equal to 1 since
P0(fi0) = 1; (4.37)
and Z 1
−1P0(fi) dfi = 2: (4.38)
The Legendre polynomials are known to satisfy the following relations
Pi (1) = 1; (4.39)
Pi (−1) = (−1)i : (4.40)
29
Figure 4.3: Obtaining a two layer cascade filter coefficients.
Integrating (4.30) in [−1;1],
Z 1
−1Pi (fi) dfi =
1
2i + 1
Z 1
−1
d
dfi(Pi+1(fi)− Pi−1(fi)) dfi
=1
2i + 1(Pi+1(1)− Pi+1(−1)− Pi−1(1) + Pi−1(−1))
= 0;
(4.41)
which shows that (B) is equal to 0 and confirms (4.34).
4.3 Cascade filtering
The recursive or cascade filtering is a sequential combination of multiple elementary filters. The cascade
filter response on the frequency domain is the multiplication of the responses of all elementary filters.
The process to obtain the cascade filter coefficients is explained by figure 4.3. It uses an example of
a cascade filter formed by the convolution of two equal elementary filters of three points. The cascade
30
0.00 0.02 0.04 0.06 0.08 0.10 0.12Dimensionless frequency, [-]
10 14
10 12
10 10
10 8
10 6
10 4
10 2
100Ga
in, [
-] Legendre/D16/W211Legendre/D16/W205Legendre/D16/W201Legendre/D16/W189Legendre/D16/W179CASCADE
Figure 4.4: Cascade filter obtained using Legendre filter of degree 16 with windows of 211, 205, 201,189 and 179 points.
100 50 0 50 100Sample, [-]
0.020.010.000.010.020.030.040.050.060.07
Gain
, [-]
Legendre/D16/W211Legendre/D16/W205Legendre/D16/W201Legendre/D16/W189Legendre/D16/W179CAS/D16/W981
Figure 4.5: Legendre-based and cascade filters coefficients.
coefficients are represented below
b′−2 = b−1; (4.42)
b′−1 = b−1 b0 + b0 b−1; (4.43)
b′0 = b−1 b1 + b0 b0 + b1 b−1; (4.44)
b′1 = b0 b1 + b1 b0; (4.45)
b′2 = b1: (4.46)
31
Figures 4.4 and 4.5 present the frequency response and filter coefficients for several LB filters and the
resulting cascade filter. All are made from Legendre polynomials with a 16th degree order, D. The
window size, W , varies from 179 to 211 for the LB filters and it is 981 for the cascade filter. The
cascade filter has very low gains in the stop-band compared to the elementary filters. This happens
because multiplying the gains of the elementary filters in the stop-band, the result is a stop-band lot
more attenuated. obtained. On the pass-band, the gains of the cascade filter will start to decay at the
same frequency of the elementary filter that decays first. This is the result of choosing single filters with
windows of 205, 201, 189 and 179 points which have cut-off frequencies within the first lobe of the filter
with a window of 211 points.
Summarizing, the cascade filter attenuates better the oscillations in the stop-band than the elementary
filters.
4.4 Gaussian Sinc filter
One of the things that was noticed in the figure 4.5 was the fact that the shape of the cascade function
is very similar to a sinc function
sinc(x) =sin(ı x)
ı x(4.47)
Another curious observation is the fact that, in the same figure, the decay of the oscillations of the
cascade filter towards away from the centre have a behaviour similar to an exponential function.
The sinc filter is an ideal filter and it is the inverse Fourier transform of a Heaviside step function in the
frequency domain [15]. It can make the drop exactly at the cut-off frequency (the transition-band is zero).
Its gain is unitary in the pass-band and null in the stop-band.
The sinc function, Eq. (4.47), never reaches an amplitude equal to zero when i → ±∞. A filter is not a
window function if it is infinite. Since the computers can not process an infinite series, to transform the
sinc function into a windowed function it must be truncated, resulting
h[i ] =sin(¸ i)
i; i ∈ {−M; : : : ;0; : : : ;M}: (4.48)
Outside the truncation region, the gain is zero. This creates a new problem: it is very difficult to model
a piecewise discontinuous function (such as the filter response in the frequency domain) by a finite sine
wave in time, due to Gibbs oscillations. When it is done, the response instead of being an ideal filter will
show overshoots and undershoots in the pass-band.
To solve this problem a convolution between the truncated sinc function and a window function is per-
formed. The Gauss window will be used to produce a Gaussian Sinc filter. The result will not be an ideal
filter. The transition bandwidth will not be zero, but the oscillations at the pass-band and stop-band will
be largely smoothed without compromising the desired filter properties.
The parameters that control the sinc function are the cut-off frequency and the window size after trunca-
tion. The cut-off frequency fc is inserted in the Eq. (4.48) in the coefficient ¸ which is present also for the
filter normalization. The cut-off frequency is proportional to the coefficient ¸. One characteristic of the
32
cut-off frequency is the fact that it is measured at the middle of the gain drop during the transition band,
instead of the usual 3 dB. This happens because the sinc filter is symmetrical between the pass-band
and the stop-band.
The number of points (or window size), 2M+1, are chosen knowing that the gain coefficients calculated
must be centred (i.e., i ∈ {−M; : : : ;0; : : : ;M}). The number of points control the transition band size. The
higher is M, the shorter will be the transition band. A good approximation of the transition bandwidth
(BW) can be seen in the Eq. (4.49) [16]
BW =4
M: (4.49)
To attenuate the truncation problems, the sinc filter multiplies with a Gauss window. The Gauss window
has the ability to prevent overshoot and undershoot. This means that there are no oscillations in pass-
band and the stop-band is very smooth. On the other hand, a Gauss window slows the roll-off of the
Sinc filter. The standard deviation is represented by ff
g [i ] =1√
2ı ffe−
i2
2ff2 : (4.50)
To obtain the Gaussian sinc filter, a convolution between the Gauss window and the truncated sinc filter
is performed. The coefficient K, in the Eq. (4.51), normalizes the result
hg [i ] = K h[i ] ∗ g [i ]: (4.51)
The Gauss window will attenuate the oscillations of the sinc filter in both pass-band and stop-band. The
sinc function will allow a narrow transition band.
The characteristics used to design the filter are the parameter ¸ from Eq. (4.48), which controls the
cut-off frequency, the standard deviation, ff and the window size, W.
The figure 4.6 presents three different Gaussian Sinc filters in the frequency domain. The red curve
represents the reference design parameters. In comparison to the red curve, the blue curve has a lower
coefficient ¸. Since the cut-off frequency is proportional to ¸, if ¸ decreases, the cut-off frequency will
also decrease. Because the standard deviation is not changed, the transition-band is the same for both
curves. It is visible that the stop-band and pass-band are symmetrical. For that reason, the cut-off
frequency is the frequency at which the gain of the Gaussian Sinc filter is 0.5.
The green curve has the same ¸ coefficient as the red curve. Therefore, both curves have the same
cut-off frequency. On the other hand, the standard deviation ff is much higher on the green filter than
on the red one. In other words, the Gauss window contribution to the filter is lower. For that reason,
the resulting filter will behave similarly to a truncated sinc filter. This behaviour consists on a narrower
transition-band at the cost of the undershoot and overshoot in the pass-band and the stop-band.
33
0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08Dimensionless frequency, [-]
0.2
0.0
0.2
0.4
0.6
0.8
1.0
1.2Ga
in, [
-] Gaussian Sinc filter: = 50.00 / = 0.50Gaussian Sinc filter: = 100.00 / = 10000.00Gaussian Sinc filter: = 100.00 / = 0.50
Figure 4.6: Gaussian Sinc filter response in frequency.
4.5 Filter comparison
Previously, this chapter presented the SG filter. Its coefficients are difficult or even, nearly impossible to
calculate analytically when the degree of the polynomial is very high. For that reason, the LB cascade
filter was seen as an alternative. The LB filter tries to approximate the unfiltered signal by a sum of
Legendre polynomials, using the least-squares fit. Since the cascade filter result was very similar to a
sinc function, the later was used since it presented better properties. The issues of the sinc filter (related
with the discontinuity in the frequency domain) are surpassed by a convolution between a truncated sinc
filter and a Gauss window.
The figure 4.7 shows a comparison of the studied filters’ coefficients. Two of them are Gaussian Sinc
filters, with different ¸ coefficients, different standard deviations, ff and different window sizes, W. The
cascade filter of 16th degree, with a window with 981 points and the LB filter of 16th degree, with a
window with 211 points from figure 4.5 are also present. One of the Gaussian Sinc filters have the
same window size as the cascade filter. The other Gaussian Sinc filter as the same window size as the
LB filter. The filter that shows more instability is the LB filter. This will cause a poor attenuation in the
stop-band, compared to the other filters. On the opposite side, the cascade filter presents a very good
attenuation. This is proven in figure 4.8.
In figure 4.8, comparing the Gaussian Sinc filters, the Gaussian Sinc function with a larger window will
have a much narrower transition-band. Comparing the cascade filter with the LB, although the second
provides a much better attenuation. The LB filter has a steeper roll-off than the smaller window Gaussian
Sinc filter. Despite this advantage, the lobes of the stop-band of the LB filter reach a gain in the order of
10% which is very high. On the other hand, the smaller window Gaussian Sinc filter lobes can reach a
gain of the order of 0.1%. The cascade and the larger window Gaussian Sinc filters are the ones with
the better attenuation in the stop-band. Both have the same window size. The cascade filter oscillates
34
400 200 0 200 400Sample, [-]
0.02
0.01
0.00
0.01
0.02
0.03
0.04
0.05
0.06Ga
in, [
-]Gaussian Sinc filter:
= 28.00 / = 0.45 / W981Gaussian Sinc filter:
= 5.40 / = 0.60 / W211CAS/D16/W981Legendre/D16/W211
Figure 4.7: Legendre-based, Gaussian Sinc and cascade filters coefficients.
0.00 0.02 0.04 0.06 0.08 0.10Dimensionless frequency, [-]
10 8
10 7
10 6
10 5
10 4
10 3
10 2
10 1
100
Gain
, [-]
Legendre/D16/W211Gaussian Sinc filter: = 28.00 / = 0.45 / W981Gaussian Sinc filter: = 5.40 / = 0.60 / W211CAS/D16/W981
Figure 4.8: Legendre-based, Gaussian Sinc and cascade filters in frequency domain.
closer to zero. In another point of view, the stop-band in both filters is so low that, in practice, their
attenuation difference is negligible. On the other side, the Gaussian Sinc filter has the steepest roll-off.
The definition of best filter differs from case to case. Both the cascade and the Gaussian Sinc filter
would fit the purpose of this project. Since both have a very good attenuation performance, the criterion
used to select a filter was the roll-off performance. In that field, the Gaussian Sinc proved to be the best
and, therefore, will be the one used. Besides that, the computation of the Gaussian Sinc filter is faster
and more efficient.
35
Listing 4.1: Python code used to compute the analytical solution of the coefficients of the Legendrefilters.import sympy , numpy , h5py , sys , osfrom sympy.core.cache import *
#~##############################################################################if len( sys.argv ) == 3:
# called with command line argumentsn = int( sys.argv [1] )NT = sympy.sympify( int( sys.argv [2] ) )
elif len( sys.argv ) == 1:# called from command line without argsn = int( 16 )NT = sympy.sympify( int( 401 ) )
else:# called from command line with wrong number of argsprint( sys.argv [0] + ": wrong number of arguments" )exit (1)
#~##############################################################################m = sympy.sympify( int(NT/2) )x = sympy.symbols( "x" )Delta = sympy.sympify( 1 / NT )TwoDelta = sympy.sympify( 2 / NT )tau0 = sympy.sympify( 0 )tau_m = sympy.sympify( -1 )
sum_bE = sympy.sympify( 0 )sum_bN = 0.0
b = numpy.zeros( NT )c = numpy.zeros( NT )r = 10** int( numpy.log10( float( NT ) )-3 ) # used for print
P = [ lambda x, i = i : sympy.legendre( i, x ) for i in range( n + 2 ) ]
#~###############################################################################~ left half of the filterfor l in range( -m, 1 ):
tau_p = tau_m + TwoDeltabl = Deltacl = 0.0
for i in range( 1, n+1 ):pp = P[i+1]( tau_p ) - P[i+1]( tau_m )pm = P[i-1]( tau_p ) - P[i-1]( tau_m )bl = bl + P[i]( tau0 ) * ( pp - pm ) / 2
dPidx = sympy.lambdify( x, sympy.diff( sympy.legendre( i, x ), x ) )cl = cl + dPidx( tau0 ) * ( pp - pm ) / 2
b[ m + l ] = sympy.N( bl , 20 )c[ m + l ] = sympy.N( cl , 20 )
if l == 0:sum_bE = sum_bE + blsum_bN = sum_bN + b[ m + l ]
else:sum_bE = sum_bE + 2*blsum_bN = sum_bN + 2*b[ m + l ]
del pp, pm, blclear_cache ()
tau_m = tau_p
if l % r == 0:print( "b[% 6i] = % .18E" % ( l, b[ m + l ] ) )
#~###############################################################################~ right half of the filter excluding 0for l in range( 1, m+1 ):
b[ m + l ] = b[ m - l ]c[ m + l ] = -c[ m - l ]
#~##############################################################################print ()print( "Sum_bE =", sympy.N( sum_bE , 18 ) )print( "Sum_bN =", sympy.N( sum_bN , 18 ) )print( c )
#~ WRITE FILE #################################################################folder = "../ dbd_filters/Legendre_D %03i" % nfilename = "/Legendre_Filter_D %03 i_W %06i.h5" % ( n, NT )
if not os.path.exists( folder ):os.mkdir( folder )
with h5py.File( folder + filename , 'w') as hf:grp = hf.create_group( 'filter ' )dset = hf.create_dataset('filter/coefs ', data = b )dset = hf.create_dataset( 'filter/deriv_coefs ', data = c )grp.attrs[ 'order ' ] = int( n )grp.attrs[ 'window ' ] = int( NT )grp.attrs[ 'sum_coefs ' ] = sum_bN
hf.close()
36
Chapter 5
Read-only filesystem
The designed ODAS must be prepared to face the sea conditions. If the power supply of the ODAS
fails while the operating system is storing data to the SD card, the problem would be much worse. In
this case, there would be filesystem corruption. The file system logically defines the way and the place
where files are stored. It makes sure that the operating system knows where a file in storage begins and
ends. While data is being written, the filesystem is defining new logical boundaries for several files. An
improper shutdown while the filesystem is operating, would cause the files that it manages to muddle.
Since the data is being written to storage that contains all the files that constitute the operating system,
the computer becomes unusable. It is important to mention that not only the DAQ program is writing
data to storage, but also the operating system. A computer is continuously writing log files, temporary
files, etc. This data, before being stored in a file, is temporarily stored in a cache which an improper
shutdown would erase. A proper shutdown consists on unmounting all the filesystems except root, end
any user processes, end the daemons and finally close the root filesystem. [17]
Besides the data loss, the main problem of filesystem corruption in this project is the fact that the ability
to communicate with the BPI-M3 could be lost. Other types of software problems could be handled by
connecting to the BPI-M3 by SSH and trying to solve it directly. A filesystem corruption could not be
dealt remotely. Since the buoy will be in a remote place for several months, the data acquisition purpose
of this project would be ruined.
A stress test was applied to the BPI-M3 to see if this problem happens. A binary backup was made
before to make sure that if the system is corrupted, it would be possible to return to the point right before
the test. The data acquisition program was set to start on boot. While the program was acquiring data
and writing it to the same storage as the operating system, the power supply would be disconnected. In
all three tests made, the filesystem was corrupted and the BPI-M3 could not initialize.
5.1 Robustness Improvement
There are several solutions to the filesystem corruption problem. For example, a periodical backup of
the operating system and all the files and applications. A binary backup was made before the stress
37
tests. It stores the current state of the system including every file just as it is to a disk image. When
there is a filesystem corruption, it is possible to simply format the SD card and install the backup image
again. In our application, this solution is feasible but does not solve the loss of communications problem.
A filesystem corruption would still cause the DAQ system to be unusable. The binary back-up requires
the physical presence of the SD card, while the buoy is operating. That would be impossible. On the
other hand, the SSH communications allow the exchange of files. Summarizing, a periodic back-up is
recommended but does not solve the problem.
Another solution could be implementing an uninterruptible power supply. The source of power for the
ODAS will be the energy converted from the waves and stored in batteries. The uninterruptible power
supply consists of using one or more extra power sources for the system. Usually, an alternative battery
is used in these situations. This would be a very feasible solution if the extra batteries could be changed
whenever they run out. Since the ODAS will be in a remote place, replacing them with new ones would
require a person to do it, and that is also not an option to be performed remotely.
The solution used for this problem was to handle the filesystem as a read-only. Read-only is a file
attribute. It means that the file can be opened and explored, but never written or changed. This way,
the filesystem will not change the files boundaries. The objective was to give the read-only attribute to
the filesystem where the operating system is stored. While this unit is read-only, it will be impossible to
write the measurements from the DAQ system in it. A second storage unit with a read-and-write attribute
was be used for that. This means that, if the second unit is corrupted, at least the one containing the
operating system will be safe and it will still be possible to communicate with it remotely.
To give the attribute of read-only to a filesystem was easy. The problem was that the operating system
would still try to write files, which would cause an error. For that reason, all the files that are normally
written to the storage must be forbidden from that or allowed to write to a cache in the random access
memory (RAM). One of those programmes that writes files is the DAQ program. As stated previously,
these files were written in a secondary storage unit.
The programmes that write files to the storage were located and handled in different ways. To give the
main storage unit the read-only attribute there are several steps to perform: [18]
1. Update the operating system
Since it will not be possible to write files any longer while in the read-only filesystem, it is better to
make all the updates beforehand. The result will be the system to be preserved.
2. Remove all the files and applications that will not be needed
These programs and services are the wolfram-engine, triggerhappy, anacron, logrotate, dphys-
swapfile, xserver-common, lightdm and x11-common, which are automatically integrated into the
operating system from the factory.
3. Use a syslog that logs to the memory
Syslog is log management software that sends event messages that are sent by devices such
as routers and switches to a logging server. Usually, they are written to the storage unit. Using
a syslog that writes to the memory avoids this problem. The log management software used is
38
called busybox-syslogd. This one will replace the rsyslog that the Raspbian operating system had
installed before.
4. Disable the filesystem check
The filesystem check is a tool that guarantees the consistency of the filesystem. If there are
errors, the filesystem check will detect and repair them. The filesystem check runs automatically
at boot. Since the operating system storage unit will not be corrupted, the filesystem check must
be disabled. Otherwise, any manual change made to the filesystem will cause the filesystem check
to deny any boot.
5. Change paths where the system writes to
Some services and applications need to write data. The directory they write in must be changed
to a temporary one in the memory.
6. Remove unnecessary start-up scripts that write to storage
These scripts are bootlogs and console-setup.
7. Set the mounting option of the storage unit as read-only
The file fstab, in the directory /etc, controls the way how storage units are mounted. Here, the the
read-only attribute is given to the main storage unit. It is also possible to add the second storage
to mount it here. The secondary unit of storage must have the read-and-write attribute.
8. Add a command to switch from read-only to read-and-write filesystem and vice-versa
This will be a help whenever a change in the main storage unit is needed.
After changing the attribute of the main unit filesystem to read-only and adding the second unit with read-
and-write attributes, the stress test was applied fifty times in different times of the boot. In none of them,
the system was corrupted. The process to make the system more robust was successful. Whenever a
change in the main storage unit is needed, a command is used to switch to read and write mode.
39
40
Chapter 6
Programming Structure
The data acquisition system is planned to start autonomously after the system boots. The system must
reboot periodically, right after the data acquisition program stops.
While the DAQ system was being developed, the communications with the BPI-M3 were executed us-
ing a headless Secure Shell (SSH) protocol. The term headless stands for the fact that a monitor is
not plugged to the BPI-M3. This means that all the graphical display was being handled by the SSH
communications to a personal computer.
The SSH protocol was invented in 1995, by Tatu Ylonen, a Finnish software engineer as a way to protect
his data (such as usernames and passwords). SSH will also be the protocol used to communicate with
the DAQ system while it is in the buoy. For that, the BPI-M3 will also need an internet connection.
It is planned that the buoy will have a 4G internet antenna since a network operator must cover the
geographical region where the buoy will operate.
It is imperative that SSH connection is guaranteed for all the DAQ system’s lifecycle. For that reason, the
method to transform the main filesystem into a read-only, described in the chapter 5 was critical, despite
its complexity and difficulty in implementation.
6.1 Clock Setup
The BPI-M3 uses the internet to set the clock for a given localization. The problem is that it is not certain
that the buoy will have continuous access to the internet. The time tracking must rely on something more
autonomous, robust and accurate. For that, the RTC was used.
The program structure of the RTC has only two steps:
1. Set the date and time of the RTC
Each information is set to its register using binary-coded decimal (bdc) where each group of four
bits (from right to left) makes a decimal digit (also from right to left).
• RTC I2C address: 0x68.
• Register 0x00: Sets the seconds (from 0 to 59) after being converted to bdc.
41
• Register 0x01: Sets the minutes (from 0 to 59) after being converted to bdc.
• Register 0x02: Sets the hours (from 0 to 24) after being converted to bdc.
• Register 0x03: Sets the day of the week (from 1 to 7) after being converted to bdc.
• Register 0x04: Sets the day (from 1 to 31) after being converted to bdc.
• Register 0x05: Sets the month (from 1 to 12) after being converted to bdc.
• Register 0x06: Sets the year (from 0 to 99) after being converted to bdc (the year register
only works for the current century).
2. Set the system clock using the RTC date and time information.
The first step only needs to be done once, while the second step must be performed at every boot of the
system.
6.2 Data Acquisition
The data acquisition software structure is a complex one. It must start at boot, it controls each sensor
and it must stop periodically so that the system can reboot. Each sensor has its own program and writes
a file with all the data acquired during that period.
One must be careful using endless cycles that only stop at reboot. If it is not possible to break it, it may
cause the whole system to be unusable for any other purpose. The acquisition is an infinite loop since it
starts at boot and orders the reboot autonomously. An external interrupt was implemented to break the
cycle when needed, using the 40 GPIO of the BPI-M3. Some of the pins are connected to the system’s
ground. It is possible to select one of the digital inputs of the GPIO that is always in the "high" state. If
the pin is disconnected from the ground, the pin’s state will be "high". If it is connected to the ground,
its state will become "low". A condition can be set that defines that if the state is "low", the system will
reboot at the end of the cycles. If the state is "high", the system will not reboot.
Figure 6.1: Main DAQ program.
42
6.3 Devices
When the main DAQ program starts, it will command the MPU-9150 and ADC programs to start. Both
run at the same time.
In the first attempt to produce a DAQ program, the algorithm was to initialise the sensors and start cycle
for data acquisition. In each loop of the cycle, the program would read a value and, right after, write it to
the storage. When the cycle ended, the program would terminate. Since the structure of this program
was very simple, it was very helpful to understand how to configure a sensor and how to acquire and
store data. The problem is the fact that the cycle was not efficient. Acquiring data from the sensor is
fast, but writing it to the storage is not. For that reason, the sampling frequency was very low (in the
order of 150 Hz for the MPU-9150).
The second attempt consisted of initialising the sensors and starting a cycle for data acquisition and
storage just as in the first attempt. The difference is that, in the cycle, a buffer would be created. The
buffer is a structure used to store data in memory temporarily. After that, a second cycle inside the
first one would acquire data and fill the buffer with it. When the buffer was full, the second cycle would
end, and the buffer information would be written in storage. When the first cycle ends, the program
terminates. Here, the sampling frequency was much faster, but not constant. While the second cycle is
performing, the data acquisition is fast. When it finishes, and the program goes back to the beginning of
the first cycle, some time is lost to store the data. That time prevents the sampling frequency from being
constant. Another problem is the fact that, if for some external reason, the program stops, all the data in
the buffer is lost.
The third attempt consisted of using a circular buffer with multithreading. The process of writing infor-
mation to a file takes time, and data acquisition is fast. To not cause delays in data reading, data can
be stored in the buffer before it is written. Multithreading in programming is the ability to run several
commands concurrently. While one process is reading data to the buffer, another is writing it to a file at
the same time.
One way to manage the input and output of information of a buffer is using the FIFO circular method.
FIFO stands for "first-in-first-out". It defines that the "oldest" data that was stored in the buffer must be
the next to leave it. The buffer is finite and, for that reason, only a certain amount of information can be
stored within it at a certain time. Since the buffer has a limited capacity of storage, while data is entering
the buffer, there must be data leaving it. When an information is read from the sensor to the buffer, it
occupies a space in it. When an information is written from the buffer to the file, the space will be free to
store new data.
In a circular buffer, when the last input data is stored in the last free space of the buffer, the next free
space of the buffer will be its first. If an input has to enter a space which is not free yet, it must wait. If
data must be written data out of a space, but the space is free, the writing function must wait until data
enters. If the reading and writing processes access the same space at the same time it can cause data
corruption which will lead to incorrect information stored. In other words, concurrent access to a space
is not allowed.
43
Figure 6.2: Circular buffer representation.
To implement a shared circular buffer between two processes is not an easy task. Not only the buffer
must be shared, but also, each process must know which space of the buffer the other one is using. In
this case, a structure is shared that contains not only the buffer, but indicators such as the next available
space for input, the next available space for output, the number of occupied spaces, an indicator if the
buffer is empty, an indicator if the buffer is full and a condition lock variable that define if a process is
allowed to read or write. Each process can alter not only the buffer but also the indicators.
Multithreading allows the reading and the writing processes to run concurrently. Since the BPI-M3
contains an octa-core processor, the processes will run in different cores in parallel execution. In the
main DAQ program, each sensor program is executed concurrently with multithreading. The methods of
multithreading in the main DAQ program and the buffer handling are the same. There are two models
for multithreading:
• Cooperative multithreading
When two processes A and B are in cooperative multithreading, process A will start running. At a
certain point, this process will idle so that process B will run until it also idles. In other words, when
a process idles, the other is executed. The cooperative multithreading can run in a single core.
The main disadvantages about it are its complexity and the fact that this model is slower since it is
not using real concurrency.
• Preemptive multithreading
The operating system will preemptively give a process its processor to run. Therefore, the concur-
rency is real and the execution time is faster. If used in a single-core, the operating system will
schedule time periods for each process to run at a time, which means that the execution time is
slower.
44
Summarizing, each device must be initialized, as well as a shared buffer between the threads. After
that, each thread must run for a certain time. One thread acquires data and the other stores it. Buffer
indicators must be used to check the position of the buffer where data is being read to and where data
is being written from. When a timer reaches the end, the programs terminate.
The sampling period was implemented using a cycle with a time condition. While the time condition is
not met, the cycle can not end. When the cycle ends, the system can read the next value. The precision
of the sampling period can be affected by this condition because it takes time to check if it is met.
When a device program is executed, it creates a new storage file. This file is stored in the secondary
storage unit and must be numbered so that problems with file naming are avoided. To do that, in the
writing thread, before starting the writing process, a function is executed to find a name that does not
exist yet for the file.
The data acquisition program of each device is complex and challenging to implement, but it is fast and
robust.
Figure 6.3: Device program.
6.3.1 Analogue to Digital Converter
The I2C address of the ADC is manually configured directly on the hardware. There are eight available
addresses to use ranging from 0x68 to 0x6F. Since there are two ADCs per board, it is possible to use up
to four boards at the same time. Because the RTC uses an address within that range, it will be possible
to stack only up to three boards. The ADC uses a configuration byte with the register 0x9C. It is used to
set the channel, the conversion mode, the conversion rate, and the programmable gain amplifier. Since
there are multiple analogue sensors using several channels, this register must be changed at every
reading, which means that the device initialisation is made during the reading thread in every cycle and
not at the beginning of the device program. [19]
• Ready bit
45
Figure 6.4: Data reading thread.
Figure 6.5: Data writing thread.
It is located on the bit 7 of the register. It communicates if the last reading was updated or not. It
is only a readable bit.
• Channel bits
Channel bits are located in bits 5 and 6, to make it possible to select between four channels.
• Conversion mode
It is located in bit 4 and it states if the readings are done continuously or if it is done at command.
46
In the last case, between commands, the ADC would run at low power. The continuous conversion
was chosen.
• Sampling rate or resolution
The sampling rate and resolution are dependent on each other. their configuration is in bits 2 and
3, which allows four different scenarios: 240 SPS (12 bits), 60 SPS (14 bits), 15 SPS (16 bits)and
3.75 SPS (18 bits). The highest resolution (18 bits) was set.
• PGA
A programmable gain amplifier is located in bits 0 and 1. There are four possible programmable
gains: x1, x2, x4, x8. The gain chosen was x1.
6.3.2 MPU-9150
There are two possible I2C addresses for the MPU-9150. Their selection can be made manually directly
to the hardware. The configurations set to the MPU-9150 during initialization are the following: [20]
• Sampling frequency
Using the register 0x19, the gyroscope sampling rate was set to 1 kHz. The accelerometer’s
sample rate is already pre-defined as 1 kHz.
• Gyroscope range
There are four different ranges that can be controlled by bits 3 and 4 of the 0x1B register: ±250,
±500, ±1000 or ±2000o /sec (dps). The lowest range was set for best sensitivity.
• Accelerometer range
Four different ranges can be controlled by bits 3 and 4 of the 0x1C register: ±2g, ±4g, ±8g or
±16g. The lowest range was set for best sensitivity.
• Magnetometer
Since the bypass mode was activated, the magnetometer acts as an I2C slave directly to the
master. Its address is 0x0C.
• Measurement
the measurements are made from the registers 0x3B to 0x40 for the accelerometer, 0x43 to 0x48
for the gyroscope and 0x03 to 0x08 for the magnetometer.
47
48
Chapter 7
Calibration
When a manufacturer produces a sensor, he provides a relation between the measurement units (LSB
or voltage) and the measured phenomenon in standard units (e.g., Celsius degrees, g, degrees per
second, etc.). Sometimes, the manufacturer provides the coefficients for the calibration of a whole batch
of produced sensors, even though each sensor is unique, due to its sensitivity to the environment which
it was produced or works in. Although it reduces the sensor cost, the factory calibration may not be
the best fit, and further and more accurate calibration is needed. That is the case of the MPU-9150.
The purpose of this chapter is to present the calibration of the accelerometer and gyroscope, using a
pendulum and a mechanism to measure its angular position. The pendulum has a total height of 1.98
metres.
Figure 7.1: Pendulum.
49
7.1 Optical rotary encoder
At the top of the pendulum, in the axis of rotation, an optical rotary encoder was placed. The encoder is
a digital sensor that measures the angular position. The encoder used was the AEDB-9140. It consists
on a disc with several holes aligned circumferentially, near the edge. On one side of the disc, in a fixed
point near the edge, there is a LED light emitter. On the same place, but at the opposite surface of
the disc, there is an optical detector which transmits a signal of 3.3 V (high state) if it receives the light
and 0 V (low state) if it does not. The light and the detector are fixed while the disc is rotating. Since
every adjacent hole is equidistant, when the amount of states transitions (counts) is counted, the angular
displacement of the disc can be obtained.
Figure 7.2: Rotary optical encoder.
Adding a second light/detector pair with a phase delay of 90o , the direction of the rotation can be known.
Saying that channel A and channel B are phases separated by 90o , according to figures 7.2 and 7.3,
if B is delayed in relation to A, the disc is rotating clockwise. If A is delayed in relation to B, the disc is
rotating counter-clockwise. In the case of the AEDB-9140, the table 7.1 shows the relationship between
the channels sequence of states and the direction of the rotation (where 1 represents the high state and
0 represents the low state). The AEDB-9140 also has a third channel (CH C in figure 7.2) which was not
used. Its purpose is to send a pulse when the disc makes a full rotation (360o). The encoder disc rotates
along with a shaft that supports the pendulum. When the pendulum rotates, the shaft and consequently,
the disc will also rotate.
Clockwise
Ch A Ch B1 10 10 01 0
Counter-clockwise
Ch A Ch B1 11 00 00 1
Table 7.1: Relation between channel states sequence and rotation direction.
The resolution of the encoder is determined by the number of high states a channel can send in a signal
50
Figure 7.3: Channels A and B signals in counter-clockwise rotation.
per rotation (CPR). In other words, the number of holes the disc has on the edge. The AEDB-9140 has a
resolution of 500 CPR. To improve the resolution of the encoder, instead of counting only the ascending
flank (when the signal goes from low state to high state), the descending flank can also be counted.
This will double the resolution for each channel. Since two channels are being used the ascending and
descending flanks of both are counted, doubling the resolution again. Using this method, a resolution of
2000 CPR was reached. In other words, 0.18o per count.
The result of the measurement of the pendulum angular motion, when the pendulum is dropped from
a certain height, is a signal with the shape of a step sine wave (see figure 7.5). This shape does not
correspond to the reality of the pendulum motion and must be improved. In the step sine wave shaped
signal, only the first point after a flank transition corresponds to the real value of amplitude. These points
correspond to the left point in a constant band. All the other points between two consecutive flanks are
constant and false. For that reason, the first step is to collect all the angular positions correspondent to
the first points in a constant band. For an increased resolution, the false values must be replaced by an
approximation.
Defining the real angular position points as "left points", the approximation consists on a weighted av-
erage between two parabolic curves fitted for every n left points. For example, if an interval with n + 1
left points is gathered, the first n left points are approximated by one parabolic curve and the last n left
points with another parabolic curve. The number of left points n must be an odd number. This will create
a middle interval d, between two left points as seen in figure 7.4.
51
The parabola fit was created for the interval d using the Eq. (7.1). The left points were defined by
(x1; f1). The coefficients oa, b and c defining the parabola are given in descendent degree order. The
Eq. (7.1) is solved using the method in Eq. (7.2). Having calculated the coefficients for both parabolas,
the weights for each were determined using a shape function defined for the interval d from figure 7.4.
The new points were then calculated to replace the false ones. This process was repeated for every
n + 1 adjacent left points of the signal. The result for n = 7 can be seen in the figure 7.5.
26666664x1
2 x1 1
x22 x2 1
::: ::: :::
xn2 xn 1
3777777526664a
b
c
37775 =
26666664f1
f2
:::
fn
37777775 (7.1)
Ay = f ⇔ AT Ay = AT f (7.2)
Figure 7.4: Parabolization.
The parabolic fit presents a mean error of 9.59% and a standard deviation ff of 0.0153 radians. This can
be improved with a study that shows the impact of the number of points of the parabolization. This error
is also associated with the resolution of the encoder. The higher it is, the better will be the parabolization.
To obtain the angular velocity, the derivative of each parabolization at each interval d is calculated.
Deriving the parabolic function will amplify numerical noise. The numerical noise is higher when the
angular velocity is also high. This happens because the encoder signal is not a perfectly shaped as a
step sine wave. There is a time gap between each adjacent count. If the pendulum is moving fast, the
encoder, instead of producing a step sine wave shape, will generate a signal represented in 7.6. While
it might seem that this signal does not have noise, small and inevitable truncations and rounding during
data processing by the computer produce it, as seen in figure 7.7. When this signal is derived to obtain
the angular velocity, the noise will be amplified. Therefore, the Gaussian Sinc filter was used for the
angular velocity signal.
52
0.45 0.50 0.55 0.60 0.65time, [s] +1.43e2
0.21
0.22
0.23
0.24
0.25
0.26Am
plitu
de, [
radi
ans] Raw data
Parabolic fit
Figure 7.5: Smoothed and not smoothed step sine wave shape in pendulum motion.
Figure 7.6: Angular position from the encoder signal in fast motion.
7.2 Gyroscope
The gyroscope is calibrated using the angular velocity calculated with the encoder. The procedure
consists of dropping the pendulum from a certain height and measuring the encoder counts while the
gyroscope measures the angular velocity in the same direction as the pendulum rotation. The test only
finishes when the pendulum stops. Both measures must be taken at the same time. The sampling
frequency used was 400 Hz.
From the encoder, the angular velocity in radians per second is calculated. From the gyroscope, the
53
Figure 7.7: Difference between consecutive angular positions from the encoder signal in fast motion.
angular velocity in LSB is measured. The gyroscope signal was filtered with a Gaussian Sinc filter with
a window of 401 points, a cut-off frequency of 5.6% and a standard deviation of 0.5. Both signals must
be centred at zero. For each signal, two exponential functions that model the decay of the oscillation are
found, one for the lower peaks and another for the upper peaks. The two functions must be equidistant
to zero.
Then, it is possible to make a parabolic regression between the encoder angular velocity and the gy-
roscope values. To avoid small phase error between the two signals, only the peak values of each
were used for the regression. From there two sets of calibration coefficients are obtained (for the upper
peaks and lower peaks). Now, it is possible to calculate the average of each coefficient. As it is seen
in figures 7.8, 7.9 and 7.10, the second order coefficients of each regression have different signs, which
means that the average must be calculated for the absolute values. The calibration follows the Eq. (7.3)
where a, b and c are the coefficients in descending order of power and x and y is the not-calibrated and
calibrated values, respectively:
y = sign(x) a x2 + b x + c (7.3)
Although the datasheet presents a linear relationship between the angular velocity in LSB and de-
grees per second of 0.000133 rad/s/LSB, the fit made here was quadratic. The linear coefficient of
the quadratic fit is very close to the datasheet coefficient. If the regression were only linear, the errors
would be higher. The parabolic fit proved to be more successful. The last term of the calibration in Eqs.
(7.4), (7.5) and (7.6) has the objective of centring the data to remove the offset.
54
8000 6000 4000 2000 0 2000 4000 6000Uncalibrated gyroscope peaks, [rad/s]
1.5
1.0
0.5
0.0
0.5
1.0
1.5
2.0En
code
r ang
ular
velo
city
peak
s, [ra
d/s] Upper peaks regression:
a=1.35e-08, b=1.37e-04, c=-0.0031Lower peaks regression: a=-1.39e-08, b=1.35e-04, c=-0.0016Upper peaksLower peaks
Figure 7.8: X - peaks parabolic regression.
10000 5000 0 5000Uncalibrated gyroscope peaks, [rad/s]
2
1
0
1
2
3
Enco
der a
ngul
ar v
elocit
y pe
aks,
[rad/
s] Upper peaks regression: a=1.48e-08, b=1.33e-04, c=0.0029Lower peaks regression: a=-1.48e-08, b=1.33e-04, c=-0.0023Upper peaksLower peaks
Figure 7.9: Y - peaks parabolic regression.
„x = sign(e„x) 1:3727× 10−8 e„2x + 1:3586× 10−4 e„x − 7:6873× 10−4 − 0:0119 (7.4)
„y = sign(e„y ) 1:4779× 10−8 e„2y + 1:3274× 10−4 e„y − 2:7953× 10−4 + 0:0282 (7.5)
55
10000 5000 0 5000Uncalibrated gyroscope peaks, [rad/s]
2
1
0
1
2
3En
code
r ang
ular
velo
city
peak
s, [ra
d/s] Upper peaks regression:
a=1.42e-08, b=1.30e-04, c=0.0017Lower peaks regression: a=-1.42e-08, b=1.30e-04, c=-0.0032Upper peaksLower peaks
Figure 7.10: Z - peaks parabolic regression.
„z = sign(e„z) 1:4226× 10−8 e„2z + 1:2974× 10−4 e„z − 7:2401× 10−4 − 6:1785 10−5 (7.6)
7.3 Accelerometer
To calibrate the accelerometer an inclinometer was used to measure the inclination angle of the pendu-
lum in static positions. If the pendulum is static, the only force applied to the accelerometer is gravity.
The radial and tangential accelerations can be calculated using only trigonometric relations. For several
inclinations, the acceleration is obtained using Eqs. (7.7) and (7.8) (where „ is measured by the in-
clinometer) and using the MPU-9150. Making a linear regression between the calculated acceleration
and the accelerometer measurements, the accelerometer readings and the real accelerations can be
related.
The tables 7.2, 7.3 and 7.4 present the measurements of the inclinometer, the accelerometer readings
for the radial and tangential directions and the calculated accelerations using the Eqs. (7.7) and (7.8).
xrad = g cos „ (7.7)
xtan = g sin „ (7.8)
Making the linear regression, the results are in Eqs. (7.9), (7.10) and (7.11)
x = 5:9778× 10−5 ex − 0:0224 (7.9)
56
Tangential Direction„ [o ] -35.2 0 14.6 39.3 45.7ainclinometer [g ] -0.5736 0 0.2521 0.6334 0.7157aaccelerometer [LSB] -9230.1 202.8 4435.8 10679.6 12033.1
Radial Direction (negative X)„ [o ] -35 0.3 14.9 39.2 54.4 61.5ainclinometer [g ] -0.8192 -1.0000 -0.9664 -0.7749 -0.5821 -0.4772aaccelerometer [LSB] -13653.4 -16423.5 -15845.4 -12583.1 -9334.4 -7595.8
Table 7.2: X axis - inclination data.
Tangential Direction„ [o ] -35 0.3 14.9 39.2 54.4 61.5ainclinometer [g ] -0.5736 0.0052 0.2571 0.6320 0.8131 0.8788aaccelerometer [LSB] -9230.1 161.2 4485.7 10589.7 13532.1 14576.3
Radial Direction (negative Y)„ [o ] -35.3 0 14.7 39 43.3ainclinometer [g ] -0.8161 -1.0000 -0.9673 -0.7771 -0.7278aaccelerometer [LSB] -13523.0 -16456.0 -15876.4 -12696.2 -11880.0
Table 7.3: Y axis - inclination data.
Tangential Direction„ [o ] -35.3 0 14.7 39 43.3ainclinometer [g ] -0.5779 0 0.2538 0.6293 0.6858aaccelerometer [LSB] -8455.2 981.0 5251.2 11362.9 12283.4
Radial Direction„ [o ] -35.2 0 14.6 39.3 45.7ainclinometer [g ] 0.8171 1.0000 0.9677 0.7738 0.6984aaccelerometer [LSB] 14521.8 17371.3 16772.4 13476.0 12196.9
Table 7.4: Z axis - inclination data.
y = 6:0408× 10−5 ey − 0:0119 (7.10)
z = 5:9832× 10−5 ez − 0:0426 (7.11)
The linear regression itself already produces a coefficient for the zero order term that removes the
accelerometer offset. The sensitivity from the datasheet is 6:1035× 10−5 m/s2/LSB. It is very similar to
the sensitivities calculated (coefficient of the first order term in the Eqs. above).
As it is presented in figures 7.11, 7.12 and 7.13, the fitting errors and standard deviations ff are relatively
low. This calibration has the disadvantage of using a small number of points for the fit.
57
15000 10000 5000 0 5000 10000Acceleration, [LSB]
1.0
0.5
0.0
0.5
1.0
Acce
lerati
on, [
g]
Linear fit: m=5.9778e-05, b=-0.0224Calculated acceleration
Figure 7.11: X - calibrated accelerometer fit.
15000 10000 5000 0 5000 10000 15000Acceleration, [LSB]
1.0
0.5
0.0
0.5
1.0
Acce
lerati
on, [
g]
Linear fit: m=6.0408e-05, b=-0.0119Calculated acceleration
Figure 7.12: Y - calibrated accelerometer fit.
58
5000 0 5000 10000 15000Acceleration, [LSB]
0.5
0.0
0.5
1.0
Acce
lerati
on, [
g]
Linear fit: m=5.9832e-05, b=-0.0426Calculated acceleration
Figure 7.13: Z - calibrated accelerometer fit.
59
60
Chapter 8
Results
This chapter presents the results and discussion of the filter, calibration and the performance of the DAQ
system.
8.1 Filter Implementation
The signals are saved in a comma-separated-values file. This means that the first step is selecting the
signal to filter and import it.
The three parameters of the filter must be chosen. A cut-off frequency (proportional to ¸) too high
can remove important information while if it is too low, the noise might not be well attenuated. The
window size is also very important. A large window allows a better roll-off performance. It is important to
maintain the standard deviation in a low value since if it is high, it can cause the filter to behave simply
as a truncated sinc filter. These parameters were found after multiple attempts to produce a filtered
signal which is the closest to the expected. The response of the designed filter with the Eq. (4.51), for
a window of 401 points can be seen in the figure 8.1. The ¸ coefficient is 5.6, and the parameter for
standard deviation ff is 0.5.
Another essential step is to remove the sensors offset. Since the filtered signal corresponds to the
oscillation of a pendulum (Chapter 7) used for the MPU-9150 calibration, these oscillations must be
centred at zero. One way to centre the data is to subtract the signal by its average. A more precise
way, used specifically in the pendulum case consists of finding a function that models the decay of the
oscillation amplitude peaks in time. This must be done both for the upper peaks and lower peaks. The
results can be fitted in two exponential functions (upper and lower) which must be equidistant from zero
in each point.
Now the signal is ready for the convolution with the filter coefficients calculated earlier. The convolution
will blend the filter and the data signals and produce the filtered signal. From the figure 8.3, it is possible
to realize that the filtered data was successful. figure 8.3(b) shows that the data is well filtered.
Representing the filtered signal in frequency domain, the frequencies that define the pendulum motion
should have a high amplitude. On the other hand, the frequencies at which the noise happens should
61
0 10 20 30 40 50 60frequency, [Hz]
10 7
10 6
10 5
10 4
10 3
10 2
10 1
100
101Ga
in, [
-]Gaussian Sinc filter: fs = 400.0, = 5.6, = 0.50, W=401
Figure 8.1: Filter response.
0 50 100 150 200 250 300 350time, [s]
3000
2000
1000
0
1000
2000
3000
Angu
lar v
elocit
y, [L
SB]
Figure 8.2: Centred data.
have a lower amplitude. Figure 8.4 shows that for frequencies between approximately 0.3 Hz to 0.6 Hz,
the amplitudes are very high. This band defines the pendulum motion. The other frequencies present
very low amplitudes. This means that the noise amplitudes are very low. From this figure, it is possible
to observe that the signal to noise ratio (SNR) is very high.
62
0 100 200 300 400 500 600time, [s]
10000
5000
0
5000
10000An
gular
velo
city,
[LSB
]raw datafiltered
(a) Full signal
0.50 0.55 0.60 0.65 0.70time, [s] +6.6e1
6800
6850
6900
6950
7000
Angu
lar v
elocit
y, [L
SB]
raw datafiltered
(b) Detailed view
Figure 8.3: Filtered and unfiltered data comparison.
8.2 Calibration
8.2.1 Gyroscope
During calibration, the most precise relation between the angular velocity calculated from the encoder
and the measurements from the gyroscope is quadratic (almost linear). Since the calibration was made
only using the peak points of each signal, it is possible to compare all the points of the calibrated signal
and of the angular velocity calculated from the encoder.
The method to obtain the results consisted of raising the pendulum to an amplitude of roughly 30o and
dropping it. With the encoder, the angular position is measured. After the parabolization of the en-
63
0 1 2 3 4 5frequency, [Hz]
0
200
400
600
800
1000
1200Am
plitu
de, [
LSB]
|a| (half spectrum)
(a) Full signal
0 1 2 3 4frequency, [Hz]
0.0
0.2
0.4
0.6
0.8
Ampl
itude
, [LS
B]
|a| (half spectrum)
(b) Detailed view
Figure 8.4: Filtered data in frequency domain.
coder left points, presented in section 7.1, its derivative represents the angular velocity. The results are
presented in figures 8.5 to 8.7. Small errors and standard deviations ff were calculated. The error of
the gyroscope calibration was 1.43% for the x axis, 1.62% for the y axis and 1.7% for the z axis. The
standard deviation of the gyroscope calibration was 0.0063 rad/s for the x axis, 0.0090 rad/s for the y
axis and 0.0066 rad/s for the z axis. Given these results, it is possible to say that the calibration of the
gyroscope was successful.
64
10 11 12 13 14 15time, [s]
1.5
1.0
0.5
0.0
0.5
1.0
1.5An
gular
Velo
city,
[rad
/s]Encoder angular velocityCalibrated gyroscope
(a) Comparison
10.6 10.7 10.8 10.9 11.0 11.1 11.2 11.3time, [s]
1.6
1.5
1.4
1.3
1.2
1.1
1.0
Angu
lar V
elocit
y, [r
ad/s]
Encoder angular velocityCalibrated gyroscope
(b) Detailed view
Figure 8.5: X - calibrated gyroscope and encoder angular velocity comparison.
8.2.2 Accelerometer
The figures 7.11, 7.12 and 7.13 were obtain by aligning each axis with the vertical direction. The value
of acceleration, in this case, must be 1 g (or -1 g if the axis is pointing downwards). For that reason,
the acceleration can be measured with the accelerometer and compared with the expected value. The
error is relatively low. This method, as stated previously, has the disadvantage of using a small number
of points for the fit. On the other hand, this method produces values very close from the expected. The
measurements in the x vertical axis showed an error of 0.42 %. For the y vertical axis, the error is 0.60
%. For the z vertical axis, the error is 0.30 %.
65
8 9 10 11 12 13time, [s]
2
1
0
1
2An
gular
Velo
city,
[rad
/s]Encoder angular velocityCalibrated gyroscope
(a) Comparison
8.8 8.9 9.0 9.1 9.2 9.3 9.4time, [s]
2.1
2.0
1.9
1.8
1.7
1.6
1.5
Angu
lar V
elocit
y, [r
ad/s]
Encoder angular velocityCalibrated gyroscope
(b) Detailed view
Figure 8.6: -Y - calibrated gyroscope and encoder angular velocity comparison.
8.3 DAQ system
The DAQ system will produce a csv file with all the measurements. The time when the measures start
and the frequency of sampling along with the legend of each measurement are included in the file. The
sensitivities used for the gyroscope and accelerometer were the ones calculated in calibration. For the
humidity and temperature sensors, the datasheet sensitivity was used.
66
7 8 9 10 11 12time, [s]
2
1
0
1
2
Angu
lar V
elocit
y, [r
ad/s]
Encoder angular velocityCalibrated gyroscope
(a) Comparison
8.1 8.2 8.3 8.4 8.5time, [s]
2.3
2.2
2.1
2.0
1.9
Angu
lar V
elocit
y, [r
ad/s]
Encoder angular velocityCalibrated gyroscope
(b) Detailed view
Figure 8.7: Z - calibrated gyroscope and encoder angular velocity comparison.
67
0 5 10 15 20 25 30time, [s]
0.04
0.02
0.00
0.02
0.04
Acce
lerati
on, [
g]
1
Calibrated dataTrue data
Figure 8.8: -x vertical axis acceleration measurement.
0 2 4 6 8 10time, [s]
0.06
0.04
0.02
0.00
0.02
0.04
Acce
lerati
on, [
g]
1
Calibrated dataTrue data
Figure 8.9: -y vertical axis acceleration measurement.
68
0 2 4 6 8 10 12 14time, [s]
0.010
0.008
0.006
0.004
0.002
0.000
0.002
0.004
Acce
lerati
on, [
g]
+1
Calibrated dataTrue data
Figure 8.10: z vertical axis acceleration measurement.
69
70
Chapter 9
Conclusions
During the present thesis, it was successfully developed and implemented a low-cost data acquisition
system for an oceanographic monitoring buoy. It required insight about electronic circuits, programming,
computer operations, mechanical physics, and signal processing.
The first task was to acquire knowledge about how a data acquisition system works and its main compo-
nents. Given the amount of possible hardware and concepts that can be used in a DAQ system, it can
be said that the one built in this project has some complexity. The assembly of the equipment allowed
the understanding of how each component works and how the circuitry among them must be.
The second task was to select the hardware that would fulfil the requirements. For example, the de-
velopment board should have a SATA port to connect it to a secondary storage unit. The price of the
components and their performance, such as the resolution of the Analogue-to-Digital converter were,
obviously, of prime importance.
The third task consisted in developing the necessary programs for the system to acquire data. For the
data acquisition, the program should perform two functions at the same time: one for acquiring the data
and the other to store it in a hard disk. Although this seems a common and trivial task, it is not the
case for a remote system that aims to be failure free to hardware problems, such as interruption of
the electrical supply. The task allowed a better understanding of how the processor and the random
access memory work. On the other side, it rose a problem: the two functions were trying to access the
same memory addresses at the same time. The concurrency problem was solved using a circular buffer
queue. The languages used for the data acquisition processes were “C” and “Bash Script” which are
very related to the operations made by the hardware. The post-processing of the signals was handled
by Python and Matlab programs, because of their libraries which allow complex manipulation of data.
The fourth task consisted on preventing data loss by a system corruption. Since the buoy will have to
support harsh environmental conditions, it was also critical to make the system robust and prevent the
long distance communications with the ODAS from being lost. Several possible solutions were possible,
but the one that was executed consisted of giving the attribute read-only to the filesystem. If there is an
improper shutdown, since the filesystem is not changing the logical boundaries of the files, there will be
a data corruption no longer.
71
After acquiring data, the noise was an important issue to address. The first step was to understand the
sources of noise. The second step was to design and use a filter. Understanding how a filter works
and how the convolution is implemented was very important. The sinc filter with a Gaussian window
was selected to remove the signal’s noise. However, this was not the first choice. The filter selection
process started with a study of the Savitzky-Golay filters. These filters have a computations can be very
unstable. For that reason, Legendre-based filters were also addressed, but they did not have the best
performance. The solution was to make a cascade filter out of elementary Legendre-based filters. The
result was very good. Because the shape of the recursive filter was very similar to a sinc function, a sinc
filter implementation was tried. Due to the fact that a sinc filter must be windowed to be implemented,
its response caused overshoots and undershoots in the passband which prevented it from performing
as an ideal filter. To overcome this issue, a convolution with a Gauss window was made. The result was
very similar to the Legendre-based cascade filter. The transition band was narrower, and the attenuation
difference between the two filters was negligible. And thus, the Gaussian Sinc filter was preferred since
it is faster and more straightforward to implement.
Finally, after having the signals filtered, the next issue to address was the accuracy of the parameter
measurements. There is a relation between the readings and the actual property given by the manu-
facturer. The problem is the fact that sensors are made in batches, and the factory calibration might
not be the best one. The sensors which were calibrated were a gyroscope and an accelerometer. The
calibration method lies on the fact that, knowing the angular position of a pendulum as a function of the
time one can calculate its acceleration and angular velocity. The sensors were placed at the tip of the
pendulum. The angular position was measured with an encoder. Being an encoder a digital sensor, it
has an error associated with it, which, in this case, was very high. For that reason, the data received
from it was improved. The gyroscope was calibrated using the encoder in the moving pendulum and
deriving the angular position to obtain the velocity. To calibrate the accelerometer an inclinometer was
used to measure the angular amplitude of the pendulum at different static positions. In this case, the
calibration can be performed using only gravity terms.
9.1 Achievements
This project achieved an innovative product for data acquisition systems. It uses low-cost components,
which gives it some competitiveness advantage in relation to other types of ODAS in the market. Its
objective is to be a system that can acquire data in any remote place. Because it uses small components,
it can fit easily in any place, and its transportation and installation are simple. The system was designed
to be very flexible and allow the integration of more analogue sensors.
A Gaussian Sinc filter was selected and showed excellent results. This filter provides a very good
attenuation and a fast response.
A method of improving the digital resolution of a signal was implemented with the angular position
acquired from the encoder. It produced a good fit with the potential to be improved.
The calibration of the gyroscope and accelerometers allowed an increase of the accuracy of the mea-
72
surements. This makes the DAQ system more reliable.
In the future, a wider variety of sensors should be integrated into the system. The system was designed
to be modular and easily allow the integration of analogue sensors. The calibration can be improved
with a study of the impact of the humidity, temperature and power supply on the measurements.
73
74
Bibliography
[1] A. F. Falcão and J. C. Henriques. Oscillating-water-column wave energy converters and air turbines:
A review. Renewable Energy, 85:1391–1424, 2016.
[2] I. O. C. Group of Experts on the Legal Status of Ocean Data Acquisition Systems. Preliminary draft
convention on ocean data acquisition systems (ODAS). In Preparatory Conference of Governmen-
tal Experts to Formulate a Draft Convention on the Legal Status of ODAS. UNESCO, 1972.
[3] A. F. Falcão. Modelling of Wave Energy Conversion. Instituto Superior Técnico, Universidade de
Lisboa, 2014.
[4] T. V. Heath. A review of oscillating water columns. Philosophical Transactions of the Royal Society
of London A: Mathematical, Physical and Engineering Sciences, 370(1959):235–245, 2012.
[5] Joint Technical Commission for Oceanography and Marine Meteorology (JCOMM). ODAS (Ocean
Data Acquisition System) Metadata Format. Technical report, Expert Team on Marine Climatology,
2002.
[6] S. Mackay, E. Wright, and J. Park. Practical Data Communications for Instrumentation and Control.
Practical professional books from Elsevier. Elsevier Science, 2003. ISBN 9780080473802.
[7] J. Sons. Sensors and Signal Conditioning, 2nd Ed, 2001: Sensors and Signal. Sensors and Signal
Conditioning. Wiley, 2001. ISBN 9780471332329.
[8] M. Mataric, N. Koenig, and R. Arkin. The Robotics Primer. Intelligent Robotics and Auton. Cam-
bridge University Press, 2007. ISBN 9780262633543.
[9] M. Bao. Analysis and Design Principles of MEMS Devices. Elsevier Science, 2005. ISBN
9780080455624.
[10] A. Sharma, F. M. Zaman, B. V. Amini, and F. Ayazi. A high-q in-plane soi tuning fork gyroscope. In
SENSORS, 2004 IEEE, pages 467–470 vol.1, Oct 2004. doi: 10.1109/ICSENS.2004.1426201.
[11] A. Savitzky and M. J. E. Golay. Smoothing and differentiation of data by simplified least squares
procedures. Analytical Chemistry, 36(8):1627–1639, 1964. doi: 10.1021/ac60214a047.
[12] P.-O. Persson and G. Strang. Smoothing by savitzky-golay and legendre filters. In J. Rosenthal and
D. S. Gilliam, editors, Mathematical Systems Theory in Biology, Communications, Computation,
and Finance, pages 301–315, New York, NY, 2003. Springer New York.
75
[13] I. W. and K. Z. On the legendre-based filters of persson and strang. Applied Mathematics and
Computation, 218(8):4216 – 4233, 2011. ISSN 0096-3003. doi: https://doi.org/10.1016/j.amc.
2011.09.053.
[14] J. Durão. Desenvolvimento de um Ondógrafo. Master’s thesis, Instituto Superior Técnico, 2011.
[15] M. Spiegel. Schaum’s Outline of Theory and Problems of Fourier Analysis, with Applications to
Boudary Value Problems. Schaum’s outline series. McGraw-Hill, 1974. URL https://books.
google.pt/books?id=TvBMnQAACAAJ.
[16] S. W. Smith. The Scientist and Engineer’s Guide to Digital Signal Processing. California Technical
Publishing, San Diego, CA, USA, 1997. ISBN 0-9660176-3-3.
[17] L. Wirzenius, J. Oja, S. Stafford, and A. Weeks. The linux system administrator’s guide. Version
0.9.
[18] K3A. How to make RaspberryPi truly read-only, reliable and trouble-
free. Internet user’s personal website. URL https://k3a.me/
how-to-make-raspberrypi-truly-read-only-reliable-and-trouble-free/.
[19] Microchip. MCP3422/3/4 18–bit, Multi–Channel Analog–to–Digital Converter with I2C Interface and
On–Board Reference. Datasheet.
[20] IvenSense. MPU–9150 Product Specification Revision 4.3. Datasheet.
76
Appendix A
Programs
A.1 Main DAQ program in bash script
# The purpose of this code is to control every sensor activity.#It also controls the loop DataAcquisition/reboot
# The priority information for the script to be executed from init.d must be presented as below#!/bin/bash### BEGIN INIT INFO# Provides: ini.sh# Required -Start: $remote_fs $syslog# Required -Stop: $remote_fs $syslog# Default -Start: 2 3 4 5# Default -Stop: 0 1 6# Short -Description: Start daemon at boot time# Description: Enable service provided by daemon.### END INIT INFO
#Set the date to the system/home/pi/Instruments/RTC/read -date
#Change filesystem to read -onlyro
#Start all programs/home/pi/Instruments/MPU -9150/ main_mpu &/home/pi/Instruments/ADC/ADC &
# Set the pin for input for reboot condition to act as a physical switchgpio mode 28 in
ro
while truedo#check if MPU -9150 is runningif pgrep main_mpu >/dev/null 2>&1then
# MPU -9150 is runningecho "running"
else
#check if ADC is runningif pgrep ADC >/dev/null 2>&1then
# ADC is runningecho "running"
else# all programs are finished#read pin 28wpi (48 bpi) - interrupt is high (1) by defaultb=$(gpio read 28)echo "not running"if [ $b == 1 ]then
roecho "$b no reboot" # The physical switch is turned off
breakelse
roecho "$b reboot" # The physical switch is turned on
breakfi
fi
fidone
77
A.2 MPU-9150
A.2.1 Main MPU-9150 program
/*This program consists on a circular buffer implemented with multithread to acquire data from theMPU -9150. It must be compiled with MPU -9150 functions , which contains the functions toconfigure the sensor , read the measurements and handle errorsThe programming of this code was inspired in:http ://www.cs.fsu.edu/~baker/realtime/restricted/examples/prodcons/prodcons.cand: http ://icube -avr.unistra.fr/en/index.php/I2C_communication_between_RPI_and_MPU9150*/
#include <stdio.h>#include "MPU -9150.h"#include <stdint.h>#include <stdlib.h>#include <sys/time.h>#include <time.h>#include <math.h>
#define BSIZE 32 // Define buffer size#define BNUM 6
/* Shared buffer structure */typedef struct shared_buffer {
int data[BNUM][ BSIZE]; /* Array to store accelerometer and gyroscope data */double datam [3][ BSIZE]; /* Array to store magnetometer data */pthread_mutex_t lock; /* protects the buffer */pthread_cond_t /* the POSIX condition variable type */new_data_cond , /* to wait when the buffer is empty */new_space_cond; /* to wait when the buffer is full */int next_in , /* next available space for input */next_out , /* next available space for output */count; /* the number of spaces occupied */
} shared_buffer_t;
/* Initialize buffer counters */void sb_init(shared_buffer_t *sb){
sb ->next_in = sb->next_out = sb->count = 0;pthread_mutex_init (&sb->lock , NULL);pthread_cond_init (&sb->new_data_cond , NULL);pthread_cond_init (&sb->new_space_cond , NULL);
}
int find_file () {/* The files that this program writes for the storage of acquired data are numbered. Thisfunction defines the number of the next file to be written */
uint16_t i;i=1;FILE * fid [1000];
while (1) {char *file_name;int numdigits = log10(i) + 1;file_name = (char *) malloc(numdigits + 27);
/* The folder BPIdrive is stored in a storage unit different from theoperating system */
sprintf(file_name , "/home/pi/BPIdrive/mpu -%d.csv", i);fid[i] = fopen(file_name , "r");
/* If fid is not null , the number of the file already exists */if (fid[i] == NULL) {
return i;}
i += 1;}
}
void * producer( void * arg ) {/* This function acquires data to the buffer */
int ret;int k = 0;struct timeval ti , tf;int elapsedTime;shared_buffer_t *sb = (shared_buffer_t *) arg;pthread_mutex_lock (&sb->lock);
/* Set the total time for data acquisition */time_t secs = 60; // 60 secondstime_t startTime = time(NULL);while (time(NULL) - startTime < secs) {
elapsedTime = 0;gettimeofday (&ti, NULL);
/* Wait for the communication with the buffer space to be allowed */while (sb->count == BSIZE)
pthread_cond_wait (&sb->new_space_cond , &sb ->lock);pthread_mutex_unlock (&sb->lock);k = sb ->next_in;
/* Read data from the MPU -9150 */ret = imupi_read( &sb->data [0][k], &sb ->data [1][k], &sb->data [2][k], &sb->data [3][k],&sb ->data [4][k], &sb->data [5][k], &sb ->datam [0][k], &sb->datam [1][k],
78
&sb ->datam [2][k]);if ( ret ) {
mpu_read_error(ret);}
/* Update the buffer indicators */sb->next_in = (sb ->next_in + 1) % BSIZE; // Circular buffer using bitwise 'and'pthread_mutex_lock (&sb->lock);sb->count ++;pthread_cond_signal (&sb->new_data_cond );
while(elapsedTime < 2500) { // 2.5ms data acquisition period (400 Hz)gettimeofday (&tf, NULL);// compute and print the elapsed time in millisecelapsedTime = (tf.tv_sec - ti.tv_sec) * 1000000; // sec to mselapsedTime += (tf.tv_usec - ti.tv_usec );
}}return NULL;
}
void * consumer(void *arg) {/* This function writes data from the buffer to a file */
/* Create the data file for storage */uint16_t filenum;filenum = find_file ();int numdigits = log10(filenum) + 1;char *file_name;file_name = (char *) malloc(numdigits + 27);sprintf(file_name , "/home/pi/BPIdrive/mpu -%d.csv", filenum );FILE *fid = fopen(file_name , "w");if (fid == NULL) {
printf("Error opening file\n");exit (1);
}
int k = 0;shared_buffer_t *sb = (shared_buffer_t *) arg;pthread_mutex_lock (&sb->lock);
/* Set the total time for data storage */time_t secs = 61; // 61 secondstime_t startTime = time(NULL);struct tm tm = *localtime (& startTime );
/* Write date and time and sampling frequency */fprintf(fid , "%04d-%02d-%02d %02d:%02d:%02d, Freq = 400Hz\nax ,ay ,az,gx,gy ,gz ,mx,my,mz\n",tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday , tm.tm_hour , tm.tm_min , tm.tm_sec );
while (time(NULL) - startTime < secs) {
while (sb->count == 0)/* Wait for the communication with the buffer space to be allowed */pthread_cond_wait (&sb->new_data_cond , &sb->lock);
pthread_mutex_unlock (&sb->lock);k = sb ->next_out;
/* Write data from buffer to file */fprintf(fid , "%f,%f,%f,%f,%f,%f,%f,%f,%f\n", (float) sb->data [0][k],(float) sb ->data [1][k], (float) sb->data [2][k], (float) sb->data [3][k],(float) sb ->data [4][k], (float) sb->data [5][k], (float) sb->datam [0][k],(float) sb ->datam [1][k], (float) sb->datam [2][k] );fflush(stdout );
/* Update the buffer indicators */sb->next_out = (sb ->next_out + 1) % BSIZE; // Circular buffer using bitwise 'and'pthread_mutex_lock (&sb->lock);sb->count --;pthread_cond_signal (&sb->new_space_cond );
}fclose(fid);return NULL;
}
int main() {
// Initialization of the MPU -9150int ret;if ( ret = imupi_init( ) ) {
mpu_init_error(ret);}
/* Initialize buffer */shared_buffer_t sb; // the buffersb_init (&sb);
/* Create and start threads */pthread_t th1 , th2; // the two thread objectspthread_create (&th1 , NULL , producer , &sb);pthread_create (&th2 , NULL , consumer , &sb);sleep (70);
/* Join threads */printf("%d %d\n", pthread_join(th1 , NULL), pthread_join(th2 , NULL ));return 0;
}
79
A.2.2 MPU-9150 functions
/*Adapted from: http ://icube -avr.unistra.fr/en/index.php/I2C_communication_between_RPI_and_MPU9150This program contains the functions to configure the sensor , read the measurements and handleerrors*/
#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <time.h>#include <linux/i2c -dev.h>#include "MPU -9150.h"
int imupi_dev = -1;unsigned char mpu_9150_address = MPU_9150_I2C_ADDRESS_1; // I2C address
/** imupi_init: initialize the board registers.*/
int imupi_init( void ){
int dummy_ax , dummy_ay , dummy_az , gx, gy, gz;double dummy_mx , dummy_my , dummy_mz;int ret , i;
/* Open I2C device */
imupi_dev = open( IMUPI_DEVNAME , O_RDWR );if ( imupi_dev == -1 )
return IMUPI_I2C_OPEN_ERROR;
/* Initialize Invensens board */
/* Initialize accelerometer and gyro */
if ( ioctl( imupi_dev , I2C_SLAVE , mpu_9150_address ) < 0 ) {mpu_9150_address = MPU_9150_I2C_ADDRESS_2;if ( ioctl( imupi_dev , I2C_SLAVE , mpu_9150_address ) < 0 )
return IMUPI_I2C_DEV_NOT_FOUND;}
// 1 kHz sampling rate: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_SMPRT_DIV , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// No ext sync , DLPF at 184Hz for the accel and 188Hz for the gyro: 0b00000001if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_DEFINE , 0x01 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// Gyro range at +/ -250 deg/s: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_GYRO_CONFIG , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// Accel range at +/-2g: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_ACCEL_CONFIG , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// Disable all FIFOs: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_FIFO_EN , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// Bypass mode enabled: 0b00000010if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_INT_PIN_CFG , 0x02 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// Disable all interrupts: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_INT_ENABLE , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// No FIFO and no I2C slaves: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_USER_CTRL , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
// No power management , internal clock source: 0b00000000if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_PWR_MGMT_1 , 0x00 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
/* Initialize magnetometer */
if ( ioctl( imupi_dev , I2C_SLAVE , MPU_9150_I2C_MAGN_ADDRESS ) < 0 )return IMUPI_I2C_DEV_NOT_FOUND;
// Check for the AKM device IDret = i2c_smbus_read_byte_data( imupi_dev , MPU_9150_WIA );if ( ret < 0 )
return IMUPI_I2C_READ_ERROR;if ( ret != MPU_9150_AKM_ID )
return IMUPI_I2C_DEV_NOT_FOUND;
// Single measurement mode: 0b00000001
80
if ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_CNTL , 0x01 ) == -1 )return IMUPI_I2C_WRITE_ERROR;
/* Give some time to the chip to initialize */
usleep( 100000 );
/* Test data reading */
if ( imupi_read( &dummy_ax , &dummy_ay , &dummy_az , &gx, &gy , &gz, &dummy_mx , &dummy_my ,&dummy_mz ) )return IMUPI_INIT_ERROR;
return IMUPI_NO_ERROR;}
/** imupi_terminate: close i2c device.*/
void imupi_terminate( void ) {
if ( imupi_dev != -1 ) {close( imupi_dev );imupi_dev = -1;
}}
/** imupi_read: read all sensor values on the board and return them as double.*/
int imupi_read( int *ax , int *ay, int *az , int *gx, int *gy , int *gz, double *mx, double *my,double *mz ) {
uint8_t block[IMUPI_BLOCK_SIZE ];int ret , i;
static double last_m [3] = { 0.0, 0.0, 0.0 };static int mag_state = 0;static uint8_t mblock[IMUPI_BLOCK_SIZE] = { 0, 0, 0, 0, 0, 0 };//*ax = *ay = *gz = 0.0; //a[2] = g[0] = g[1] = 0
if ( imupi_dev == -1 )return IMUPI_INIT_ERROR;
/* Read accelerations */
if ( ioctl( imupi_dev , I2C_SLAVE , mpu_9150_address ) < 0 )return IMUPI_I2C_DEV_NOT_FOUND;
if ( i2c_smbus_read_i2c_block_data( imupi_dev ,IMUPI_I2C_AUTO_INCREMENT | MPU_9150_ACCEL_XOUT_H ,IMUPI_BLOCK_SIZE , block ) != IMUPI_BLOCK_SIZE )
return IMUPI_I2C_READ_ERROR;
*ax = /*(double)*/( (int16_t )( block [0] << 8 | block [1] ) ) ;*ay = /*(double)*/( (int16_t )( block [2] << 8 | block [3] ) ) ;*az = /*(double)*/( (int16_t )( block [4] << 8 | block [5] ) ) ;
/* Read gyro */
if ( i2c_smbus_read_i2c_block_data( imupi_dev ,IMUPI_I2C_AUTO_INCREMENT | MPU_9150_GYRO_XOUT_H , IMUPI_BLOCK_SIZE ,block ) != IMUPI_BLOCK_SIZE )
return IMUPI_I2C_READ_ERROR;
*gx = /*(double)*/( (int16_t )( block [0] << 8 | block [1] ) ) ;*gy = /*(double)*/( (int16_t )( block [2] << 8 | block [3] ) ) ;*gz = /*(double)*/( (int16_t )( block [4] << 8 | block [5] ) ) ;
/* Read magnetometer */
if ( ioctl( imupi_dev , I2C_SLAVE , MPU_9150_I2C_MAGN_ADDRESS ) < 0 )return IMUPI_I2C_DEV_NOT_FOUND;
/* Read sequentially X, Y and Z to avoid too long delays */
switch( mag_state ) {
case 0:// Check if data is ready.
ret = i2c_smbus_read_byte_data( imupi_dev , MPU_9150_ST1 );
if ( ret < 0 )return IMUPI_I2C_READ_ERROR;
if ( ret & 0x01 ) {mag_state = 1;
}
// Duplicate last measurements*mx = last_m [0];*my = last_m [1];*mz = last_m [2];break;
81
case 1:// Read X axis
for ( i = 0; i < 2; i++ ) {ret = i2c_smbus_read_byte_data( imupi_dev , MPU_9150_HXL + i );if ( ret < 0 )
return IMUPI_I2C_READ_ERROR;mblock[i] = ret;
}mag_state = 2;
// Duplicate last measurements*mx = last_m [0];*my = last_m [1];*mz = last_m [2];break;
case 2:// Read Y axis
for ( i = 2; i < 4; i++ ) {ret = i2c_smbus_read_byte_data( imupi_dev , MPU_9150_HXL + i );if ( ret < 0 )
return IMUPI_I2C_READ_ERROR;mblock[i] = ret;
}mag_state = 3;
// Duplicate last measurements*mx = last_m [0];*my = last_m [1];*mz = last_m [2];break;
case 3:// Read Z axis
for ( i = 4; i < 6; i++ ) {ret = i2c_smbus_read_byte_data( imupi_dev , MPU_9150_HXL + i );if ( ret < 0 )
return IMUPI_I2C_READ_ERROR;mblock[i] = ret;
}
*my = (double )( (int16_t )( mblock [1] << 8 | mblock [0] ) *IMUPI_M_GAIN );
*mx = (double )( (int16_t )( mblock [3] << 8 | mblock [2] ) *IMUPI_M_GAIN );
*mz = -(double )( (int16_t )( mblock [5] << 8 | mblock [4] ) *IMUPI_M_GAIN );
last_m [0] = *mx;last_m [1] = *my;last_m [2] = *mz;
// Re -arm single measurement modeif ( i2c_smbus_write_byte_data( imupi_dev , MPU_9150_CNTL , 0x01 ) == -1 )
return IMUPI_I2C_WRITE_ERROR;
mag_state = 0;break;
default:mag_state = 0;
}
return IMUPI_NO_ERROR;}
/* Initialization error handling */void mpu_init_error(int ret) {
switch( ret ) {case IMUPI_NO_ERROR:
break;
case IMUPI_I2C_OPEN_ERROR:fprintf (stderr , "Unable to open I2C device .\n" );exit( EXIT_FAILURE );
case IMUPI_I2C_DEV_NOT_FOUND:fprintf (stderr , "Device not found .\n" );exit( EXIT_FAILURE );
case IMUPI_I2C_WRITE_ERROR:fprintf (stderr , "I2C write error.\n" );exit( EXIT_FAILURE );
default:fprintf (stderr , "Initialization errror .\n" );exit( EXIT_FAILURE );
}}
/* Read error handling */void mpu_read_error(int ret) {
switch( ret ) {case IMUPI_NO_ERROR:
break;
82
case IMUPI_INIT_ERROR:fprintf (stderr , "Trying to read an uninitialized device .\n" );exit( EXIT_FAILURE );
case IMUPI_I2C_DEV_NOT_FOUND:fprintf (stderr , "Device not found .\n" );exit( EXIT_FAILURE );
case IMUPI_I2C_READ_ERROR:fprintf (stderr , "I2C read error.\n" );exit( EXIT_FAILURE );
default:fprintf (stderr , "Read errror .\n" );exit( EXIT_FAILURE );
}}
A.2.3 MPU-9150 registers
/*Definitions for Invensense MPU -9150.Adapted from: http ://icube -avr.unistra.fr/en/index.php/I2C_communication_between_RPI_and_MPU9150*/
#ifndef _MPU_9150_H_#define _MPU_9150_H_
#define MPU_9150_I2C_ADDRESS_1 0x69 // Base address of the Drotek board#define MPU_9150_I2C_ADDRESS_2 0x68 // Base address of the SparkFun board#define MPU_9150_SMPRT_DIV 0x19 // Gyro sampling rate divider#define MPU_9150_DEFINE 0x1A // Gyro and accel configuration#define MPU_9150_GYRO_CONFIG 0x1B // Gyroscope configuration#define MPU_9150_ACCEL_CONFIG 0x1C // Accelerometer configuration#define MPU_9150_FIFO_EN 0x23 // FIFO buffer control#define MPU_9150_INT_PIN_CFG 0x37 // Bypass enable configuration#define MPU_9150_INT_ENABLE 0x38 // Interrupt control#define MPU_9150_ACCEL_XOUT_H 0x3B // Accel X axis High#define MPU_9150_ACCEL_XOUT_L 0x3C // Accel X axis Low#define MPU_9150_ACCEL_YOUT_H 0x3D // Accel Y axis High#define MPU_9150_ACCEL_YOUT_L 0x3E // Accel Y axis Low#define MPU_9150_ACCEL_ZOUT_H 0x3F // Accel Z axis High#define MPU_9150_ACCEL_ZOUT_L 0x40 // Accel Z axis Low#define MPU_9150_GYRO_XOUT_H 0x43 // Gyro X axis High#define MPU_9150_GYRO_XOUT_L 0x44 // Gyro X axis Low#define MPU_9150_GYRO_YOUT_H 0x45 // Gyro Y axis High#define MPU_9150_GYRO_YOUT_L 0x46 // Gyro Y axis Low#define MPU_9150_GYRO_ZOUT_H 0x47 // Gyro Z axis High#define MPU_9150_GYRO_ZOUT_L 0x48 // Gyro Z axis Low#define MPU_9150_USER_CTRL 0x6A // User control#define MPU_9150_PWR_MGMT_1 0x6B // Power management 1
#define MPU_9150_I2C_MAGN_ADDRESS 0x0C // Address of the magnetometer in bypass mode#define MPU_9150_WIA 0x00 // Mag Who I Am#define MPU_9150_AKM_ID 0x48 // Mag device ID#define MPU_9150_ST1 0x02 // Magnetometer status 1#define MPU_9150_HXL 0x03 // Mag X axis Low#define MPU_9150_HXH 0x04 // Mag X axis High#define MPU_9150_HYL 0x05 // Mag Y axis Low#define MPU_9150_HYH 0x06 // Mag Y axis High#define MPU_9150_HZL 0x07 // Mag Z axis Low#define MPU_9150_HZH 0x08 // Mag Z axis High#define MPU_9150_ST2 0x09 // Magnetometer status 2#define MPU_9150_CNTL 0x0A // Magnetometer control
#define IMUPI_DEVNAME "/dev/i2c -2"#define IMUPI_BLOCK_SIZE 6#define IMUPI_NB_AXIS 3#define IMUPI_I2C_AUTO_INCREMENT 0x80#define IMUPI_A_GAIN 1 // 6.103515625e-05#define IMUPI_G_GAIN 1 // 0.030487804878049#define IMUPI_M_GAIN 1 // 0.3001221001221001#define IMUPI_GOFF_NB_ITER 50
#define IMUPI_NO_ERROR 0#define IMUPI_I2C_OPEN_ERROR 1#define IMUPI_I2C_DEV_NOT_FOUND 2#define IMUPI_I2C_WRITE_ERROR 3#define IMUPI_I2C_READ_ERROR 4#define IMUPI_INIT_ERROR 5
#endif
A.3 ADC
A.3.1 Main ADC program
/*This program consists on a circular buffer implemented with multithread to acquire data from theADC. It must be compiled with ADCDifferentialPi functions , which contains the functions to
83
configure the board , read the measurements and handle errorsThe programming of this code was inspired in:http ://www.cs.fsu.edu/~baker/realtime/restricted/examples/prodcons/prodcons.c*/
#include <stdio.h>#include <stdint.h>#include <stdlib.h>#include <sys/time.h>#include <time.h>#include <math.h>#include "ABE_ADCDifferentialPi.h"
#define BSIZE 32 // Define buffer size#define BNUM 2
/* Shared buffer structure */typedef struct shared_buffer {
double data[BNUM][BSIZE ]; /* Array to store ADC data */pthread_mutex_t lock; /* protects the buffer */pthread_cond_t /* the POSIX condition variable type */new_data_cond , /* to wait when the buffer is empty */new_space_cond; /* to wait when the buffer is full */int next_in , /* next available space for input */next_out , /* next available space for output */count; /* the number of spaces occupied */
} shared_buffer_t;
/* Initialize buffer counters */void sb_init(shared_buffer_t *sb){
sb ->next_in = sb->next_out = sb->count = 0;pthread_mutex_init (&sb->lock , NULL);pthread_cond_init (&sb->new_data_cond , NULL);pthread_cond_init (&sb->new_space_cond , NULL);
}
int find_file () {/* The files that this program writes for the storage of acquired data are numbered. Thisfunction defines the number of the next file to be written */
uint16_t i;i=1;FILE * fid [1000];
while (1) {char *file_name;int numdigits = log10(i) + 1;file_name = (char *) malloc(numdigits + 27);
/* The folder BPIdrive is stored in a storage unit different from theoperating system */
sprintf(file_name , "/home/pi/BPIdrive/adc -%d.csv", i);fid[i] = fopen(file_name , "r");
/* If fid is not null , the number of the file already exists */if (fid[i] == NULL) {
return i;}
i += 1;}
}
void * producer( void * arg ) {/* This function acquires data to the buffer */
int ret;int k = 0;struct timeval ti , tf;int elapsedTime;shared_buffer_t *sb = (shared_buffer_t *) arg;pthread_mutex_lock (&sb->lock);
/* Set the total time for data acquisition */time_t secs = 60; // 60 secondstime_t startTime = time(NULL);while (time(NULL) - startTime < secs) {
elapsedTime = 0;gettimeofday (&ti, NULL);
/* Wait for the communication with the buffer space to be allowed */while (sb->count == BSIZE)
pthread_cond_wait (&sb->new_space_cond , &sb ->lock);pthread_mutex_unlock (&sb->lock);k = sb ->next_in;
/* Read data from the analog sensors */sb->data [0][k] = read_voltage (0x6a , 1, 18, 1, 1); //HIH -4000 humidity sensorsb->data [1][k] = read_voltage (0x6a , 2, 18, 1, 1); //LM35 DZ temperature sensor
/* Update the buffer indicators */sb->next_in = (sb ->next_in + 1) % BSIZE; // Circular buffer using bitwise 'and'pthread_mutex_lock (&sb->lock);sb->count ++;pthread_cond_signal (&sb->new_data_cond );
while(elapsedTime < 1000000) { // 1s data acquisition periodgettimeofday (&tf, NULL);// compute and print the elapsed time in millisecelapsedTime = (tf.tv_sec - ti.tv_sec) * 1000000; // sec to ms
84
elapsedTime += (tf.tv_usec - ti.tv_usec ); // us to ms}
}return NULL;
}
void * consumer(void *arg) {/* This function writes data from the buffer to a file */
/* Create the data file for storage *///Open Data Fileuint16_t filenum;filenum = find_file ();int numdigits = log10(filenum) + 1;char *file_name;file_name = (char *) malloc(numdigits + 27);sprintf(file_name , "/home/pi/BPIdrive/adc -%d.csv", filenum );FILE *fid = fopen(file_name , "w");if (fid == NULL) {
printf("Error opening file\n");exit (1);
}
int k = 0;shared_buffer_t *sb = (shared_buffer_t *) arg;pthread_mutex_lock (&sb->lock);
/* Set the total time for data storage */time_t secs = 61; // 61 secondstime_t startTime = time(NULL);struct tm tm = *localtime (& startTime );
/* Write date and time and sampling frequency */fprintf(fid , "%04d-%02d-%02d %02d:%02d:%02d, Freq = 1Hz\nHum ,Temp ,ax ,ay,az\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday , tm.tm_hour , tm.tm_min , tm.tm_sec );
while (time(NULL) - startTime < secs) {
while (sb->count == 0)/* Wait for the communication with the buffer space to be allowed */pthread_cond_wait (&sb->new_data_cond , &sb->lock);
pthread_mutex_unlock (&sb->lock);
k = sb ->next_out;
/* Write data from buffer to file */fprintf( fid , "%f,%f,%f,%f,%f\n", sb ->data [0][k], sb ->data [1][k], sb->data [2][k],sb->data [3][k], sb ->data [4][k] );fflush(stdout );
/* Update the buffer indicators */sb->next_out = (sb ->next_out + 1) % BSIZE; // Circular buffer using bitwise 'and'pthread_mutex_lock (&sb->lock);sb->count --;pthread_cond_signal (&sb->new_space_cond );
}fclose(fid);return NULL;
}
int main() {
/* Initialize buffer */shared_buffer_t sb; /* the buffer */sb_init (&sb);
/* Create and start all threads */pthread_t th1 , th2; /* the two thread objects */pthread_create (&th1 , NULL , producer , &sb);pthread_create (&th2 , NULL , consumer , &sb);sleep (70);
/* Join threads */printf("%d %d\n", pthread_join(th1 , NULL), pthread_join(th2 , NULL ));return 0;
}
A.3.2 ADC functions
/*From: https :// github.com/abelectronicsuk/ABElectronics_C_Libraries/tree/master/ADCDifferetialPiReads from the MCP3424 ADC on the ADC Differential Pi and Delta -Sigma Pi.Two functions are available to use.read_raw(address ,channel ,bitrate ,pga ,conversionmode) returns the raw number from the ADCread_voltage(address ,channel ,bitrate ,pga ,conversionmode) returns the voltage present at theADC input*/
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <sys/ioctl.h>
85
#include <linux/i2c -dev.h>
static int i2cbus;const char *fileNamei2c = "/dev/i2c -2";unsigned char bufferwritebuffer [10] = { 0 };unsigned char bufferreadbuffer [10] = { 0 };static char signbit = 0;
// local methods
static void open_i2c_bus () {if (( i2cbus = open(fileNamei2c , O_RDWR )) < 0) {
printf("Failed to open i2c port for read %s \n", strerror(errno ));exit (1);
}}
static void close_i2c_bus () {close(i2cbus );
}
static void read_byte_array(char address , char reg , char length) {
if (ioctl(i2cbus , I2C_SLAVE , address) < 0) {printf("Failed to write to i2c port for read\n");exit (1);
}
bufferwritebuffer [0] = reg;
if ((write(i2cbus , bufferwritebuffer , 1)) != 1) {printf("Failed to write to i2c device for read\n");exit (1);
}
read(i2cbus , bufferreadbuffer , 4);}
static char update_byte(char byte , char bit , char value) {/*internal method for setting the value of a single bit within a byte*/
if (value == 0) {return (byte &= ~(1 << bit ));
} else {return (byte |= 1 << bit);
}
}
static char set_pga(char config , char gain) {/*internal method for Programmable Gain Amplifier gain selection*/
switch (gain) {case 1:
config = update_byte(config , 0, 0);config = update_byte(config , 1, 0);break;
case 2:config = update_byte(config , 0, 1);config = update_byte(config , 1, 0);break;
case 4:config = update_byte(config , 0, 0);config = update_byte(config , 1, 1);break;
case 8:config = update_byte(config , 0, 1);config = update_byte(config , 1, 1);break;
default:break;
}return (config );
}
static char set_bit_rate(char config , char rate) {/*internal method for bit rate selection*/
switch (rate) {case 12:
config = update_byte(config , 2, 0);config = update_byte(config , 3, 0);break;
case 14:config = update_byte(config , 2, 1);config = update_byte(config , 3, 0);break;
case 16:config = update_byte(config , 2, 0);config = update_byte(config , 3, 1);
break;case 18:
config = update_byte(config , 2, 1);config = update_byte(config , 3, 1);
86
break;default:
break;}return (config );
}
static char set_conversion_mode(char config , char mode) {/*internal method for setting the conversion mode*/
if (mode == 1) {config = update_byte(config , 4, 1);
} else {config = update_byte(config , 4, 0);
}
return (config );}
static char set_channel(char config , char channel) {/*internal method for setting the channel*/
switch (channel) {case 1:
config = update_byte(config , 5, 0);config = update_byte(config , 6, 0);break;
case 2:config = update_byte(config , 5, 1);config = update_byte(config , 6, 0);break;
case 3:config = update_byte(config , 5, 0);config = update_byte(config , 6, 1);break;
case 4:config = update_byte(config , 5, 1);config = update_byte(config , 6, 1);break;
}
return (config );}
/*** Reads the raw value from the selected ADC channel* @param address - I2C address for the target device e.g. 0x68* @param channel - 1 to 4* @param bitrate - 12, 14, 16 or 18* @param pga - 1, 2, 4 or 8* @param conversionmode - 0 = one shot conversion , 1 = continuous conversion* @returns - raw long value from ADC buffer*/int read_raw(char address , char channel , int bitrate , int pga ,
char conversionmode) {// variables for storing the raw bytes from the ADCchar h = 0;char l = 0;char m = 0;char s = 0;char config = 0x9C;long t = 0;signbit = 0;
// set the config based on the provided parametersconfig = set_channel(config , channel );config = set_conversion_mode(config , conversionmode );config = set_bit_rate(config , bitrate );config = set_pga(config , pga);
// keep reading the ADC data until the conversion result is readyint timeout = 1000; // number of reads before a timeout occursint x = 0;
open_i2c_bus ();
do {if (bitrate == 18) {
read_byte_array(address , config , 3);h = bufferreadbuffer [0];m = bufferreadbuffer [1];l = bufferreadbuffer [2];s = bufferreadbuffer [3];
} else {read_byte_array(address , config , 2);h = bufferreadbuffer [0];m = bufferreadbuffer [1];s = bufferreadbuffer [2];
}
// check bit 7 of s to see if the conversion result is readyif (!(s & (1 << 7))) {
break;}
if (x > timeout) {
87
// timeout occurredreturn (0);
}
x++;} while (1);
close_i2c_bus ();
// extract the returned bytes and combine in the correct orderswitch (bitrate) {case 18:
t = ((h & 3) << 16) | (m << 8) | l;if ((t >> 17) & 1) {
signbit = 1;t &= ~(1 << 17);
}break;
case 16:t = (h << 8) | m;if ((t >> 15) & 1) {
signbit = 1;t &= ~(1 << 15);
}break;
case 14:t = ((h & 63) << 8) | m;if ((t >> 13) & 1) {
signbit = 1;t &= ~(1 << 13);
}break;
case 12:t = ((h & 15) << 8) | m;if ((t >> 11) & 1) {
signbit = 1;t &= ~(1 << 11);
}break;
default:break;
}
return (t);}
/*** Returns the voltage from the selected ADC channel* @param address - I2C address for the target device e.g. 0x68* @param channel - 1 to 4* @param bitrate - 12, 14, 16 or 18* @param pga - 1, 2, 4 or 8* @param conversionmode - 0 = one shot conversion , 1 = continuous conversion* @returns - double voltage value from ADC*/double read_voltage(char address , char channel , int bitrate , int pga ,
char conversionmode) {int raw = read_raw(address , channel , bitrate , pga , conversionmode ); // get the raw value
// calculate the gain based on the pga valuedouble gain = (double) pga / 2;double offset = 2.048 / (double) pga;
// set the lsb value based on the bitratedouble lsb = 0;
switch (bitrate) {case 12:
lsb = 0.0005;break;
case 14:lsb = 0.000125;break;
case 16:lsb = 0.00003125;break;
case 18:lsb = 0.0000078125;break;
default:return (9999);break;
}
if (signbit == 1) { // if the signbit is 1 convert it back to positive and subtract 2.048.// calculate the voltage and return itdouble voltage = (double) raw * (lsb / gain) - offset;return (voltage );
} else {double voltage = (double) raw * (lsb / gain); // calculate the voltage and return itreturn (voltage );
}}
A.4 Filter
88
# This code imports data from a csv file and filters it
from __future__ import print_function , absolute_import , divisionimport numpy as npimport pandasfrom scipy import signalfrom pylab import *import math
matplotlib.style.use('classic ')matplotlib.rcParams['figure.facecolor '] = '1.0'matplotlib.rcParams['mathtext.fontset '] = 'stix'matplotlib.rcParams['font.family '] = 'STIXGeneral 'matplotlib.rcParams['xtick.labelsize '] = 'medium 'matplotlib.rcParams['ytick.labelsize '] = 'medium 'matplotlib.rcParams['legend.fontsize '] = 'medium '
# Declare a simple class to store dataclass Data:
pass
# Plot types allowed: eps , jpeg , jpg , pdf , pgf , png , ps, raw , rgba ,# svg , svgz , tif , tiffplots_type = 'pdf'
lab_folder = './accel/'fig_folder = './'
sensor_data = Data()
filename = './ accel/y_-x_z/unf_gyro_z.csv' # import file
df = pandas.read_csv( filename )
sensor_data.raw_data = df.iloc [:,1]sensor_data.signal_name = "Angular velocity"sensor_data.units = 'LSB'sensor_data.frequency = f
fs = 400 # Sampling frequencymult_fexp = 2
# Window fucntion in the FFT
def cosine_taper_window( time , y, tlen = 0.02 ):
NT = y.shape [0]NL = int( NT * tlen )NR = NT - NL
tL = time[NL]tT = time[NT -1]
omega = tL = pi / tL
y[ 0:NL] = y[ 0:NL] * 0.5 * ( 1 - cos( omega * time [0:NL] ) )y[NR:NT] = y[NR:NT] * 0.5 * ( 1 - cos( omega * ( time[NR:NT] - tT ) ) )
return y
# Filter frequency response
def filter_response( LPF_coefs , points = 40000, lowpow = -6, highpow = 0 ):
NT = LPF_coefs.shape [0]delta_f = 1.0 / points
m = int( ( NT -1 ) / 2 )omega_star = np.zeros( points )H = np.zeros( points )
a = highpow - lowpowjs = ( -1J * np.pi ) * np.linspace( -m, m, 2*m+1 )
for i in range( points ):omega_star[i] = 10**(a * delta_f * i + lowpow )eiwt = np.exp( omega_star[i] * js )G = np.dot( LPF_coefs , eiwt )H[i] = np.real( G )
return omega_star , H
# Filter using convolution and neglecting the ends
def filter_signal( coeffs , time , unf_signal ):
NS = unf_signal.shape [0]NC = coeffs.shape [0]
assert NC % 2 > 0 # assert that is a centred filter (odd)
flt_signal = np.convolve( unf_signal , coeffs , 'valid')hNC = int( NC / 2 )flt_time = time[ hNC: NS-hNC ]
assert flt_time.shape [0] == flt_signal.shape [0]
89
return flt_time , flt_signal
def filter_SincGaussian( window , fc , sigma ):M = int( window / 2 )pnts = np.linspace( -M, M, 2*M+1 ) / MLP_coefs = 2.0 * np.sinc( fc * pnts ) * np.exp( -0.5* pnts **2/ sigma **2 )LP_coefs /= sum(LP_coefs)return LP_coefs
# Perform FFT and related computations
# Create all plot with the same propertiesdef new_fig( FigSIZE = (12,4), FigDPI = 88 ):
new_fig.num = new_fig.num + 1figure( new_fig.num , figsize=FigSIZE , dpi = FigDPI )subplots_adjust( top = 0.93, bottom = 0.12, left = 0.10, right =0.96 ,\
hspace = 0.2, wspace = 0.2 )return new_fig.num
# create a "new_fig" function counter (kind of static variable)new_fig.num = 0
# Plot filter response
new_fig ()
LP_window = 401 # Window size
LP_fc = 5.6 # alphaLP_sigma = 0.5 # standard deviation
LP_coefs = filter_SincGaussian( LP_window , LP_fc , LP_sigma )LP_omega , LP_H = filter_response( LP_coefs )LP_omega *= fs # abscissa for plotting
semilogy( LP_omega , LP_H , label = "Gaussian Sinc filter: " \"$f_s =%.1f,\\ \\alpha =%.1f,\\ \\sigma =%.2f$ , W=%.0f"
% ( fs , LP_fc , LP_sigma , LP_window ) );legend ()grid()xlabel('frequency , [Hz]')ylabel('Gain , [-]')
filename = lab_folder + '/' + 'Low_Pass_Filter.' + plots_typesavefig( filename )
# Plot cosine taper window for FFT
t = linspace( 0, 100, 500 )Y = cosine_taper_window( t, ones( 500 ) )new_fig ()plot( t, Y );xlabel('time , [s]')ylabel('Gain , [-]')ylim ([0 ,1.2])
filename = lab_folder + '/' + 'cosine_taper_window.' + plots_typesavefig( filename )
def post_process_signal( fsample , LP_coefs , time_series_unf ):
PP = Data()
time_unf = array( range( time_series_unf.shape [0] ) ) / fstime_flt , time_series_flt = filter_signal( LP_coefs , time_unf , time_series_unf )
data_0 = time_series_flt.shape [0]data_N = int( 2** floor( log2( data_0 ) ) ) # closest power of two
hN = int( data_N / 2 )lN = data_N - 1
# time on cosine_taper_window function must start at 0time = arange( data_N ) / fsampledata = copy( time_series_flt[ data_0 -data_N:data_0 ] )
data -= mean(data) # remove the meandstd = data.std()data = cosine_taper_window( time , data )
delta_f = fsample / data_Nfreqs = delta_f * array( range( data_N ) )
data_fft = np.fft.fft( data )
Af = 2.0 * abs( data_fft ) / data_N # amplitudeVar = 0.5 * Af**2 # Variance spectrumSf = Var / delta_f # Spectral density
H_mean = sqrt( sum( Sf ) * delta_f )
# unfiltered datadata_unf = copy( time_series_unf[ data_0 -data_N:data_0 ] )
90
data_unf = cosine_taper_window( time , data_unf )data_unf_fft = np.fft.fft( data_unf )unf_Af = 2.0 * abs( data_unf_fft ) / data_N # amplitude
PP.time_unf = time_unfPP.time_series_unf = time_series_unfPP.time_flt = time_fltPP.time_series_flt = time_series_flt
PP.fsample = fsamplePP.N = data_NPP.hN = hNPP.lN = lNPP.time = timePP.data = dataPP.std = dstdPP.delta_f = delta_fPP.freqs = freqsPP.data_fft = data_fftPP.Spec_Af = AfPP.Spec_Var = VarPP.Spec_Sf = SfPP.H_mean = H_mean
PP.data_unf_fft = data_unf_fftPP.Spec_unf_Af = unf_Af
return PP
def time_series_plot_data( SENSOR , fexp , signal_name , units , \fig_folder , ext = 'png' ):
"""SENSOR - output from "post_process_signal"fig_folder - folder where figures are savedprefix - filename prefixext - figures file type.
File types allowed: eps , jpeg , jpg , pdf , pgf , png , ps, raw ,rgba , svg , svgz , tif , tiff
"""time_series_plot_data.hundreds = time_series_plot_data.hundreds + 1new_fig.num = time_series_plot_data.hundreds * 100
fn_signal=signal_name.replace(" ", "_"). replace("/",""). replace("\\","").\replace("=","")
########################################################################## Compare raw and filtered signals#########################################################################new_fig ()
plot( SENSOR.time_unf , SENSOR.time_series_unf , 'b', label='raw data' )plot( SENSOR.time_flt , SENSOR.time_series_flt , 'r', label='filtered ' )
xlabel( 'time , [s]' )ylabel( '%s, [%s]' % ( signal_name , units ) )legend( loc='upper left' )grid()
filename = fig_folder + '/' + fn_signal + '_TimeSeries_Raw_Flt.' + extsavefig( filename )
########################################################################## Time series#########################################################################new_fig ()
plot( SENSOR.time , SENSOR.data )axhline( +SENSOR.H_mean , c = 'r' )axhline( -SENSOR.H_mean , c = 'r' )
xlabel( 'time , [s]' )ylabel( '%s, [%s]' % ( signal_name , units ) )
filename = fig_folder + '/' + fn_signal + '_TimeSeries_for_FFT.' + extsavefig( filename )
########################################################################## Amplitude spectrum#########################################################################new_fig ()
plot( SENSOR.freqs [0: SENSOR.hN], SENSOR.Spec_Af [0: SENSOR.hN],\label='$|a|\\ mathrm {\ (half\ spectrum )}$' )
#axvline( fexp , c = 'r', label = '$f_\\ mathrm{exp}$' )
xlim( [ 0, 5 ] )#ylim( [ 0, 25 ] ) #altereixlabel( 'frequency , [Hz]' )ylabel( 'Amplitude , [%s]' % units )legend( loc='upper right')grid()filename = fig_folder + '/' + fn_signal + '_Amplitude_spectrum.' + extsavefig( filename )
########################################################################## Amplitude spectrum unfiltered data#########################################################################new_fig ()
91
plot( SENSOR.freqs [0: SENSOR.hN], SENSOR.Spec_unf_Af [0: SENSOR.hN],\label='$|a_{unf }|\\ mathrm {\ (half\ spectrum )}$' )
#axvline( fexp , c = 'r', label = '$f_\\ mathrm{exp}$' )
xlim( [ 0, 5 ] )xlabel( 'frequency , [Hz]' )ylabel( 'Amplitude , [%s]' % units )legend( loc='upper right')
filename = fig_folder + '/' + fn_signal + '_Unf_Amplitude_spectrum.' + extsavefig( filename )########################################################################## Variance diagram#########################################################################new_fig ()
plot( SENSOR.freqs , SENSOR.Spec_Var ,label='$\\frac {1}{2} a^2\\ mathrm {\ (half\ spectrum )}$' )#axvline( fexp , c = 'r', label = '$f_\\ mathrm{exp}$' )
legend( loc='upper left')#xlim( [ 0, fexp*mult_fexp ] )xlabel( 'frequency , [Hz]' )ylabel( 'Variance , [%s$^2$]' % units )
filename = fig_folder + '/' + fn_signal + '_Variance_diagram.' + extsavefig( filename )
########################################################################## Spectrum measured in the wave flume#########################################################################new_fig ()
# SENSOR.PM_freqs = SENSOR.freqs [1: -1] # remove zero frequency# SENSOR.PM = PM_Spectrum( fexp , Hs, SENSOR.PM_freqs )# plot( SENSOR.PM_freqs , SENSOR.PM, 'g-', label = 'Pierson -Moskowitz ' )
plot( SENSOR.freqs , SENSOR.Spec_Sf ,label = '$S_\eta(f)\\ mathrm {\ (half\ spectrum )}$' )#axvline( fexp , c = 'r', label = '$f_\\ mathrm{exp}$' )
#xlim( [ 0, fexp*mult_fexp ] )xlabel( 'frequency , [Hz]' )ylabel( 'Wave spectral density , [%s$^2$s]' % units )legend( loc='upper left')
filename = fig_folder + '/' + fn_signal + '_Spectral_Density.' + extsavefig( filename )
#close('all ')
return time_series_plot_data.hundreds
# create a hundreds counter (kind of static variable)time_series_plot_data.hundreds = 1
# ## Sensor data post -processing
hundreds = 0
sg_raw = sensor_data.raw_datasg_name = sensor_data.signal_namesg_units = sensor_data.unitssg_freq = sensor_data.frequency
PP = post_process_signal( fs , LP_coefs , sg_raw )sensor_data.PP = PP
print( sg_name + " STD:", PP.std )print( sg_name + " H_mean:", PP.H_mean )print ()
# In[31]:
hundreds = 0
sg_raw = sensor_data.raw_datasg_name = sensor_data.signal_namesg_units = sensor_data.unitssg_freq = sensor_data.frequency
PP = post_process_signal( fs , LP_coefs , sg_raw )sensor_data.PP = PP
print( sg_name + " STD:", PP.std )print( sg_name + " H_mean:", PP.H_mean )print ()
hundreds = time_series_plot_data( PP, sg_freq , sg_name , sg_units ,lab_folder , plots_type )
# prepare next figuresnew_fig.num = ( hundreds +1 ) * 100
92
A.5 Encoder parabolization
A.5.1 Main parabolization program
% Import csv datafs = 400 ; %Data acquisition frequency[ e_data , a_data , a_rad_flt ] = import_csv( fs ) ;
% Get left points[ index , pts ] = left_pts( e_data (:,2) ) ;
% Number of points to build each parabolep_pts = 7;
% Get first parabolic coefficientsY = zeros( (length(pts) - 1), 3) ;x_med = zeros( (length(pts) - 1), 1) ;[ Y(1,:) , x_med (1) ] = parabolize( e_data( index (1: p_pts) , 1 ) , pts( 1: p_pts ) ) ;
f_edata = zeros( length(index(ceil(p_pts /2)): index(length(index -floor(p_pts /2)))) , 2 ) ;df_dx = f_edata ;f_edata (:,1) = e_data( index(ceil(p_pts /2)): index(length(index -floor(p_pts /2))) , 1 ) ;df_dx (:,1) = f_edata (:,1) ;
j=1;for i = 2 : (length(pts) - (p_pts -1))
% Get first parabolic coefficients[ Y(i,:) , x_med(i) ] = parabolize( e_data( index(i:i+p_pts -1) , 1 ) , pts( i:i+p_pts -1 ) ) ;
% Get new amplitude points[f_edata(j:j+length(index(i+floor(p_pts /2)): index(i+ceil(p_pts /2)) -1) ,2) , ...
df_dx(j:j+length(index(i+floor(p_pts /2)): index(i+ceil(p_pts /2)) -1) ,2)] = ...get_points( Y(i-1,:) , Y(i,:) , e_data(index(i+floor(p_pts /2)): index(i+ceil(p_pts /2)), 1) ..., x_med(i-1), x_med(i) ) ;
j = j+length(index(i+floor(p_pts /2)): index(i+ceil(p_pts /2)) -1) ;
end
% Remove offset[pks , locs] = findpeaks(abs(f_edata (: ,2)));[pksup , locsup] = findpeaks(f_edata (: ,2));[pksd , locsd] = findpeaks(-f_edata (: ,2));pksd = -pksd;pup = fit(f_edata(locsup (2:135) ,1) , pksup (2:135) ,'exp2') ;pd = fit(f_edata(locsd (2:135) ,1) , pksd (2:135) ,'exp2') ;yup = feval(pup , f_edata(locs)) ;yd = feval(pd , f_edata(locs)) ;y0 = (yup +yd)/2;f_edata (:,2) = f_edata (:,2) - mean(y0);clear pks locs pksup locsup pksd locsd pup pd yup yd y0
% Remove offsetdf_dx (:,2) = df_dx (:,2) - mean(df_dx (: ,2)) ;
plot( e_data (:,1), e_data (:,2), f_edata (:,1), f_edata (:,2), '.' )figureplot( df_dx (:,1), df_dx (:,2) )figureplot(df_dx2 (:,1), df_dx2 (:,2))clear i j
A.5.2 Import csv data
function [ e_data , a_data , a_rad_flt ] = import_csv( fs )% Imports the encoder and accelerometer data% Calculate the time steps and return two matrices
mat = csvread('mpu_cal21.csv') ;
delta_t = 1 / fs ;
e_data = zeros(length(mat), 2) ;a_data = zeros(length(mat), 3) ;e_data (1,1) = 0 ;a_data (1,1) = 0 ;for i = 2: length(e_data)
e_data(i,1) = e_data(i-1,1) + delta_t ; % timea_data(i,1) = a_data(i-1,1) + delta_t ; % time
end
e_data (:,2) = mat(:,1) * 2 * pi / 2000 ;a_data (:,2) = mat(:,2) ; % axa_data (:,3) = mat(:,3) ; % aya_data (:,4) = mat(:,4) ; % az
end
93
A.5.3 Collect left points
function [ index , pts ] = left_pts( e_data )% Get left points of encoder (real transition points)
index (1) = 1;for i = 2: length(e_data)
if ( e_data(i) > e_data(i-1) )index = [index; i];
elseif ( e_data(i) < e_data(i-1) )index = [index; i];
endend
pts = zeros(length(index), 1);for i = 1: length(index)
pts(i) = e_data(index(i));end
end
A.5.4 Parabola coefficients
function [ y, x_med ] = parabolize( x_in , pts_x )% Get parabolic coefficients from highest degree to lowest% Five points least squares fit
x_med = mean(x_in) ;x = zeros(length(x_in), 1) ;A = zeros(length(x_in), 3) ;
A(:,3) = 1 ;for i = 1: length(x)
x(i) = x_in(i) - x_med ;A(i,1) = (x(i))^2 ;A(i,2) = x(i) ;
end
AT_A = A' * A ;AT_f = A' * pts_x ;
y = AT_A\AT_f ;
end
A.5.5 Interval points
function [ f , df_dx ] = get_points( coef1 , coef2 , x_in , x_med1 , x_med2 )% Calculate the points for an interval , ponderating between 3 paraboles
x1 = zeros(length(x_in), 1) ;x2 = zeros(length(x_in), 1) ;for i = 1: length(x_in)
x1(i) = x_in(i) - x_med1 ;x2(i) = x_in(i) - x_med2 ;
end
f = zeros(length(x_in), 1) ;df_dx = zeros(length(x_in), 1) ;phi1 = zeros(length(x_in), 1) ;phi2 = zeros(length(x_in), 1) ;
for i = 1: length(x_in)
delta_x_in = x_in(length(x_in))-x_in (1) ;phi1(i) = 1 - (x_in(i)-x_in (1))/ delta_x_in ;phi2(i) = 1 - phi1(i);
%p1 = ( coef1 (1) * (x1(i))^2 + coef1 (2) * x1(i) + coef1 (3) ) ;p2 = ( coef2 (1) * (x2(i))^2 + coef2 (2) * x2(i) + coef2 (3) ) ;
f(i) = p1 * phi1(i) + p2 * phi2(i) ;
df_dx(i) = p2 / delta_x_in - p1 / delta_x_in + ...(2* coef1 (1)*x1(i)+coef1 (2))* phi1(i) + (2* coef2 (1)*x2(i)+coef2 (2))* phi1(i);
end
end
94