IT++ Logo
modulator.h
Go to the documentation of this file.
1
29#ifndef MODULATOR_H
30#define MODULATOR_H
31
32#include <itpp/base/mat.h>
37#include <itpp/itexports.h>
38
39
40namespace itpp
41{
42
51
74template <typename T>
76{
77public:
81 Modulator(const Vec<T>& symbols, const ivec& bits2symbols);
83 virtual ~Modulator() {}
84
86 virtual void set(const Vec<T>& symbols, const ivec& bits2symbols);
87
89 virtual int bits_per_symbol() const { return k; }
90
92 virtual int get_k() const { return k; }
93
95 virtual int get_M() const { return M; }
96
98 virtual Vec<T> get_symbols() const { return symbols; }
99
117 virtual ivec get_bits2symbols() const { return bits2symbols; }
118
120 virtual void modulate(const ivec& symbolnumbers, Vec<T>& output) const;
122 virtual Vec<T> modulate(const ivec& symbolnumbers) const;
123
125 virtual void demodulate(const Vec<T>& signal, ivec& output) const;
127 virtual ivec demodulate(const Vec<T>& signal) const;
128
130 virtual void modulate_bits(const bvec& bits, Vec<T>& output) const;
132 virtual Vec<T> modulate_bits(const bvec& bits) const;
133
135 virtual void demodulate_bits(const Vec<T>& signal, bvec& bits) const;
137 virtual bvec demodulate_bits(const Vec<T>& signal) const;
138
178 virtual void demodulate_soft_bits(const Vec<T>& rx_symbols, double N0,
179 vec& soft_bits,
180 Soft_Method method = LOGMAP) const;
182 virtual vec demodulate_soft_bits(const Vec<T>& rx_symbols, double N0,
183 Soft_Method method = LOGMAP) const;
184
224 const Vec<T>& channel,
225 double N0, vec& soft_bits,
226 Soft_Method method = LOGMAP) const;
229 const Vec<T>& channel,
230 double N0,
231 Soft_Method method = LOGMAP) const;
232
233protected:
237 int k;
239 int M;
248 imat S0;
251 imat S1;
252
255};
256
257
258// ----------------------------------------------------------------------
259// Type definitions of Modulator_1D and Modulator_2D
260// ----------------------------------------------------------------------
261
267
273
274
275// ----------------------------------------------------------------------
276// Implementation of templated Modulator members
277// ----------------------------------------------------------------------
278
279template<typename T>
281 setup_done(false), k(0), M(0), bitmap(""), bits2symbols(""), symbols(""),
282 S0(""), S1("") {}
283
284template<typename T>
285Modulator<T>::Modulator(const Vec<T> &symbols, const ivec &bits2symbols)
286{
287 set(symbols, bits2symbols);
288}
289
290template<typename T>
292{
294 "Modulator<T>::set(): Number of symbols and bits2symbols does not match");
296 "Modulator<T>::set(): Number of symbols needs to be even and non-zero");
298 && (min(in_bits2symbols) == 0), "Modulator<T>::set(): Improper bits2symbol vector");
299 symbols = in_symbols;
300 bits2symbols = in_bits2symbols;
301 M = bits2symbols.size();
302 k = levels2bits(M);
303 bitmap.set_size(M, k);
304 for (int m = 0; m < M; m++) {
305 bitmap.set_row(bits2symbols(m), dec2bin(k, m));
306 }
307 calculate_softbit_matrices();
308 setup_done = true;
309}
310
311
312template<typename T>
313void Modulator<T>::modulate(const ivec &symbolnumbers, Vec<T>& output) const
314{
315 it_assert_debug(setup_done, "Modulator<T>::modulate(): Modulator not ready.");
316 output.set_size(symbolnumbers.length());
317 for (int i = 0; i < symbolnumbers.length(); i++)
318 output(i) = symbols(symbolnumbers(i));
319}
320
321template<typename T>
323{
324 Vec<T> output(symbolnumbers.length());
325 modulate(symbolnumbers, output);
326 return output;
327}
328
329
330template<typename T>
331void Modulator<T>::demodulate(const Vec<T> &signal, ivec& output) const
332{
333 it_assert_debug(setup_done, "Modulator<T>::demodulate(): Modulator not ready.");
334 double dist, mindist;
335 int closest;
336 output.set_size(signal.size());
337
338 for (int i = 0; i < signal.size(); i++) {
339 mindist = std::abs(symbols(0) - signal(i));
340 closest = 0;
341 for (int j = 1; j < M; j++) {
342 dist = std::abs(symbols(j) - signal(i));
343 if (dist < mindist) {
344 mindist = dist;
345 closest = j;
346 }
347 }
348 output(i) = closest;
349 }
350}
351
352template<typename T>
353ivec Modulator<T>::demodulate(const Vec<T>& signal) const
354{
355 ivec output(signal.length());
356 demodulate(signal, output);
357 return output;
358}
359
360
361template<typename T>
362void Modulator<T>::modulate_bits(const bvec &bits, Vec<T> &output) const
363{
364 it_assert_debug(setup_done, "Modulator<T>::modulate_bits(): Modulator not ready.");
365 // Check if some bits have to be cut and print warning message in such
366 // case.
367 if (bits.length() % k) {
368 it_warning("Modulator<T>::modulate_bits(): The number of input bits is not a multiple of k (number of bits per symbol). Remainder bits are not modulated.");
369 }
370 int no_symbols = bits.length() / k;
371 output.set_size(no_symbols);
372 for (int i = 0; i < no_symbols; i++) {
373 output(i) = symbols(bits2symbols(bin2dec(bits.mid(i * k, k))));
374 }
375}
376
377template<typename T>
379{
380 Vec<T> output;
381 modulate_bits(bits, output);
382 return output;
383}
384
385template<typename T>
386void Modulator<T>::demodulate_bits(const Vec<T> &signal, bvec &bits) const
387{
388 it_assert_debug(setup_done, "Modulator<T>::demodulate_bist(): Modulator not ready.");
389 double dist, mindist;
390 int closest;
391 bits.set_size(k*signal.size());
392
393 for (int i = 0; i < signal.size(); i++) {
394 mindist = std::abs(symbols(0) - signal(i));
395 closest = 0;
396 for (int j = 1; j < M; j++) {
397 dist = std::abs(symbols(j) - signal(i));
398 if (dist < mindist) {
399 mindist = dist;
400 closest = j;
401 }
402 }
403 bits.replace_mid(i*k, bitmap.get_row(closest));
404 }
405}
406
407template<typename T>
408bvec Modulator<T>::demodulate_bits(const Vec<T> &signal) const
409{
410 bvec bits;
411 demodulate_bits(signal, bits);
412 return bits;
413}
414
415
416template<typename T>
418 vec &soft_bits,
419 Soft_Method method) const
420{
421 it_assert_debug(setup_done, "Modulator<T>::demodulate_soft_bits(): Modulator not ready.");
422 double P0, P1, d0min, d1min, temp;
423 vec metric(M);
424
426
427 if (method == LOGMAP) {
428 for (int l = 0; l < rx_symbols.size(); l++) {
429 for (int j = 0; j < M; j++) {
430 metric(j) = std::exp(-sqr(rx_symbols(l) - symbols(j)) / N0);
431 }
432 for (int i = 0; i < k; i++) {
433 P0 = P1 = 0;
434 for (int j = 0; j < (M >> 1); j++) {
435 P0 += metric(S0(i, j));
436 P1 += metric(S1(i, j));
437 }
438 soft_bits(l*k + i) = trunc_log(P0) - trunc_log(P1);
439 }
440 }
441 }
442 else { // method == APPROX
443 for (int l = 0; l < rx_symbols.size(); l++) {
444 for (int j = 0; j < M; j++) {
445 metric(j) = sqr(rx_symbols(l) - symbols(j));
446 }
447 for (int i = 0; i < k; i++) {
448 d0min = d1min = std::numeric_limits<double>::max();
449 for (int j = 0; j < (M >> 1); j++) {
450 temp = metric(S0(i, j));
451 if (temp < d0min) { d0min = temp; }
452 temp = metric(S1(i, j));
453 if (temp < d1min) { d1min = temp; }
454 }
455 soft_bits(l*k + i) = (-d0min + d1min) / N0;
456 }
457 }
458 }
459}
460
461template<typename T>
463 double N0,
464 Soft_Method method) const
465{
466 vec output;
467 demodulate_soft_bits(rx_symbols, N0, output, method);
468 return output;
469}
470
471template<typename T>
473 const Vec<T> &channel, double N0,
474 vec &soft_bits,
475 Soft_Method method) const
476{
477 it_assert_debug(setup_done, "Modulator_2D::demodulate_soft_bits(): Modulator not ready.");
478 double P0, P1, d0min, d1min, temp;
479 vec metric(M);
480
482
483 if (method == LOGMAP) {
484 for (int l = 0; l < rx_symbols.size(); l++) {
485 for (int j = 0; j < M; j++) {
486 metric(j) = std::exp(-sqr(rx_symbols(l) - channel(l) * symbols(j))
487 / N0);
488 }
489 for (int i = 0; i < k; i++) {
490 P0 = P1 = 0;
491 for (int j = 0; j < (M >> 1); j++) {
492 P0 += metric(S0(i, j));
493 P1 += metric(S1(i, j));
494 }
495 soft_bits(l*k + i) = trunc_log(P0) - trunc_log(P1);
496 }
497 }
498 }
499 else { // method == APPROX
500 for (int l = 0; l < rx_symbols.size(); l++) {
501 for (int j = 0; j < M; j++) {
502 metric(j) = sqr(rx_symbols(l) - channel(l) * symbols(j));
503 }
504 for (int i = 0; i < k; i++) {
505 d0min = d1min = std::numeric_limits<double>::max();
506 for (int j = 0; j < (M >> 1); j++) {
507 temp = metric(S0(i, j));
508 if (temp < d0min) { d0min = temp; }
509 temp = metric(S1(i, j));
510 if (temp < d1min) { d1min = temp; }
511 }
512 soft_bits(l*k + i) = (-d0min + d1min) / N0;
513 }
514 }
515 }
516}
517
518template<typename T>
520 const Vec<T> &channel,
521 double N0,
522 Soft_Method method) const
523{
524 vec output;
525 demodulate_soft_bits(rx_symbols, channel, N0, output, method);
526 return output;
527}
528
529template<typename T>
531{
532 int count0, count1;
533
534 // Allocate storage space for the result matrices:
535 S0.set_size(k, M >> 1, false);
536 S1.set_size(k, M >> 1, false);
537
538 for (int i = 0; i < k; i++) {
539 count0 = 0;
540 count1 = 0;
541 for (int j = 0; j < M; j++) {
542 if (bitmap(j, i) == bin(0)) {
543 S0(i, count0++) = j;
544 }
545 else {
546 S1(i, count1++) = j;
547 }
548 }
549 }
550}
551
553
554// ----------------------------------------------------------------------
555// Instantiations
556// ----------------------------------------------------------------------
559
561
562// ----------------------------------------------------------------------
563// QAM : Modulator_2D
564// ----------------------------------------------------------------------
565
586class ITPP_EXPORT QAM : public Modulator<std::complex<double> >
587{
588public:
590 QAM() {}
592 QAM(int M) { set_M(M); }
594 virtual ~QAM() { }
596 void set_M(int M);
597
599 void demodulate_bits(const cvec& signal, bvec& bits) const;
601 bvec demodulate_bits(const cvec& signal) const;
602
603protected:
605 int L;
608};
609
610
611// ----------------------------------------------------------------------
612// PSK : Modulator<std::complex<double> >
613// ----------------------------------------------------------------------
614
635class ITPP_EXPORT PSK : public Modulator<std::complex<double> >
636{
637public:
639 PSK() {}
641 PSK(int M) { set_M(M); }
643 virtual ~PSK() { }
645 void set_M(int M);
646
648 void demodulate_bits(const cvec& signal, bvec& bits) const;
650 bvec demodulate_bits(const cvec& signal) const;
651};
652
653
654// ----------------------------------------------------------------------
655// QPSK : PSK : Modulator<std::complex<double> >
656// ----------------------------------------------------------------------
657
677class ITPP_EXPORT QPSK : public PSK
678{
679public:
681 QPSK(): PSK(4) {}
683 virtual ~QPSK() {}
684
706 virtual void demodulate_soft_bits(const cvec& rx_symbols, double N0,
707 vec& soft_bits,
708 Soft_Method method = LOGMAP) const;
710 vec demodulate_soft_bits(const cvec& rx_symbols, double N0,
711 Soft_Method method = LOGMAP) const;
712
713
736 virtual void demodulate_soft_bits(const cvec& rx_symbols,
737 const cvec& channel, double N0,
738 vec& soft_bits,
739 Soft_Method method = LOGMAP) const;
741 vec demodulate_soft_bits(const cvec& rx_symbols, const cvec& channel,
742 double N0, Soft_Method method = LOGMAP) const;
743};
744
745
746// ----------------------------------------------------------------------
747// BPSK_c : PSK : Modulator<std::complex<double> >
748// ----------------------------------------------------------------------
749
775class ITPP_EXPORT BPSK_c : public PSK
776{
777public:
779 BPSK_c(): PSK(2) {}
781 virtual ~BPSK_c() {}
782
784 void modulate_bits(const bvec& bits, cvec& output) const;
786 cvec modulate_bits(const bvec& bits) const;
788 void demodulate_bits(const cvec& signal, bvec& output) const;
790 bvec demodulate_bits(const cvec& signal) const;
791
811 virtual void demodulate_soft_bits(const cvec& rx_symbols, double N0,
812 vec& soft_bits,
813 Soft_Method method = LOGMAP) const;
815 vec demodulate_soft_bits(const cvec& rx_symbols, double N0,
816 Soft_Method method = LOGMAP) const;
817
838 virtual void demodulate_soft_bits(const cvec& rx_symbols,
839 const cvec& channel, double N0,
840 vec& soft_bits,
841 Soft_Method method = LOGMAP) const;
843 vec demodulate_soft_bits(const cvec& rx_symbols, const cvec& channel,
844 double N0, Soft_Method method = LOGMAP) const;
845};
846
847
848
849// ----------------------------------------------------------------------
850// BPSK : Modulator<double>
851// ----------------------------------------------------------------------
852
876class ITPP_EXPORT BPSK : public Modulator<double>
877{
878public:
880 BPSK(): Modulator<double>("1.0 -1.0", "0 1") {}
882 virtual ~BPSK() {}
883
885 void modulate_bits(const bvec& bits, vec& output) const;
887 vec modulate_bits(const bvec& bits) const;
889 void demodulate_bits(const vec& signal, bvec& output) const;
891 bvec demodulate_bits(const vec& signal) const;
892
910 virtual void demodulate_soft_bits(const vec& rx_symbols, double N0,
911 vec& soft_bits,
912 Soft_Method method = LOGMAP) const;
914 vec demodulate_soft_bits(const vec& rx_symbols, double N0,
915 Soft_Method method = LOGMAP) const;
916
936 virtual void demodulate_soft_bits(const vec& rx_symbols,
937 const vec& channel, double N0,
938 vec& soft_bits,
939 Soft_Method method = LOGMAP) const;
941 vec demodulate_soft_bits(const vec& rx_symbols, const vec& channel,
942 double N0, Soft_Method method = LOGMAP) const;
943};
944
945
946// ----------------------------------------------------------------------
947// PAM_c : Modulator<std::complex<double> >
948// ----------------------------------------------------------------------
949
968class ITPP_EXPORT PAM_c : public Modulator<std::complex<double> >
969{
970public:
972 PAM_c() {}
974 PAM_c(int M) { set_M(M); }
976 virtual ~PAM_c() {}
978 void set_M(int M);
979
981 void demodulate_bits(const cvec& signal, bvec& output) const;
983 bvec demodulate_bits(const cvec& signal) const;
984
1024 virtual void demodulate_soft_bits(const cvec& rx_symbols, double N0,
1025 vec& soft_bits,
1026 Soft_Method method = LOGMAP) const;
1028 virtual vec demodulate_soft_bits(const cvec& rx_symbols, double N0,
1029 Soft_Method method = LOGMAP) const;
1030
1069 virtual void demodulate_soft_bits(const cvec& rx_symbols,
1070 const cvec& channel, double N0,
1071 vec& soft_bits,
1072 Soft_Method method = LOGMAP) const;
1074 virtual vec demodulate_soft_bits(const cvec& rx_symbols,
1075 const cvec& channel, double N0,
1076 Soft_Method method = LOGMAP) const;
1077
1078protected:
1081};
1082
1083
1084// ----------------------------------------------------------------------
1085// PAM : Modulator<double>
1086// ----------------------------------------------------------------------
1087
1104class ITPP_EXPORT PAM : public Modulator<double>
1105{
1106public:
1108 PAM() {}
1110 PAM(int M) { set_M(M); }
1112 virtual ~PAM() {}
1114 void set_M(int M);
1115
1117 void demodulate_bits(const vec& signal, bvec& output) const;
1119 bvec demodulate_bits(const vec& signal) const;
1120
1121protected:
1124};
1125
1126} // namespace itpp
1127
1128#endif // #ifndef MODULATOR_H
General array class.
Definition array.h:105
Array< T > mid(int pos, int n) const
Get n elements of the array starting from pos.
Definition array.h:377
int size() const
Returns the number of data elements in the array object.
Definition array.h:155
void set_size(int n, bool copy=false)
Resizing an Array<T>.
Definition array.h:257
int length() const
Returns the number of data elements in the array object.
Definition array.h:157
BPSK modulator with complex symbols.
Definition modulator.h:776
virtual ~BPSK_c()
Destructor.
Definition modulator.h:781
BPSK_c()
Constructor.
Definition modulator.h:779
BPSK modulator with real symbols.
Definition modulator.h:877
virtual ~BPSK()
Destructor.
Definition modulator.h:882
BPSK()
Constructor.
Definition modulator.h:880
General modulator for 1D or 2D signal constellations.
Definition modulator.h:76
Modulator(const Vec< T > &symbols, const ivec &bits2symbols)
Constructor.
Definition modulator.h:285
virtual vec demodulate_soft_bits(const Vec< T > &rx_symbols, const Vec< T > &channel, double N0, Soft_Method method=LOGMAP) const
Soft demodulator for fading channels.
Definition modulator.h:519
virtual ivec get_bits2symbols() const
Get the bitmap, which maps input bits into symbols.
Definition modulator.h:117
bmat bitmap
Bit to symbol mapping table (size: M x k)
Definition modulator.h:241
Vec< T > symbols
Corresponding modulation symbols (size: M)
Definition modulator.h:245
virtual int get_k() const
Returns number of bits per symbol.
Definition modulator.h:92
int k
Number of bits per modulation symbol.
Definition modulator.h:237
virtual int bits_per_symbol() const
Returns number of bits per symbol.
Definition modulator.h:89
ivec bits2symbols
Bit to symbol mapping in decimal form (size: M)
Definition modulator.h:243
virtual void demodulate_soft_bits(const Vec< T > &rx_symbols, double N0, vec &soft_bits, Soft_Method method=LOGMAP) const
Soft demodulator for AWGN channels.
Definition modulator.h:417
virtual Vec< T > modulate(const ivec &symbolnumbers) const
Modulation of symbols.
Definition modulator.h:322
virtual void demodulate(const Vec< T > &signal, ivec &output) const
Demodulation of symbols.
Definition modulator.h:331
bool setup_done
Setup indicator.
Definition modulator.h:235
virtual int get_M() const
Returns number of modulation symbols.
Definition modulator.h:95
virtual ivec demodulate(const Vec< T > &signal) const
Demodulation of symbols.
Definition modulator.h:353
virtual void modulate_bits(const bvec &bits, Vec< T > &output) const
Modulation of bits.
Definition modulator.h:362
virtual Vec< T > modulate_bits(const bvec &bits) const
Modulation of bits.
Definition modulator.h:378
virtual bvec demodulate_bits(const Vec< T > &signal) const
Hard demodulation of bits.
Definition modulator.h:408
virtual void demodulate_bits(const Vec< T > &signal, bvec &bits) const
Hard demodulation of bits.
Definition modulator.h:386
Modulator< std::complex< double > > Modulator_2D
Definition of 2D Modulator (with complex symbols)
Definition modulator.h:272
imat S1
Matrix where row k contains the constellation points with '1' in bit position k.
Definition modulator.h:251
Modulator()
Default constructor.
Definition modulator.h:280
int M
Number of modulation symbols.
Definition modulator.h:239
virtual Vec< T > get_symbols() const
Get the symbol values used in the modulator.
Definition modulator.h:98
virtual void demodulate_soft_bits(const Vec< T > &rx_symbols, const Vec< T > &channel, double N0, vec &soft_bits, Soft_Method method=LOGMAP) const
Soft demodulator for fading channels.
Definition modulator.h:472
virtual vec demodulate_soft_bits(const Vec< T > &rx_symbols, double N0, Soft_Method method=LOGMAP) const
Soft demodulator for AWGN channels.
Definition modulator.h:462
virtual void set(const Vec< T > &symbols, const ivec &bits2symbols)
Set the constellation to use in the modulator.
Definition modulator.h:291
void calculate_softbit_matrices()
This function calculates the soft bit mapping matrices S0 and S1.
Definition modulator.h:530
virtual void modulate(const ivec &symbolnumbers, Vec< T > &output) const
Modulation of symbols.
Definition modulator.h:313
imat S0
Matrix where row k contains the constellation points with '0' in bit position k.
Definition modulator.h:248
virtual ~Modulator()
Destructor.
Definition modulator.h:83
Modulator< double > Modulator_1D
Definition of 1D Modulator (with real symbols)
Definition modulator.h:266
M-ary PAM modulator with complex symbols.
Definition modulator.h:969
PAM_c()
Default Constructor.
Definition modulator.h:972
double scaling_factor
Scaling factor used to normalize the average energy to 1.
Definition modulator.h:1080
PAM_c(int M)
Constructor.
Definition modulator.h:974
virtual ~PAM_c()
Destructor.
Definition modulator.h:976
M-ary PAM modulator with real symbols.
Definition modulator.h:1105
double scaling_factor
Scaling factor used to normalize the average energy to 1.
Definition modulator.h:1123
PAM(int M)
Constructor.
Definition modulator.h:1110
PAM()
Default Constructor.
Definition modulator.h:1108
virtual ~PAM()
Destructor.
Definition modulator.h:1112
M-ary PSK modulator.
Definition modulator.h:636
PSK()
Default Constructor.
Definition modulator.h:639
PSK(int M)
Class constructor.
Definition modulator.h:641
virtual ~PSK()
Destructor.
Definition modulator.h:643
M-ary QAM modulator with square lattice.
Definition modulator.h:587
double scaling_factor
Scaling factor of square QAM constellation (sqrt((M-1)*2/3))
Definition modulator.h:607
virtual ~QAM()
Destructor.
Definition modulator.h:594
QAM()
Default Constructor.
Definition modulator.h:590
QAM(int M)
Class Constructor.
Definition modulator.h:592
int L
The square-root of M.
Definition modulator.h:605
QPSK modulator.
Definition modulator.h:678
QPSK()
Class Constructor.
Definition modulator.h:681
virtual ~QPSK()
Destructor.
Definition modulator.h:683
Binary arithmetic (boolean) class.
Definition binary.h:57
Definitions of converters between different vector and matrix types.
Elementary mathematical functions - header file.
#define it_warning(s)
Display a warning message.
Definition itassert.h:173
#define it_assert_debug(t, s)
Abort if t is not true and NDEBUG is not defined.
Definition itassert.h:107
#define it_assert(t, s)
Abort if t is not true.
Definition itassert.h:94
double trunc_log(double x)
Truncated natural logarithm function.
Definition log_exp.h:115
int levels2bits(int n)
Calculate the number of bits needed to represent n different values (levels).
Definition log_exp.h:92
T min(const Vec< T > &in)
Minimum value of vector.
Definition min_max.h:125
T max(const Vec< T > &v)
Maximum value of vector.
Definition min_max.h:45
bool is_even(int x)
Return true if x is an even integer.
Definition misc.h:122
vec sqr(const cvec &data)
Absolute square of elements.
Definition elem_math.cpp:36
Soft_Method
Soft demodulation methods.
Definition modulator.h:47
@ LOGMAP
Log-MAP full calculation.
Definition modulator.h:48
@ APPROX
Approximate faster method.
Definition modulator.h:49
Logarithmic and exponenential functions - header file.
Matrix Class Definitions.
Mat< bin > bmat
bin matrix
Definition mat.h:508
Minimum and maximum functions on vectors and matrices.
itpp namespace
Definition itmex.h:37
ITPP_EXPORT int bin2dec(const bvec &inbvec, bool msb_first=true)
Convert a bvec to decimal int with the first bit as MSB if msb_first == true.
ITPP_EXPORT bvec dec2bin(int length, int index)
Convert a decimal int index to bvec using length bits in the representation.

Generated on Tue Mar 26 2024 19:08:31 for IT++ by Doxygen 1.9.8