Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MDA, MWD, MWV #81

Merged
merged 4 commits into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions mda.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package nmea

/**
$WIMDA

NMEA 0183 standard Meteorological Composite.

Syntax
$WIMDA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,
<12>,<13>,<14>,<15>,<16>,<17>,<18>,<19>,<20>*hh
<CR><LF>

Fields
<1> Barometric pressure, inches of mercury, to the nearest 0.01 inch
<2> I = inches of mercury
<3> Barometric pressure, bars, to the nearest .001 bar
<4> B = bars
<5> Air temperature, degrees C, to the nearest 0.1 degree C
<6> C = degrees C
<7> Water temperature, degrees C (this field left blank by some WeatherStations)
<8> C = degrees C (this field left blank by WeatherStation)
<9> Relative humidity, percent, to the nearest 0.1 percent
<10> Absolute humidity, percent (this field left blank by some WeatherStations)
<11> Dew point, degrees C, to the nearest 0.1 degree C
<12> C = degrees C
<13> Wind direction, degrees True, to the nearest 0.1 degree
<14> T = true
<15> Wind direction, degrees Magnetic, to the nearest 0.1 degree
<16> M = magnetic
<17> Wind speed, knots, to the nearest 0.1 knot
<18> N = knots
<19> Wind speed, meters per second, to the nearest 0.1 m/s
<20> M = meters per second
*/

const (
// TypeMDA type for MDA sentences
TypeMDA = "MDA"
// InchMDA for valid pressure in Inches of mercury
InchMDA = "I"
// BarsMDA for valid pressure in Bars
BarsMDA = "B"
// DegreesCMDA for valid data in degrees C
DegreesCMDA = "C"
// TrueMDA for valid data in True direction
TrueMDA = "T"
// MagneticMDA for valid data in Magnetic direction
MagneticMDA = "M"
// KnotsMDA for valid data in Knots
KnotsMDA = "N"
// MetersSecondMDA for valid data in Meters per Second
MetersSecondMDA = "M"
)

// MDA is the Meteorological Composite
// Data of air pressure, air and water temperatures and wind speed and direction
type MDA struct {
BaseSentence
PressureInch float64
InchesValid bool // I
PressureBar float64
BarsValid bool // B
AirTemp float64
AirTempValid bool // C or empty if no data
WaterTemp float64
WaterTempValid bool // C or empty if no data
RelativeHum float64 // percent to .1
AbsoluteHum float64 // percent to .1
DewPoint float64
DewPointValid bool // C or empty if no data
WindDirectionTrue float64
TrueValid bool // T
WindDirectionMagnetic float64
MagneticValid bool // M
WindSpeedKnots float64
KnotsValid bool // N
WindSpeedMeters float64
MetersValid bool // M
}

func newMDA(s BaseSentence) (MDA, error) {
p := NewParser(s)
p.AssertType(TypeMDA)
return MDA{
BaseSentence: s,
PressureInch: p.Float64(0, "pressure in inch"),
InchesValid: p.EnumString(1, "inches valid", InchMDA) == InchMDA,
PressureBar: p.Float64(2, "pressure in bar"),
BarsValid: p.EnumString(3, "bars valid", BarsMDA) == BarsMDA,
AirTemp: p.Float64(4, "air temp"),
AirTempValid: p.EnumString(5, "air temp valid", DegreesCMDA) == DegreesCMDA,
WaterTemp: p.Float64(6, "water temp"),
WaterTempValid: p.EnumString(7, "water temp valid", DegreesCMDA) == DegreesCMDA,
RelativeHum: p.Float64(8, "relative humidity"),
AbsoluteHum: p.Float64(9, "absolute humidity"),
DewPoint: p.Float64(10, "dewpoint"),
DewPointValid: p.EnumString(11, "dewpoint valid", DegreesCMDA) == DegreesCMDA,
WindDirectionTrue: p.Float64(12, "wind direction true"),
TrueValid: p.EnumString(13, "wind direction true valid", TrueMDA) == TrueMDA,
WindDirectionMagnetic: p.Float64(14, "wind direction magnetic"),
MagneticValid: p.EnumString(15, "wind direction magnetic valid", MagneticMDA) == MagneticMDA,
WindSpeedKnots: p.Float64(16, "windspeed knots"),
KnotsValid: p.EnumString(17, "windspeed knots valid", KnotsMDA) == KnotsMDA,
WindSpeedMeters: p.Float64(18, "windspeed m/s"),
MetersValid: p.EnumString(19, "windspeed m/s valid", MetersSecondMDA) == MetersSecondMDA,
}, p.Err()
}
57 changes: 57 additions & 0 deletions mda_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nmea

