1use itertools::Itertools;
29use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
30use serde::{Deserialize, Serialize};
31
32use crate::{utils, Bit, DecodingAlgo, Error, Interleaver};
33
34const CODE_POLYNOMIALS: [usize; 2] = [0o13, 0o15];
35const INVERSE_CODE_RATE: usize = 3;
36const NUM_TAIL_CODE_BITS: usize = 12;
37
38#[derive(Clone, PartialEq, Debug, Copy, Deserialize, Serialize)]
40pub struct SimParams {
41 pub num_info_bits_per_block: u32,
43 pub decoding_algo: DecodingAlgo,
45 pub es_over_n0_db: f64,
47 pub num_block_errors_min: u32,
49 pub num_blocks_per_run: u32,
51 pub num_runs_min: u32,
53 pub num_runs_max: u32,
55}
56
57impl SimParams {
58 fn check(&self) -> Result<(), Error> {
60 if qpp_coefficients(usize::try_from(self.num_info_bits_per_block).unwrap()).is_err() {
63 return Err(Error::InvalidInput(format!(
64 "{} is not a valid number of information bits per block",
65 self.num_info_bits_per_block
66 )));
67 }
68 if self.num_blocks_per_run == 0 {
69 return Err(Error::InvalidInput(
70 "Number of blocks per run cannot be zero".to_string(),
71 ));
72 }
73 if self.num_runs_min > self.num_runs_max {
74 return Err(Error::InvalidInput(format!(
75 "Minimum number of runs ({}) exceeds maximum number of runs ({})",
76 self.num_runs_min, self.num_runs_max
77 )));
78 }
79 Ok(())
80 }
81
82 fn print(&self) {
84 eprintln!();
85 self.print_num_info_bits_per_block();
86 self.print_decoding_algo();
87 self.print_es_over_n0_db();
88 self.print_num_block_errors_min();
89 self.print_num_blocks_per_run();
90 self.print_num_runs_min();
91 self.print_num_runs_max();
92 }
93
94 fn print_num_info_bits_per_block(&self) {
96 eprintln!(
97 "{:?} information bits per block",
98 self.num_info_bits_per_block,
99 );
100 }
101
102 fn print_decoding_algo(&self) {
104 eprintln!("{}", self.decoding_algo);
105 }
106
107 fn print_es_over_n0_db(&self) {
109 eprintln!("Es/N0 of {} dB", self.es_over_n0_db);
110 }
111
112 fn print_num_block_errors_min(&self) {
114 eprintln!("Minimum of {} block errors", self.num_block_errors_min);
115 }
116
117 fn print_num_blocks_per_run(&self) {
119 eprintln!("{} blocks per run", self.num_blocks_per_run);
120 }
121
122 fn print_num_runs_min(&self) {
124 eprintln!("Minimum of {} runs", self.num_runs_min);
125 }
126
127 fn print_num_runs_max(&self) {
129 eprintln!("Maximum of {} runs", self.num_runs_max);
130 }
131}
132
133#[derive(Clone, PartialEq, Debug, Copy, Deserialize, Serialize)]
135pub struct SimResults {
136 pub params: SimParams,
138 pub num_blocks: u32,
140 pub num_info_bits: u32,
142 pub num_block_errors: u32,
144 pub num_info_bit_errors: u32,
146}
147
148impl SimResults {
149 #[must_use]
151 fn new(params: &SimParams) -> Self {
152 Self {
153 params: *params,
154 num_blocks: 0,
155 num_info_bits: 0,
156 num_block_errors: 0,
157 num_info_bit_errors: 0,
158 }
159 }
160
161 #[must_use]
163 pub fn block_error_rate(&self) -> f64 {
164 if self.num_blocks > 0 {
165 f64::from(self.num_block_errors) / f64::from(self.num_blocks)
166 } else {
167 0.0
168 }
169 }
170
171 #[must_use]
173 pub fn info_bit_error_rate(&self) -> f64 {
174 if self.num_info_bits > 0 {
175 f64::from(self.num_info_bit_errors) / f64::from(self.num_info_bits)
176 } else {
177 0.0
178 }
179 }
180
181 #[allow(dead_code)]
183 fn print_progress_message(&self) {
184 if self.run_complete() {
185 eprint!(
186 "\rBER = {}/{}, BLER = {}/{}",
187 self.num_info_bit_errors,
188 self.num_info_bits,
189 self.num_block_errors,
190 self.num_blocks,
191 );
192 if self.sim_complete() {
193 eprintln!();
194 }
195 }
196 }
197
198 fn run_complete(&self) -> bool {
200 self.num_blocks % self.params.num_blocks_per_run == 0
201 }
202
203 fn sim_complete(&self) -> bool {
205 self.run_complete()
206 && self.num_blocks >= self.params.num_runs_min * self.params.num_blocks_per_run
207 && (self.num_block_errors >= self.params.num_block_errors_min
208 || self.num_blocks >= self.params.num_runs_max * self.params.num_blocks_per_run)
209 }
210
211 fn update_after_block(&mut self, num_info_bit_errors_this_block: u32) {
213 self.num_blocks += 1;
214 self.num_info_bits += self.params.num_info_bits_per_block;
215 if num_info_bit_errors_this_block > 0 {
216 self.num_block_errors += 1;
217 self.num_info_bit_errors += num_info_bit_errors_this_block;
218 }
219 }
220}
221
222#[derive(Clone, Eq, Hash, PartialEq, Debug, Copy)]
224struct SimCase {
225 num_info_bits_per_block: u32,
226 decoding_algo: DecodingAlgo,
227}
228
229impl std::fmt::Display for SimCase {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 write!(
232 f,
233 "{} bits/block, {}",
234 self.num_info_bits_per_block, self.decoding_algo
235 )
236 }
237}
238
239impl From<&SimResults> for SimCase {
240 fn from(results: &SimResults) -> SimCase {
241 SimCase {
242 num_info_bits_per_block: results.params.num_info_bits_per_block,
243 decoding_algo: results.params.decoding_algo,
244 }
245 }
246}
247
248pub fn encoder(info_bits: &[Bit]) -> Result<Vec<Bit>, Error> {
263 let qpp_interleaver = interleaver(info_bits.len())?;
264 crate::encoder(info_bits, &qpp_interleaver, &CODE_POLYNOMIALS)
265}
266
267pub fn decoder(code_bits_llr: &[f64], decoding_algo: DecodingAlgo) -> Result<Vec<Bit>, Error> {
285 if code_bits_llr.len() < NUM_TAIL_CODE_BITS {
286 return Err(Error::InvalidInput(format!(
287 "Expected a minimum of {NUM_TAIL_CODE_BITS} code bit LLR values (found {})",
288 code_bits_llr.len()
289 )));
290 }
291 let num_info_bits = (code_bits_llr.len() - NUM_TAIL_CODE_BITS) / INVERSE_CODE_RATE;
292 let qpp_interleaver = interleaver(num_info_bits)?;
293 crate::decoder(
294 code_bits_llr,
295 &qpp_interleaver,
296 &CODE_POLYNOMIALS,
297 decoding_algo,
298 )
299}
300
301#[allow(clippy::cast_possible_truncation)]
335#[allow(clippy::missing_panics_doc)]
336pub fn bpsk_awgn_sim(params: &SimParams) -> Result<SimResults, Error> {
337 params.check()?;
338 let mut results = SimResults::new(params);
339 while !results.sim_complete() {
340 let all_num_info_bit_errors_this_run: Vec<usize> = (0 .. params.num_blocks_per_run)
341 .into_par_iter()
342 .map(|_| {
343 let info_bits =
344 utils::random_bits(usize::try_from(params.num_info_bits_per_block).unwrap());
345 let code_bits = encoder(&info_bits).unwrap();
346 let code_bits_llr = utils::bpsk_awgn_channel(&code_bits, params.es_over_n0_db);
347 let info_bits_hat = decoder(&code_bits_llr, params.decoding_algo).unwrap();
348 utils::error_count(&info_bits_hat, &info_bits)
349 })
350 .collect();
351 for num_info_bit_errors_this_block in all_num_info_bit_errors_this_run {
352 results.update_after_block(u32::try_from(num_info_bit_errors_this_block).unwrap());
353 }
354 }
359 Ok(results)
360}
361
362pub fn run_bpsk_awgn_sims(all_params: &[SimParams], json_filename: &str) -> Result<(), Error> {
398 for params in all_params {
399 if params.check().is_err() {
400 params.print();
401 eprintln!("WARNING: Ignoring above simulation parameters as they are invalid");
402 }
403 }
404 let all_results: Vec<SimResults> = all_params
405 .par_iter()
406 .filter_map(|params| bpsk_awgn_sim(params).ok())
407 .collect();
408 summarize_all_sim_results(&all_results);
409 save_all_sim_results_to_file(&all_results, json_filename)?;
410 Ok(())
411}
412
413fn summarize_all_sim_results(all_results: &[SimResults]) {
415 let mut all_cases: Vec<SimCase> = all_results.iter().map(SimCase::from).unique().collect();
416 all_cases.sort_by_key(|case| case.num_info_bits_per_block);
417 for case in all_cases {
418 let all_results_for_case = all_sim_results_for_sim_case(all_results, case);
419 let all_es_over_n0_db = all_results_for_case
420 .iter()
421 .map(|&results| results.params.es_over_n0_db);
422 let all_info_bit_error_rate = all_results_for_case
423 .iter()
424 .map(|&results| results.info_bit_error_rate());
425 let all_block_error_rate = all_results_for_case
426 .iter()
427 .map(|&results| results.block_error_rate());
428 let banner_str = "=".repeat(case.to_string().len());
429 println!("\n{banner_str}");
430 println!("{case}");
431 println!("{banner_str}");
432 println!(" Es/N0 (dB) BER BLER");
433 all_info_bit_error_rate
434 .zip(all_block_error_rate)
435 .zip(all_es_over_n0_db)
436 .for_each(|((ber, bler), es_over_n0_db)| {
437 println!("{es_over_n0_db:>8.2} {ber:7.2e} {bler:7.2e}");
438 });
439 }
440}
441
442fn save_all_sim_results_to_file(
444 all_results: &[SimResults],
445 json_filename: &str,
446) -> Result<(), Error> {
447 let writer = std::io::BufWriter::new(std::fs::File::create(json_filename)?);
448 serde_json::to_writer_pretty(writer, all_results)?;
449 Ok(())
450}
451
452#[allow(clippy::cast_possible_truncation)]
454fn all_sim_results_for_sim_case(all_results: &[SimResults], case: SimCase) -> Vec<SimResults> {
455 let mut all_results_for_case = Vec::new();
456 for results in all_results {
457 if SimCase::from(results) == case {
458 all_results_for_case.push(*results);
459 }
460 }
461 all_results_for_case.sort_by_key(|results| (1e6 * results.params.es_over_n0_db) as i32);
464 all_results_for_case
465}
466
467#[allow(dead_code)]
469fn all_sim_results_from_file(json_filename: &str) -> Result<Vec<SimResults>, Error> {
470 let reader = std::io::BufReader::new(std::fs::File::open(json_filename)?);
471 let all_results = serde_json::from_reader(reader)?;
472 Ok(all_results)
473}
474
475fn interleaver(num_info_bits: usize) -> Result<Interleaver, Error> {
477 let (coeff1, coeff2) = qpp_coefficients(num_info_bits)?;
478 let perm: Vec<usize> = (0 .. num_info_bits)
479 .map(|out_index| ((coeff1 + coeff2 * out_index) * out_index) % num_info_bits)
480 .collect();
481 Interleaver::new(&perm)
482}
483
484fn qpp_coefficients(num_info_bits: usize) -> Result<(usize, usize), Error> {
486 if num_info_bits <= 128 {
487 qpp_coefficients_40_to_128_bits(num_info_bits)
488 } else if num_info_bits <= 256 {
489 qpp_coefficients_136_to_256_bits(num_info_bits)
490 } else if num_info_bits <= 512 {
491 qpp_coefficients_264_to_512_bits(num_info_bits)
492 } else if num_info_bits <= 1024 {
493 qpp_coefficients_528_to_1024_bits(num_info_bits)
494 } else if num_info_bits <= 2048 {
495 qpp_coefficients_1056_to_2048_bits(num_info_bits)
496 } else if num_info_bits <= 4096 {
497 qpp_coefficients_2112_to_4096_bits(num_info_bits)
498 } else {
499 qpp_coefficients_4160_to_6144_bits(num_info_bits)
500 }
501}
502
503fn qpp_coefficients_40_to_128_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
505 match num_info_bits {
506 40 => Ok((3, 10)),
507 48 => Ok((7, 12)),
508 56 => Ok((19, 42)),
509 64 => Ok((7, 16)),
510 72 => Ok((7, 18)),
511 80 => Ok((11, 20)),
512 88 => Ok((5, 22)),
513 96 => Ok((11, 24)),
514 104 => Ok((7, 26)),
515 112 => Ok((41, 84)),
516 120 => Ok((103, 90)),
517 128 => Ok((15, 32)),
518 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
519 num_info_bits,
520 ))),
521 }
522}
523
524fn qpp_coefficients_136_to_256_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
526 match num_info_bits {
527 136 => Ok((9, 34)),
528 144 => Ok((17, 108)),
529 152 => Ok((9, 38)),
530 160 => Ok((21, 120)),
531 168 => Ok((101, 84)),
532 176 => Ok((21, 44)),
533 184 => Ok((57, 46)),
534 192 => Ok((23, 48)),
535 200 => Ok((13, 50)),
536 208 => Ok((27, 52)),
537 216 => Ok((11, 36)),
538 224 => Ok((27, 56)),
539 232 => Ok((85, 58)),
540 240 => Ok((29, 60)),
541 248 => Ok((33, 62)),
542 256 => Ok((15, 32)),
543 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
544 num_info_bits,
545 ))),
546 }
547}
548
549fn qpp_coefficients_264_to_512_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
551 match num_info_bits {
552 264 => Ok((17, 198)),
553 272 => Ok((33, 68)),
554 280 => Ok((103, 210)),
555 288 => Ok((19, 36)),
556 296 => Ok((19, 74)),
557 304 => Ok((37, 76)),
558 312 => Ok((19, 78)),
559 320 => Ok((21, 120)),
560 328 => Ok((21, 82)),
561 336 => Ok((115, 84)),
562 344 => Ok((193, 86)),
563 352 => Ok((21, 44)),
564 360 => Ok((133, 90)),
565 368 => Ok((81, 46)),
566 376 => Ok((45, 94)),
567 384 => Ok((23, 48)),
568 392 => Ok((243, 98)),
569 400 => Ok((151, 40)),
570 408 => Ok((155, 102)),
571 416 => Ok((25, 52)),
572 424 => Ok((51, 106)),
573 432 => Ok((47, 72)),
574 440 => Ok((91, 110)),
575 448 => Ok((29, 168)),
576 456 => Ok((29, 114)),
577 464 => Ok((247, 58)),
578 472 => Ok((29, 118)),
579 480 => Ok((89, 180)),
580 488 => Ok((91, 122)),
581 496 => Ok((157, 62)),
582 504 => Ok((55, 84)),
583 512 => Ok((31, 64)),
584 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
585 num_info_bits,
586 ))),
587 }
588}
589
590fn qpp_coefficients_528_to_1024_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
592 match num_info_bits {
593 528 => Ok((17, 66)),
594 544 => Ok((35, 68)),
595 560 => Ok((227, 420)),
596 576 => Ok((65, 96)),
597 592 => Ok((19, 74)),
598 608 => Ok((37, 76)),
599 624 => Ok((41, 234)),
600 640 => Ok((39, 80)),
601 656 => Ok((185, 82)),
602 672 => Ok((43, 252)),
603 688 => Ok((21, 86)),
604 704 => Ok((155, 44)),
605 720 => Ok((79, 120)),
606 736 => Ok((139, 92)),
607 752 => Ok((23, 94)),
608 768 => Ok((217, 48)),
609 784 => Ok((25, 98)),
610 800 => Ok((17, 80)),
611 816 => Ok((127, 102)),
612 832 => Ok((25, 52)),
613 848 => Ok((239, 106)),
614 864 => Ok((17, 48)),
615 880 => Ok((137, 110)),
616 896 => Ok((215, 112)),
617 912 => Ok((29, 114)),
618 928 => Ok((15, 58)),
619 944 => Ok((147, 118)),
620 960 => Ok((29, 60)),
621 976 => Ok((59, 122)),
622 992 => Ok((65, 124)),
623 1008 => Ok((55, 84)),
624 1024 => Ok((31, 64)),
625 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
626 num_info_bits,
627 ))),
628 }
629}
630
631fn qpp_coefficients_1056_to_2048_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
633 match num_info_bits {
634 1056 => Ok((17, 66)),
635 1088 => Ok((171, 204)),
636 1120 => Ok((67, 140)),
637 1152 => Ok((35, 72)),
638 1184 => Ok((19, 74)),
639 1216 => Ok((39, 76)),
640 1248 => Ok((19, 78)),
641 1280 => Ok((199, 240)),
642 1312 => Ok((21, 82)),
643 1344 => Ok((211, 252)),
644 1376 => Ok((21, 86)),
645 1408 => Ok((43, 88)),
646 1440 => Ok((149, 60)),
647 1472 => Ok((45, 92)),
648 1504 => Ok((49, 846)),
649 1536 => Ok((71, 48)),
650 1568 => Ok((13, 28)),
651 1600 => Ok((17, 80)),
652 1632 => Ok((25, 102)),
653 1664 => Ok((183, 104)),
654 1696 => Ok((55, 954)),
655 1728 => Ok((127, 96)),
656 1760 => Ok((27, 110)),
657 1792 => Ok((29, 112)),
658 1824 => Ok((29, 114)),
659 1856 => Ok((57, 116)),
660 1888 => Ok((45, 354)),
661 1920 => Ok((31, 120)),
662 1952 => Ok((59, 610)),
663 1984 => Ok((185, 124)),
664 2016 => Ok((113, 420)),
665 2048 => Ok((31, 64)),
666 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
667 num_info_bits,
668 ))),
669 }
670}
671
672fn qpp_coefficients_2112_to_4096_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
674 match num_info_bits {
675 2112 => Ok((17, 66)),
676 2176 => Ok((171, 136)),
677 2240 => Ok((209, 420)),
678 2304 => Ok((253, 216)),
679 2368 => Ok((367, 444)),
680 2432 => Ok((265, 456)),
681 2496 => Ok((181, 468)),
682 2560 => Ok((39, 80)),
683 2624 => Ok((27, 164)),
684 2688 => Ok((127, 504)),
685 2752 => Ok((143, 172)),
686 2816 => Ok((43, 88)),
687 2880 => Ok((29, 300)),
688 2944 => Ok((45, 92)),
689 3008 => Ok((157, 188)),
690 3072 => Ok((47, 96)),
691 3136 => Ok((13, 28)),
692 3200 => Ok((111, 240)),
693 3264 => Ok((443, 204)),
694 3328 => Ok((51, 104)),
695 3392 => Ok((51, 212)),
696 3456 => Ok((451, 192)),
697 3520 => Ok((257, 220)),
698 3584 => Ok((57, 336)),
699 3648 => Ok((313, 228)),
700 3712 => Ok((271, 232)),
701 3776 => Ok((179, 236)),
702 3840 => Ok((331, 120)),
703 3904 => Ok((363, 244)),
704 3968 => Ok((375, 248)),
705 4032 => Ok((127, 168)),
706 4096 => Ok((31, 64)),
707 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
708 num_info_bits,
709 ))),
710 }
711}
712
713fn qpp_coefficients_4160_to_6144_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
715 match num_info_bits {
716 4160 => Ok((33, 130)),
717 4224 => Ok((43, 264)),
718 4288 => Ok((33, 134)),
719 4352 => Ok((477, 408)),
720 4416 => Ok((35, 138)),
721 4480 => Ok((233, 280)),
722 4544 => Ok((357, 142)),
723 4608 => Ok((337, 480)),
724 4672 => Ok((37, 146)),
725 4736 => Ok((71, 444)),
726 4800 => Ok((71, 120)),
727 4864 => Ok((37, 152)),
728 4928 => Ok((39, 462)),
729 4992 => Ok((127, 234)),
730 5056 => Ok((39, 158)),
731 5120 => Ok((39, 80)),
732 5184 => Ok((31, 96)),
733 5248 => Ok((113, 902)),
734 5312 => Ok((41, 166)),
735 5376 => Ok((251, 336)),
736 5440 => Ok((43, 170)),
737 5504 => Ok((21, 86)),
738 5568 => Ok((43, 174)),
739 5632 => Ok((45, 176)),
740 5696 => Ok((45, 178)),
741 5760 => Ok((161, 120)),
742 5824 => Ok((89, 182)),
743 5888 => Ok((323, 184)),
744 5952 => Ok((47, 186)),
745 6016 => Ok((23, 94)),
746 6080 => Ok((47, 190)),
747 6144 => Ok((263, 480)),
748 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
749 num_info_bits,
750 ))),
751 }
752}
753
754fn invalid_num_info_bits_message(num_info_bits: usize) -> String {
756 format!("Number of information bits {num_info_bits} is not in Table 5.1.3-3 of 3GPP TS 36.212")
757}
758
759#[cfg(test)]
760mod tests_of_simparams {
761 use super::*;
762
763 #[test]
764 fn test_check() {
765 let params = SimParams {
767 num_info_bits_per_block: 32,
768 decoding_algo: DecodingAlgo::LinearLogMAP(8),
769 es_over_n0_db: -3.0,
770 num_block_errors_min: 10,
771 num_blocks_per_run: 1,
772 num_runs_min: 1,
773 num_runs_max: 2,
774 };
775 assert!(params.check().is_err());
776 let params = SimParams {
777 num_info_bits_per_block: 40,
778 decoding_algo: DecodingAlgo::LinearLogMAP(8),
779 es_over_n0_db: -3.0,
780 num_block_errors_min: 10,
781 num_blocks_per_run: 0,
782 num_runs_min: 1,
783 num_runs_max: 2,
784 };
785 assert!(params.check().is_err());
786 let params = SimParams {
787 num_info_bits_per_block: 40,
788 decoding_algo: DecodingAlgo::LinearLogMAP(8),
789 es_over_n0_db: -3.0,
790 num_block_errors_min: 10,
791 num_blocks_per_run: 1,
792 num_runs_min: 2,
793 num_runs_max: 1,
794 };
795 assert!(params.check().is_err());
796 let params = SimParams {
798 num_info_bits_per_block: 40,
799 decoding_algo: DecodingAlgo::LinearLogMAP(8),
800 es_over_n0_db: -3.0,
801 num_block_errors_min: 10,
802 num_blocks_per_run: 1,
803 num_runs_min: 1,
804 num_runs_max: 2,
805 };
806 assert!(params.check().is_ok());
807 }
808
809 #[test]
810 fn test_print() {
811 let params = SimParams {
812 num_info_bits_per_block: 40,
813 decoding_algo: DecodingAlgo::LinearLogMAP(8),
814 es_over_n0_db: -3.0,
815 num_block_errors_min: 100,
816 num_blocks_per_run: 1000,
817 num_runs_min: 1,
818 num_runs_max: 10,
819 };
820 params.print();
821 }
822}
823
824#[cfg(test)]
825mod tests_of_simresults {
826 use float_eq::assert_float_eq;
827
828 use super::*;
829
830 fn params_for_test() -> SimParams {
831 SimParams {
832 num_info_bits_per_block: 48,
833 decoding_algo: DecodingAlgo::LinearLogMAP(8),
834 es_over_n0_db: -3.0,
835 num_block_errors_min: 100,
836 num_blocks_per_run: 1000,
837 num_runs_min: 1,
838 num_runs_max: 10,
839 }
840 }
841
842 fn results_for_test(num_blocks: u32, num_block_errors: u32) -> SimResults {
843 let params = params_for_test();
844 let num_info_bits = num_blocks * params.num_info_bits_per_block;
845 let num_info_bit_errors = num_block_errors * 10;
846 SimResults {
847 params,
848 num_blocks,
849 num_info_bits,
850 num_block_errors,
851 num_info_bit_errors,
852 }
853 }
854
855 #[test]
856 fn test_new() {
857 let results = SimResults::new(¶ms_for_test());
858 assert_eq!(results.num_blocks, 0);
859 assert_eq!(results.num_info_bits, 0);
860 assert_eq!(results.num_block_errors, 0);
861 assert_eq!(results.num_info_bit_errors, 0);
862 }
863
864 #[test]
865 fn test_block_error_rate() {
866 let results = results_for_test(2000, 10);
867 assert_float_eq!(results.block_error_rate(), 10.0 / 2000.0, abs <= 1e-8);
868 }
869
870 #[test]
871 fn test_info_bit_error_rate() {
872 let results = results_for_test(2000, 10);
873 assert_float_eq!(results.info_bit_error_rate(), 100.0 / 96000.0, abs <= 1e-8);
874 }
875
876 #[test]
877 fn test_print_progress_message() {
878 let results = results_for_test(1000, 10);
879 results.print_progress_message();
880 }
881
882 #[test]
883 fn test_run_complete() {
884 let results = results_for_test(999, 0);
885 assert!(!results.run_complete());
886 let results = results_for_test(1000, 0);
887 assert!(results.run_complete());
888 let results = results_for_test(1001, 0);
889 assert!(!results.run_complete());
890 }
891
892 #[test]
893 fn test_sim_complete() {
894 let results = results_for_test(5000, 99);
896 assert!(!results.sim_complete());
897 let results = results_for_test(5000, 100);
898 assert!(results.sim_complete());
899 let results = results_for_test(4999, 500);
901 assert!(!results.sim_complete());
902 let results = results_for_test(5000, 500);
903 assert!(results.sim_complete());
904 let results = results_for_test(5001, 500);
905 assert!(!results.sim_complete());
906 let results = results_for_test(999, 500);
908 assert!(!results.sim_complete());
909 let results = results_for_test(1000, 500);
910 assert!(results.sim_complete());
911 let results = results_for_test(9999, 50);
913 assert!(!results.sim_complete());
914 let results = results_for_test(10000, 50);
915 assert!(results.sim_complete());
916 }
917
918 #[test]
919 fn test_update_after_block() {
920 let mut results = results_for_test(100, 10);
922 results.update_after_block(0);
923 assert_eq!(results.num_blocks, 101);
924 assert_eq!(results.num_info_bits, 4848);
925 assert_eq!(results.num_block_errors, 10);
926 assert_eq!(results.num_info_bit_errors, 100);
927 let mut results = results_for_test(100, 10);
929 results.update_after_block(10);
930 assert_eq!(results.num_blocks, 101);
931 assert_eq!(results.num_info_bits, 4848);
932 assert_eq!(results.num_block_errors, 11);
933 assert_eq!(results.num_info_bit_errors, 110);
934 }
935}
936
937#[cfg(test)]
938mod tests_of_functions {
939 use super::*;
940
941 #[test]
942 fn test_encoder() {
943 let info_bits = utils::random_bits(40);
944 assert!(encoder(&info_bits).is_ok());
945 }
946
947 #[test]
948 fn test_decoder() {
949 let code_bits_llr = utils::bpsk_awgn_channel(&utils::random_bits(132), 10.0);
950 assert!(decoder(&code_bits_llr, DecodingAlgo::LinearLogMAP(8)).is_ok());
951 }
952
953 #[test]
954 fn test_bpsk_awgn_sim() {
955 let params = SimParams {
957 num_info_bits_per_block: 32,
958 decoding_algo: DecodingAlgo::LinearLogMAP(8),
959 es_over_n0_db: -3.0,
960 num_block_errors_min: 10,
961 num_blocks_per_run: 10,
962 num_runs_min: 1,
963 num_runs_max: 2,
964 };
965 assert!(bpsk_awgn_sim(¶ms).is_err());
966 let params = SimParams {
968 num_info_bits_per_block: 40,
969 decoding_algo: DecodingAlgo::LinearLogMAP(8),
970 es_over_n0_db: -3.0,
971 num_block_errors_min: 10,
972 num_blocks_per_run: 10,
973 num_runs_min: 1,
974 num_runs_max: 2,
975 };
976 assert!(bpsk_awgn_sim(¶ms).is_ok());
977 }
978
979 #[test]
980 fn test_run_bpsk_awgn_sims() {
981 let all_params = vec![
982 SimParams {
983 num_info_bits_per_block: 36,
984 decoding_algo: DecodingAlgo::LinearLogMAP(8),
985 es_over_n0_db: -3.0,
986 num_block_errors_min: 20,
987 num_blocks_per_run: 10,
988 num_runs_min: 1,
989 num_runs_max: 2,
990 },
991 SimParams {
992 num_info_bits_per_block: 40,
993 decoding_algo: DecodingAlgo::LinearLogMAP(8),
994 es_over_n0_db: -3.0,
995 num_block_errors_min: 10,
996 num_blocks_per_run: 10,
997 num_runs_min: 1,
998 num_runs_max: 2,
999 },
1000 SimParams {
1001 num_info_bits_per_block: 44,
1002 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1003 es_over_n0_db: -3.0,
1004 num_block_errors_min: 10,
1005 num_blocks_per_run: 10,
1006 num_runs_min: 1,
1007 num_runs_max: 2,
1008 },
1009 SimParams {
1010 num_info_bits_per_block: 48,
1011 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1012 es_over_n0_db: -3.0,
1013 num_block_errors_min: 10,
1014 num_blocks_per_run: 10,
1015 num_runs_min: 1,
1016 num_runs_max: 2,
1017 },
1018 ];
1019 run_bpsk_awgn_sims(&all_params, "results.json").unwrap();
1020 }
1021
1022 fn all_sim_params_for_test() -> Vec<SimParams> {
1023 let mut all_params = Vec::new();
1024 for num_info_bits_per_block in [40, 48] {
1025 for es_over_n0_db in [-3.5, -3.0, -4.0] {
1026 all_params.push(SimParams {
1027 num_info_bits_per_block,
1028 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1029 es_over_n0_db,
1030 num_block_errors_min: 20,
1031 num_blocks_per_run: 10,
1032 num_runs_min: 1,
1033 num_runs_max: 10,
1034 });
1035 }
1036 }
1037 all_params
1038 }
1039
1040 fn all_sim_results_for_test(all_params: &[SimParams]) -> Vec<SimResults> {
1041 let mut all_results = Vec::new();
1042 for params in all_params {
1043 all_results.push(SimResults::new(params));
1044 }
1045 all_results
1046 }
1047
1048 #[test]
1049 fn test_summarize_all_sim_results() {
1050 let all_results = all_sim_results_for_test(&all_sim_params_for_test());
1051 summarize_all_sim_results(&all_results);
1052 }
1053
1054 #[test]
1055 fn test_all_sim_results_for_sim_case() {
1056 let all_results = all_sim_results_for_test(&all_sim_params_for_test());
1057 assert_eq!(
1058 all_sim_results_for_sim_case(
1059 &all_results,
1060 SimCase {
1061 num_info_bits_per_block: 40,
1062 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1063 },
1064 ),
1065 [all_results[2], all_results[0], all_results[1]]
1066 );
1067 assert_eq!(
1068 all_sim_results_for_sim_case(
1069 &all_results,
1070 SimCase {
1071 num_info_bits_per_block: 48,
1072 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1073 },
1074 ),
1075 [all_results[5], all_results[3], all_results[4]]
1076 );
1077 }
1078
1079 #[test]
1080 fn test_interleaver() {
1081 assert!(interleaver(32).is_err());
1083 for num in 0 .. 60 {
1085 let num_info_bits = 40 + 8 * num;
1086 assert!(interleaver(num_info_bits).is_ok());
1087 }
1088 for num in 0 .. 32 {
1089 let num_info_bits = 528 + 16 * num;
1090 assert!(interleaver(num_info_bits).is_ok());
1091 }
1092 for num in 0 .. 32 {
1093 let num_info_bits = 1056 + 32 * num;
1094 assert!(interleaver(num_info_bits).is_ok());
1095 }
1096 for num in 0 .. 64 {
1097 let num_info_bits = 2112 + 64 * num;
1098 assert!(interleaver(num_info_bits).is_ok());
1099 }
1100 assert!(interleaver(6208).is_err());
1102 }
1103
1104 #[test]
1105 fn test_qpp_coefficients() {
1106 assert!(qpp_coefficients(32).is_err());
1108 for num in 0 .. 60 {
1110 let num_info_bits = 40 + 8 * num;
1111 assert!(qpp_coefficients(num_info_bits).is_ok());
1112 }
1113 for num in 0 .. 32 {
1114 let num_info_bits = 528 + 16 * num;
1115 assert!(qpp_coefficients(num_info_bits).is_ok());
1116 }
1117 for num in 0 .. 32 {
1118 let num_info_bits = 1056 + 32 * num;
1119 assert!(qpp_coefficients(num_info_bits).is_ok());
1120 }
1121 for num in 0 .. 64 {
1122 let num_info_bits = 2112 + 64 * num;
1123 assert!(qpp_coefficients(num_info_bits).is_ok());
1124 }
1125 assert!(qpp_coefficients(6208).is_err());
1127 }
1128
1129 #[test]
1130 fn test_qpp_coefficients_40_to_128_bits() {
1131 assert!(qpp_coefficients_40_to_128_bits(32).is_err());
1133 assert!(qpp_coefficients_40_to_128_bits(84).is_err());
1134 assert!(qpp_coefficients_40_to_128_bits(136).is_err());
1135 assert_eq!(qpp_coefficients_40_to_128_bits(40).unwrap(), (3, 10));
1137 assert_eq!(qpp_coefficients_40_to_128_bits(128).unwrap(), (15, 32));
1138 }
1139
1140 #[test]
1141 fn test_qpp_coefficients_136_to_256_bits() {
1142 assert!(qpp_coefficients_136_to_256_bits(128).is_err());
1144 assert!(qpp_coefficients_136_to_256_bits(196).is_err());
1145 assert!(qpp_coefficients_136_to_256_bits(264).is_err());
1146 assert_eq!(qpp_coefficients_136_to_256_bits(136).unwrap(), (9, 34));
1148 assert_eq!(qpp_coefficients_136_to_256_bits(256).unwrap(), (15, 32));
1149 }
1150
1151 #[test]
1152 fn test_qpp_coefficients_264_to_512_bits() {
1153 assert!(qpp_coefficients_264_to_512_bits(256).is_err());
1155 assert!(qpp_coefficients_264_to_512_bits(388).is_err());
1156 assert!(qpp_coefficients_264_to_512_bits(520).is_err());
1157 assert_eq!(qpp_coefficients_264_to_512_bits(264).unwrap(), (17, 198));
1159 assert_eq!(qpp_coefficients_264_to_512_bits(512).unwrap(), (31, 64));
1160 }
1161
1162 #[test]
1163 fn test_qpp_coefficients_528_to_1024_bits() {
1164 assert!(qpp_coefficients_528_to_1024_bits(512).is_err());
1166 assert!(qpp_coefficients_528_to_1024_bits(776).is_err());
1167 assert!(qpp_coefficients_528_to_1024_bits(1040).is_err());
1168 assert_eq!(qpp_coefficients_528_to_1024_bits(528).unwrap(), (17, 66));
1170 assert_eq!(qpp_coefficients_528_to_1024_bits(1024).unwrap(), (31, 64));
1171 }
1172
1173 #[test]
1174 fn test_qpp_coefficients_1056_to_2048_bits() {
1175 assert!(qpp_coefficients_1056_to_2048_bits(1024).is_err());
1177 assert!(qpp_coefficients_1056_to_2048_bits(1552).is_err());
1178 assert!(qpp_coefficients_1056_to_2048_bits(2080).is_err());
1179 assert_eq!(qpp_coefficients_1056_to_2048_bits(1056).unwrap(), (17, 66));
1181 assert_eq!(qpp_coefficients_1056_to_2048_bits(2048).unwrap(), (31, 64));
1182 }
1183
1184 #[test]
1185 fn test_qpp_coefficients_2112_to_4096_bits() {
1186 assert!(qpp_coefficients_2112_to_4096_bits(2048).is_err());
1188 assert!(qpp_coefficients_2112_to_4096_bits(3104).is_err());
1189 assert!(qpp_coefficients_2112_to_4096_bits(4160).is_err());
1190 assert_eq!(qpp_coefficients_2112_to_4096_bits(2112).unwrap(), (17, 66));
1192 assert_eq!(qpp_coefficients_2112_to_4096_bits(4096).unwrap(), (31, 64));
1193 }
1194
1195 #[test]
1196 fn test_qpp_coefficients_4160_to_6144_bits() {
1197 assert!(qpp_coefficients_4160_to_6144_bits(4096).is_err());
1199 assert!(qpp_coefficients_4160_to_6144_bits(5152).is_err());
1200 assert!(qpp_coefficients_4160_to_6144_bits(6208).is_err());
1201 assert_eq!(qpp_coefficients_4160_to_6144_bits(4160).unwrap(), (33, 130));
1203 assert_eq!(
1204 qpp_coefficients_4160_to_6144_bits(6144).unwrap(),
1205 (263, 480)
1206 );
1207 }
1208}