Goby v2
moos_translator.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Goby Underwater Autonomy Project Libraries
8 // ("The Goby Libraries").
9 //
10 // The Goby Libraries are free software: you can redistribute them and/or modify
11 // them under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // The Goby Libraries are distributed in the hope that they will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include <boost/algorithm/string.hpp>
24 #include <boost/math/special_functions/fpclassify.hpp>
25 
26 #include "goby/acomms/dccl.h"
27 #include "goby/util/sci.h"
28 
29 #include "moos_translator.h"
30 
31 const double NaN = std::numeric_limits<double>::quiet_NaN();
32 
33 void goby::moos::MOOSTranslator::initialize(double lat_origin, double lon_origin,
34  const std::string& modem_id_lookup_path)
35 {
36  transitional::DCCLAlgorithmPerformer* ap = transitional::DCCLAlgorithmPerformer::getInstance();
37 
38  // set up algorithms
39  ap->add_algorithm("power_to_dB", &alg_power_to_dB);
40  ap->add_algorithm("dB_to_power", &alg_dB_to_power);
41  ap->add_adv_algorithm("TSD_to_soundspeed", &alg_TSD_to_soundspeed);
42  ap->add_algorithm("to_lower", &alg_to_lower);
43  ap->add_algorithm("to_upper", &alg_to_upper);
44  ap->add_algorithm("angle_0_360", &alg_angle_0_360);
45  ap->add_algorithm("angle_-180_180", &alg_angle_n180_180);
46  ap->add_algorithm("lat2hemisphere_initial", &alg_lat2hemisphere_initial);
47  ap->add_algorithm("lon2hemisphere_initial", &alg_lon2hemisphere_initial);
48 
49  ap->add_algorithm("lat2nmea_lat", &alg_lat2nmea_lat);
50  ap->add_algorithm("lon2nmea_lon", &alg_lon2nmea_lon);
51 
52  ap->add_algorithm("unix_time2nmea_time", &alg_unix_time2nmea_time);
53 
54  ap->add_algorithm("abs", &alg_abs);
55 
56  ap->add_adv_algorithm("add", &alg_add);
57  ap->add_adv_algorithm("subtract", &alg_subtract);
58 
59  if (!modem_id_lookup_path.empty())
60  {
61  std::string id_lookup_output = modem_lookup_.read_lookup_file(modem_id_lookup_path);
62  goby::glog.is(goby::common::logger::DEBUG1) && goby::glog << id_lookup_output << std::flush;
63 
64  ap->add_algorithm("modem_id2name",
65  boost::bind(&MOOSTranslator::alg_modem_id2name, this, _1));
66  ap->add_algorithm("modem_id2type",
67  boost::bind(&MOOSTranslator::alg_modem_id2type, this, _1));
68  ap->add_algorithm("name2modem_id",
69  boost::bind(&MOOSTranslator::alg_name2modem_id, this, _1));
70 
71  // set up conversion for DCCLModemIdConverterCodec
72  //for(std::map<int, std::string>::const_iterator it = modem_lookup_.names().begin(),
73  // end = modem_lookup_.names().end(); it != end; ++it)
74  // goby::acomms::DCCLModemIdConverterCodec::add(it->second, it->first);
75  }
76 
77  if (!(boost::math::isnan)(lat_origin) && !(boost::math::isnan)(lon_origin))
78  {
79  if (geodesy_.Initialise(lat_origin, lon_origin))
80  {
81  ap->add_adv_algorithm("lat2utm_y",
82  boost::bind(&MOOSTranslator::alg_lat2utm_y, this, _1, _2));
83  ap->add_adv_algorithm("lon2utm_x",
84  boost::bind(&MOOSTranslator::alg_lon2utm_x, this, _1, _2));
85  ap->add_adv_algorithm("utm_x2lon",
86  boost::bind(&MOOSTranslator::alg_utm_x2lon, this, _1, _2));
87  ap->add_adv_algorithm("utm_y2lat",
88  boost::bind(&MOOSTranslator::alg_utm_y2lat, this, _1, _2));
89  }
90  }
91 }
92 
93 void goby::moos::alg_power_to_dB(transitional::DCCLMessageVal& val_to_mod)
94 {
95  val_to_mod = 10 * log10(double(val_to_mod));
96 }
97 
98 void goby::moos::alg_dB_to_power(transitional::DCCLMessageVal& val_to_mod)
99 {
100  val_to_mod = pow(10.0, double(val_to_mod) / 10.0);
101 }
102 
103 // applied to "T" (temperature), references are "S" (salinity), then "D" (depth)
104 void goby::moos::alg_TSD_to_soundspeed(transitional::DCCLMessageVal& val,
105  const std::vector<transitional::DCCLMessageVal>& ref_vals)
106 {
107  val.set(goby::util::mackenzie_soundspeed(val, ref_vals[0], ref_vals[1]), 3);
108 }
109 
110 void goby::moos::alg_angle_0_360(transitional::DCCLMessageVal& angle)
111 {
112  double a = angle;
113  while (a < 0) a += 360;
114  while (a >= 360) a -= 360;
115  angle = a;
116 }
117 
118 void goby::moos::alg_angle_n180_180(transitional::DCCLMessageVal& angle)
119 {
120  double a = angle;
121  while (a < -180) a += 360;
122  while (a >= 180) a -= 360;
123  angle = a;
124 }
125 
126 void goby::moos::MOOSTranslator::alg_lat2utm_y(
127  transitional::DCCLMessageVal& mv, const std::vector<transitional::DCCLMessageVal>& ref_vals)
128 {
129  double lat = mv;
130  double lon = ref_vals[0];
131  double x = NaN;
132  double y = NaN;
133 
134  if (!(boost::math::isnan)(lat) && !(boost::math::isnan)(lon))
135  geodesy_.LatLong2LocalUTM(lat, lon, y, x);
136  mv = y;
137 }
138 
139 void goby::moos::MOOSTranslator::alg_lon2utm_x(
140  transitional::DCCLMessageVal& mv, const std::vector<transitional::DCCLMessageVal>& ref_vals)
141 {
142  double lon = mv;
143  double lat = ref_vals[0];
144  double x = NaN;
145  double y = NaN;
146 
147  if (!(boost::math::isnan)(lat) && !(boost::math::isnan)(lon))
148  geodesy_.LatLong2LocalUTM(lat, lon, y, x);
149  mv = x;
150 }
151 
152 void goby::moos::MOOSTranslator::alg_utm_x2lon(
153  transitional::DCCLMessageVal& mv, const std::vector<transitional::DCCLMessageVal>& ref_vals)
154 {
155  double x = mv;
156  double y = ref_vals[0];
157 
158  double lat = NaN;
159  double lon = NaN;
160  if (!(boost::math::isnan)(y) && !(boost::math::isnan)(x))
161  geodesy_.UTM2LatLong(x, y, lat, lon);
162 
163  const int LON_INT_DIGITS = 3;
164  lon =
165  goby::util::unbiased_round(lon, std::numeric_limits<double>::digits10 - LON_INT_DIGITS - 1);
166  mv = lon;
167 }
168 
169 void goby::moos::MOOSTranslator::alg_utm_y2lat(
170  transitional::DCCLMessageVal& mv, const std::vector<transitional::DCCLMessageVal>& ref_vals)
171 {
172  double y = mv;
173  double x = ref_vals[0];
174 
175  double lat = NaN;
176  double lon = NaN;
177  if (!(boost::math::isnan)(x) && !(boost::math::isnan)(y))
178  geodesy_.UTM2LatLong(x, y, lat, lon);
179 
180  const int LAT_INT_DIGITS = 2;
181  lat =
182  goby::util::unbiased_round(lat, std::numeric_limits<double>::digits10 - LAT_INT_DIGITS - 1);
183  mv = lat;
184 }
185 
186 void goby::moos::MOOSTranslator::alg_modem_id2name(transitional::DCCLMessageVal& in)
187 {
188  bool is_numeric = true;
189  BOOST_FOREACH (const char c, std::string(in))
190  {
191  if (!isdigit(c))
192  {
193  is_numeric = false;
194  break;
195  }
196  }
197  if (is_numeric)
198  in = modem_lookup_.get_name_from_id(boost::lexical_cast<unsigned>(std::string(in)));
199 }
200 
201 void goby::moos::MOOSTranslator::alg_modem_id2type(transitional::DCCLMessageVal& in)
202 {
203  bool is_numeric = true;
204  BOOST_FOREACH (const char c, std::string(in))
205  {
206  if (!isdigit(c))
207  {
208  is_numeric = false;
209  break;
210  }
211  }
212 
213  if (is_numeric)
214  in = modem_lookup_.get_type_from_id(boost::lexical_cast<unsigned>(std::string(in)));
215 }
216 
217 void goby::moos::MOOSTranslator::alg_name2modem_id(transitional::DCCLMessageVal& in)
218 {
219  std::stringstream ss;
220  ss << modem_lookup_.get_id_from_name(std::string(in));
221  in = ss.str();
222 }
223 
224 void goby::moos::alg_to_upper(transitional::DCCLMessageVal& val_to_mod)
225 {
226  val_to_mod = boost::algorithm::to_upper_copy(std::string(val_to_mod));
227 }
228 
229 void goby::moos::alg_to_lower(transitional::DCCLMessageVal& val_to_mod)
230 {
231  val_to_mod = boost::algorithm::to_lower_copy(std::string(val_to_mod));
232 }
233 
234 void goby::moos::alg_lat2hemisphere_initial(transitional::DCCLMessageVal& val_to_mod)
235 {
236  double lat = val_to_mod;
237  if (lat < 0)
238  val_to_mod = "S";
239  else
240  val_to_mod = "N";
241 }
242 
243 void goby::moos::alg_lon2hemisphere_initial(transitional::DCCLMessageVal& val_to_mod)
244 {
245  double lon = val_to_mod;
246  if (lon < 0)
247  val_to_mod = "W";
248  else
249  val_to_mod = "E";
250 }
251 
252 void goby::moos::alg_abs(transitional::DCCLMessageVal& val_to_mod)
253 {
254  val_to_mod = std::abs(double(val_to_mod));
255 }
256 
257 void goby::moos::alg_unix_time2nmea_time(transitional::DCCLMessageVal& val_to_mod)
258 {
259  double unix_time = val_to_mod;
260  boost::posix_time::ptime ptime = goby::common::unix_double2ptime(unix_time);
261 
262  // HHMMSS.SSSSSS
263  boost::format f("%02d%02d%02d.%06d");
264  f % ptime.time_of_day().hours() % ptime.time_of_day().minutes() %
265  ptime.time_of_day().seconds() %
266  (ptime.time_of_day().fractional_seconds() * 1000000 /
267  boost::posix_time::time_duration::ticks_per_second());
268 
269  val_to_mod = f.str();
270 }
271 
272 void goby::moos::alg_lat2nmea_lat(transitional::DCCLMessageVal& val_to_mod)
273 {
274  double lat = val_to_mod;
275 
276  // DDMM.MM
277  boost::format f("%02d%02d.%04d");
278 
279  int degrees = std::floor(lat);
280  int minutes = std::floor((lat - degrees) * 60);
281  int ten_thousandth_minutes = std::floor(((lat - degrees) * 60 - minutes) * 10000);
282 
283  f % degrees % minutes % ten_thousandth_minutes;
284 
285  val_to_mod = f.str();
286 }
287 
288 void goby::moos::alg_lon2nmea_lon(transitional::DCCLMessageVal& val_to_mod)
289 {
290  double lon = val_to_mod;
291 
292  // DDDMM.MM
293  boost::format f("%03d%02d.%04d");
294 
295  int degrees = std::floor(lon);
296  int minutes = std::floor((lon - degrees) * 60);
297  int ten_thousandth_minutes = std::floor(((lon - degrees) * 60 - minutes) * 10000);
298 
299  f % degrees % minutes % ten_thousandth_minutes;
300 
301  val_to_mod = f.str();
302 }
303 
304 void goby::moos::alg_subtract(transitional::DCCLMessageVal& val_to_mod,
305  const std::vector<transitional::DCCLMessageVal>& ref_vals)
306 {
307  double diff = val_to_mod;
308 
309  for (std::vector<transitional::DCCLMessageVal>::const_iterator it = ref_vals.begin(),
310  end = ref_vals.end();
311  it != end; ++it)
312  diff -= static_cast<double>(*it);
313 
314  val_to_mod = diff;
315 }
316 
317 void goby::moos::alg_add(transitional::DCCLMessageVal& val_to_mod,
318  const std::vector<transitional::DCCLMessageVal>& ref_vals)
319 {
320  double sum = val_to_mod;
321 
322  for (std::vector<transitional::DCCLMessageVal>::const_iterator it = ref_vals.begin(),
323  end = ref_vals.end();
324  it != end; ++it)
325  sum += static_cast<double>(*it);
326 
327  val_to_mod = sum;
328 }
common::FlexOstream glog
Access the Goby logger through this object.
boost::posix_time::ptime unix_double2ptime(double given_time)
convert to boost date_time ptime from the number of seconds (including fractional) since 1/1/1970 0:0...
Definition: time.cpp:47