import (
"github.com/stretchr/testify/assert"
"testing"
)

var mdatests = []struct {
name string
raw string
err string
msg MDA
}{
{
name: "good sentence",
raw: "$WIMDA,3.02,I,1.01,B,23.4,C,,,40.2,,12.1,C,19.3,T,20.1,M,13.1,N,1.1,M*62",
msg: MDA{
PressureInch: 3.02,
InchesValid: true,
PressureBar: 1.01,
BarsValid: true,
AirTemp: 23.4,
AirTempValid: true,
WaterTemp: 0,
WaterTempValid: false,
RelativeHum: 40.2,
AbsoluteHum: 0,
DewPoint: 12.1,
DewPointValid: true,
WindDirectionTrue: 19.3,
TrueValid: true,
WindDirectionMagnetic: 20.1,
MagneticValid: true,
WindSpeedKnots: 13.1,
KnotsValid: true,
WindSpeedMeters: 1.1,
MetersValid: true,
},
},
}

func TestMDA(t *testing.T) {
for _, tt := range mdatests {
t.Run(tt.name, func(t *testing.T) {
m, err := Parse(tt.raw)
if tt.err != "" {
assert.Error(t, err)
assert.EqualError(t, err, tt.err)
} else {
assert.NoError(t, err)
mda := m.(MDA)
mda.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, mda)
}
})
}
}
62 changes: 62 additions & 0 deletions mwd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package nmea

/**
$WIMWD

NMEA 0183 standard Wind Direction and Speed, with respect to north.

Syntax
$WIMWD,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>*hh<CR><LF>

Fields
<1> Wind direction, 0.0 to 359.9 degrees True, to the nearest 0.1 degree
<2> T = True
<3> Wind direction, 0.0 to 359.9 degrees Magnetic, to the nearest 0.1 degree
<4> M = Magnetic
<5> Wind speed, knots, to the nearest 0.1 knot.
<6> N = Knots
<7> Wind speed, meters/second, to the nearest 0.1 m/s.
<8> M = Meters/second
*/

const (
// TypeMWD type for MWD sentences
TypeMWD = "MWD"
// TrueMWD for valid True Direction
TrueMWD = "T"
// MagneticMWD for valid Magnetic direction
MagneticMWD = "M"
// KnotsMWD for valid Knots
KnotsMWD = "N"
// MetersSecondMWD for valid Meters per Second
MetersSecondMWD = "M"
)

// MWD Wind Direction and Speed, with respect to north.
type MWD struct {
BaseSentence
WindDirectionTrue float64
TrueValid bool
WindDirectionMagnetic float64
MagneticValid bool
WindSpeedKnots float64
KnotsValid bool
WindSpeedMeters float64
MetersValid bool
}

func newMWD(s BaseSentence) (MWD, error) {
p := NewParser(s)
p.AssertType(TypeMWD)
return MWD{
BaseSentence: s,
WindDirectionTrue: p.Float64(0, "true wind direction"),
TrueValid: p.EnumString(1, "true wind valid", TrueMWD) == TrueMWD,
WindDirectionMagnetic: p.Float64(2, "magnetic wind direction"),
MagneticValid: p.EnumString(3, "magnetic direction valid", MagneticMWD) == MagneticMWD,
WindSpeedKnots: p.Float64(4, "windspeed knots"),
KnotsValid: p.EnumString(5, "windspeed knots valid", KnotsMWD) == KnotsMWD,
WindSpeedMeters: p.Float64(6, "windspeed m/s"),
MetersValid: p.EnumString(7, "windspeed m/s valid", MetersSecondMWD) == MetersSecondMWD,
}, p.Err()
}
59 changes: 59 additions & 0 deletions mwd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package nmea

import (
"github.com/stretchr/testify/assert"
"testing"
)

var mwdtests = []struct {
name string
raw string
err string
msg MWD
}{
{
name: "good sentence",
raw: "$WIMWD,10.1,T,10.1,M,12,N,40,M*5D",
msg: MWD{
WindDirectionTrue: 10.1,
TrueValid: true,
WindDirectionMagnetic: 10.1,
MagneticValid: true,
WindSpeedKnots: 12,
KnotsValid: true,
WindSpeedMeters: 40,
MetersValid: true,
},
},
{
name: "empty data",
raw: "$WIMWD,,,,,,,,*40",
msg: MWD{
WindDirectionTrue: 0,
TrueValid: false,
WindDirectionMagnetic: 0,
MagneticValid: false,
WindSpeedKnots: 0,
KnotsValid: false,
WindSpeedMeters: 0,
MetersValid: false,
},
},
}

func TestMWD(t *testing.T) {
for _, tt := range mwdtests {
t.Run(tt.name, func(t *testing.T) {
m, err := Parse(tt.raw)
if tt.err != "" {
assert.Error(t, err)
assert.EqualError(t, err, tt.err)
} else {
assert.NoError(t, err)
mwd := m.(MWD)
mwd.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, mwd)
}
})
}
}
71 changes: 71 additions & 0 deletions mwv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package nmea

/**
$WIMWV

NMEA 0183 standard Wind Speed and Angle, in relation to the vessel’s bow/centerline.

Syntax
$WIMWV,<1>,<2>,<3>,<4>,<5>*hh<CR><LF>

Fields
<1> Wind angle, 0.0 to 359.9 degrees, in relation to the vessel’s bow/centerline, to the nearest 0.1
degree. If the data for this field is not valid, the field will be blank.
<2> Reference:
R = Relative (apparent wind, as felt when standing on the moving ship)
T = Theoretical (calculated actual wind, as though the vessel were stationary)
<3> Wind speed, to the nearest tenth of a unit. If the data for this field is not valid, the field will be
blank.
<4> Wind speed units:
K = km/hr
M = m/s
N = knots
S = statute miles/hr
(Most WeatherStations will commonly use "N" (knots))
<5> Status:
A = data valid; V = data invalid
*/

const (
// TypeMWV type for MWV sentences
TypeMWV = "MWV"
// RelativeMWV for Valid Relative angle data
RelativeMWV = "R"
// TheoreticalMWV for valid Theoretical angle data
TheoreticalMWV = "T"
// UnitKMHMWV unit for Kilometer per hour (KM/H)
UnitKMHMWV = "K" // KM/H
// UnitMSMWV unit for Meters per second (M/S)
UnitMSMWV = "M" // M/S
// UnitKnotsMWV unit for knots
UnitKnotsMWV = "N" // knots
// UnitSMilesHMWV unit for Miles per hour (M/H)
UnitSMilesHMWV = "S"
// ValidMWV data is valid
ValidMWV = "A"
// InvalidMWV data is invalid
InvalidMWV = "V"
)

// MWV is the Wind Speed and Angle, in relation to the vessel’s bow/centerline.
type MWV struct {
BaseSentence
WindAngle float64
Reference string
WindSpeed float64
WindSpeedUnit string
StatusValid bool
}

func newMWV(s BaseSentence) (MWV, error) {
p := NewParser(s)
p.AssertType(TypeMWV)
return MWV{
BaseSentence: s,
WindAngle: p.Float64(0, "wind angle"),
Reference: p.EnumString(1, "reference", RelativeMWV, TheoreticalMWV),
WindSpeed: p.Float64(2, "wind speed"),
WindSpeedUnit: p.EnumString(3, "wind speed unit", UnitKMHMWV, UnitMSMWV, UnitKnotsMWV, UnitSMilesHMWV),
StatusValid: p.EnumString(4, "status", ValidMWV, InvalidMWV) == ValidMWV,
}, p.Err()
}
Loading