Example #1
0
    private void FixedUpdate()
    {
        FixUpdateCount += 1;
        Rx_MPC1         = Rx_Seen_MPC_Script.seen_MPC1;
        Rx_MPC1_att     = Rx_Seen_MPC_Script.seen_MPC1_att;

        Rx_MPC2     = Rx_Seen_MPC_Script.seen_MPC2;
        Rx_MPC2_att = Rx_Seen_MPC_Script.seen_MPC2_att;

        Rx_MPC3     = Rx_Seen_MPC_Script.seen_MPC3;
        Rx_MPC3_att = Rx_Seen_MPC_Script.seen_MPC3_att;

        Tx_MPC1     = Tx_Seen_MPC_Script.seen_MPC1;
        Tx_MPC1_att = Tx_Seen_MPC_Script.seen_MPC1_att;

        Tx_MPC2     = Tx_Seen_MPC_Script.seen_MPC2;
        Tx_MPC2_att = Tx_Seen_MPC_Script.seen_MPC2_att;

        Tx_MPC3     = Tx_Seen_MPC_Script.seen_MPC3;
        Tx_MPC3_att = Tx_Seen_MPC_Script.seen_MPC3_att;


        ///////////////////////////////////////////////////////////////////////////////////
        /// LOS
        ///////////////////////////////////////////////////////////////////////////////////

        float dtLoS        = 0;
        float PathGainLoS  = 0;
        float LOS_distance = 0;

        if (!Physics.Linecast(Tx.transform.position, Rx.transform.position))
        {
            Vector3 LoS_dir = (Tx.transform.position - Rx.transform.position).normalized;
            Vector3 Tx_fwd  = Tx.transform.forward;
            Vector3 Rx_fwd  = Rx.transform.forward;
            float   cos_Tx  = -1;
            float   cos_Rx  = -1;
            float   K_antanne_pattern;

            if (Tx_Antenna_pattern)
            {
                cos_Tx = Vector3.Dot(-LoS_dir, Tx_fwd);
            }
            if (Rx_Antenna_pattern)
            {
                cos_Rx = Vector3.Dot(LoS_dir, Rx_fwd);
            }
            K_antanne_pattern = 0.25f * (1 - cos_Rx - cos_Tx + cos_Rx * cos_Tx);

            flag_LoS = 1;
            if (LoS_Start == 0)
            {
                LoS_Start = FixUpdateCount; Debug.Log("LoS Start " + LoS_Start);
            }                                                                                        // finding the start time of LoS

            if (LOS_Tracer)
            {
                Debug.DrawLine(Tx.transform.position, Rx.transform.position, Color.magenta);
            }

            LOS_distance = (Tx.transform.position - Rx.transform.position).magnitude;
            //Debug.Log("Distance = " + LOS_distance);
            //LOS_distance = 200;
            dtLoS       = LOS_distance / SpeedofLight;// + 1000/SpeedofLight;
            PathGainLoS = (1 / (LOS_distance)) * K_antanne_pattern;

            float hbyd           = 3.4f / LOS_distance; // 2h/d; h = 1.7meters
            float Rparallel      = (RelativePermitivity * hbyd - Z) / (RelativePermitivity * hbyd + Z);
            float Rperpendicular = (hbyd - Z) / (hbyd + Z);
            float Rcoef          = (float)Math.Sqrt(0.5f * (Rparallel * Rparallel + Rperpendicular * Rperpendicular));

            //PathGainLoS -= PathGainLoS * Rcoef * Rcoef / 2;
            //float h2byd = 5.78f / LOS_distance; // 2 h^2/2

            EdgeEffect(FixUpdateCount - LoS_Start, out EdgeEffect_LoS);

            // the follwing can be done due to manual calculation of the LoS End
            if (FixUpdateCount > 100 && FixUpdateCount < 126)
            {
                EdgeEffect(124 - FixUpdateCount, out EdgeEffect_LoS);
            }
        }

        /*else
         * {
         *  if (flag_LoS == 1)
         *  {
         *      flag_LoS = 2;
         *      LoS_End = FixUpdateCount;
         *      Debug.Log("LoS End " + LoS_End);
         *      // remember the last LoS channel
         *      for (int i = 0; i < H_LoS.Length; i++)
         *      {
         *          H_old[i] = H_LoS[i];
         *      }
         *  } // finding the end time of LoS
         * }*/

        //Debug.Log("Edge effect coefficient = " + EdgeEffect_LoS);



        var dtLoSParallel       = new NativeArray <float>(1, Allocator.TempJob);
        var distanceLoSParallel = new NativeArray <float>(1, Allocator.TempJob);
        var PathGainLoSParallel = new NativeArray <float>(1, Allocator.TempJob);

        for (int i = 0; i < dtLoSParallel.Length; i++)
        {
            dtLoSParallel[i]       = dtLoS;
            distanceLoSParallel[i] = LOS_distance;
            PathGainLoSParallel[i] = PathGainLoS;
        }

        dtLoSParallel.Dispose();
        distanceLoSParallel.Dispose();
        PathGainLoSParallel.Dispose();
        ///////////////////////////////////////////////////////////////////////////////////
        /// MPC1
        ///////////////////////////////////////////////////////////////////////////////////

        var RxArray1     = new NativeArray <int>(Rx_MPC1.Count, Allocator.TempJob);
        var RxArray1_att = new NativeArray <float>(Rx_MPC1.Count, Allocator.TempJob);
        var TxArray1     = new NativeArray <int>(Tx_MPC1.Count, Allocator.TempJob);
        var TxArray1_att = new NativeArray <float>(Tx_MPC1.Count, Allocator.TempJob);

        var possiblePath1 = new NativeArray <Path1>(Tx_MPC1.Count, Allocator.TempJob);
        var dtMPC1Array   = new NativeArray <float>(Tx_MPC1.Count, Allocator.TempJob);
        var PathGainMPC1  = new NativeArray <float>(Tx_MPC1.Count, Allocator.TempJob);

        for (int i = 0; i < Rx_MPC1.Count; i++)
        {
            RxArray1[i]     = Rx_MPC1[i];
            RxArray1_att[i] = Rx_MPC1_att[i];
        }

        for (int i = 0; i < Tx_MPC1.Count; i++)
        {
            TxArray1[i]      = Tx_MPC1[i];
            TxArray1_att[i]  = Tx_MPC1_att[i];
            possiblePath1[i] = empty_path;
        }
        CommonMPC1Parallel commonMPC1Parallel = new CommonMPC1Parallel
        {
            Speed_of_Light = SpeedofLight,
            MPC1           = SeenMPC1Table,
            Array1         = RxArray1,
            Array1_att     = RxArray1_att,
            Array2         = TxArray1,
            Array2_att     = TxArray1_att,
            Rx_Point       = Rx.transform.position,
            Tx_Point       = Tx.transform.position,

            Output           = possiblePath1,
            OutputDelays     = dtMPC1Array,
            OutputAmplitudes = PathGainMPC1,
        };
        JobHandle jobHandleMPC1 = commonMPC1Parallel.Schedule(TxArray1.Length, 2);

        jobHandleMPC1.Complete();

        // transition from NativeArrays to Lists
        List <Path1> first_order_paths_full_parallel = new List <Path1>();

        if (MPC1_Tracer)
        {
            for (int i = 0; i < possiblePath1.Length; i++)
            {
                if (possiblePath1[i].Distance > 0)
                {
                    first_order_paths_full_parallel.Add(possiblePath1[i]);
                    Debug.DrawLine(possiblePath1[i].Rx_Point, possiblePath1[i].MPC1, Color.cyan);
                    Debug.DrawLine(possiblePath1[i].Tx_Point, possiblePath1[i].MPC1, Color.cyan);
                }
            }
        }



        RxArray1.Dispose();
        RxArray1_att.Dispose();
        TxArray1.Dispose();
        TxArray1_att.Dispose();
        possiblePath1.Dispose();
        dtMPC1Array.Dispose();
        PathGainMPC1.Dispose();
        ///////////////////////////////////////////////////////////////////////////////////
        /// MPC2 Parallel
        ///////////////////////////////////////////////////////////////////////////////////

        var level2MPC2     = new NativeArray <int>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var level2MPC2_att = new NativeArray <float>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var possiblePath2  = new NativeArray <Path2>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var dtArrayMPC2    = new NativeArray <float>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var PathGainMPC2   = new NativeArray <float>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);

        for (int l = 0; l < Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists; l++)
        {
            level2MPC2[l]     = Rx_MPC2[Mathf.FloorToInt(l / MaxLengthOfSeenMPC2Lists)];
            level2MPC2_att[l] = Rx_MPC2_att[Mathf.FloorToInt(l / MaxLengthOfSeenMPC2Lists)];
            possiblePath2[l]  = empty_path2;
        }

        var TxMPC2Array     = new NativeArray <int>(Tx_MPC2.Count, Allocator.TempJob);
        var TxMPC2Array_att = new NativeArray <float>(Tx_MPC2.Count, Allocator.TempJob);

        for (int l = 0; l < Tx_MPC2.Count; l++)
        {
            TxMPC2Array[l]     = Tx_MPC2[l];
            TxMPC2Array_att[l] = Tx_MPC2_att[l];
        }

        Path2ParallelSearch path2ParallelSearch = new Path2ParallelSearch
        {
            // common data
            SeenMPC2Table  = SeenMPC2Table,
            LookUpTable2   = LookUpTable2,
            LookUpTable2ID = LookUpTable2ID,
            // must be disposed
            Rx_MPC2Array     = level2MPC2,
            Rx_MPC2Array_att = level2MPC2_att,
            Tx_MPC2          = TxMPC2Array,
            Tx_MPC2_att      = TxMPC2Array_att,

            // other data
            Rx_Position    = Rx.transform.position,
            Tx_Position    = Tx.transform.position,
            MaxListsLength = MaxLengthOfSeenMPC2Lists,
            Speed_of_Light = SpeedofLight,

            SecondOrderPaths = possiblePath2,
            OutputDelays     = dtArrayMPC2,
            OutputAmplitudes = PathGainMPC2,
        };
        // create a job handle list
        JobHandle jobHandleMPC2 = path2ParallelSearch.Schedule(level2MPC2.Length, MaxLengthOfSeenMPC2Lists, jobHandleMPC1);

        jobHandleMPC2.Complete();



        /// MPC2
        List <Path2> second_order_paths_full_parallel = new List <Path2>();

        if (MPC2_Tracer)
        {
            for (int l = 0; l < possiblePath2.Length; l++)
            {
                if (possiblePath2[l].Distance > 0)
                {
                    second_order_paths_full_parallel.Add(possiblePath2[l]);
                    Debug.DrawLine(possiblePath2[l].Rx_Point, possiblePath2[l].MPC2_1, Color.white);
                    Debug.DrawLine(possiblePath2[l].MPC2_1, possiblePath2[l].MPC2_2, Color.white);
                    Debug.DrawLine(possiblePath2[l].MPC2_2, possiblePath2[l].Tx_Point, Color.white);
                }
            }
        }

        level2MPC2.Dispose();
        level2MPC2_att.Dispose();
        possiblePath2.Dispose();
        TxMPC2Array.Dispose();
        TxMPC2Array_att.Dispose();
        dtArrayMPC2.Dispose();
        PathGainMPC2.Dispose();

        ///////////////////////////////////////////////////////////////////////////////////
        /// MPC3
        ///////////////////////////////////////////////////////////////////////////////////

        if (If_we_need_MPC3 == true)
        {
            // define how many elements should be processed in a single core
            int innerloopBatchCount = MaxLengthOfSeenMPC3Lists;

            Vector3 Rx_Point = Rx.transform.position;
            Vector3 Tx_Point = Tx.transform.position;

            NativeArray <int>       Rx_Seen_MPC3              = new NativeArray <int>(Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            NativeArray <float>     Rx_Seen_MPC3_att          = new NativeArray <float>(Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            NativeArray <Path3Half> RxReachableHalfPath3Array = new NativeArray <Path3Half>(Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            for (int l = 0; l < Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists; l++)
            {
                Rx_Seen_MPC3[l]              = Rx_MPC3[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
                Rx_Seen_MPC3_att[l]          = Rx_MPC3_att[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
                RxReachableHalfPath3Array[l] = empty_path3Half;
            }

            NativeArray <int>       Tx_Seen_MPC3              = new NativeArray <int>(Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            NativeArray <float>     Tx_Seen_MPC3_att          = new NativeArray <float>(Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            NativeArray <Path3Half> TxReachableHalfPath3Array = new NativeArray <Path3Half>(Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            for (int l = 0; l < Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists; l++)
            {
                Tx_Seen_MPC3[l]              = Tx_MPC3[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
                Tx_Seen_MPC3_att[l]          = Tx_MPC3_att[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
                TxReachableHalfPath3Array[l] = empty_path3Half;
            }

            HalfPath3Set RxhalfPath3Set = new HalfPath3Set
            {
                // common data
                SeenMPC3Table  = SeenMPC3Table,
                LookUpTable3   = LookUpTable3,
                LookUpTable3ID = LookUpTable3ID,
                MaxListsLength = MaxLengthOfSeenMPC3Lists,

                // Car specific data
                Point = Rx_Point,
                // must be disposed
                Seen_MPC3          = Rx_Seen_MPC3,
                Seen_MPC3_att      = Rx_Seen_MPC3_att,
                ReachableHalfPath3 = RxReachableHalfPath3Array,
            };
            // create a job handle list
            NativeList <JobHandle> jobHandleList = new NativeList <JobHandle>(Allocator.Temp);

            JobHandle RxjobHandleMPC3 = RxhalfPath3Set.Schedule(Rx_Seen_MPC3.Length, innerloopBatchCount, jobHandleMPC2);
            jobHandleList.Add(RxjobHandleMPC3);

            HalfPath3Set TxhalfPath3Set = new HalfPath3Set
            {
                // common data
                SeenMPC3Table  = SeenMPC3Table,
                LookUpTable3   = LookUpTable3,
                LookUpTable3ID = LookUpTable3ID,
                MaxListsLength = MaxLengthOfSeenMPC3Lists,

                // Car specific data
                Point = Tx_Point,
                // must be disposed
                Seen_MPC3          = Tx_Seen_MPC3,
                Seen_MPC3_att      = Tx_Seen_MPC3_att,
                ReachableHalfPath3 = TxReachableHalfPath3Array,
            };

            JobHandle TxjobHandleMPC3 = TxhalfPath3Set.Schedule(Tx_Seen_MPC3.Length, innerloopBatchCount, jobHandleMPC2);
            jobHandleList.Add(TxjobHandleMPC3);

            JobHandle.CompleteAll(jobHandleList);



            // storing nonempty path3s
            List <Path3Half> TxHalfPath3 = new List <Path3Half>();
            List <Path3Half> RxHalfPath3 = new List <Path3Half>();

            // introducing a little bit of randomness to the third order of paths selection
            int MPC3PathStep = 3; // otherwise, the sets of possible third order of paths become too big
            for (int l = 0; l < TxReachableHalfPath3Array.Length; l += MPC3PathStep)
            {
                if (TxReachableHalfPath3Array[l].Distance > 0)
                {
                    TxHalfPath3.Add(TxReachableHalfPath3Array[l]);
                }
            }
            for (int l = 0; l < RxReachableHalfPath3Array.Length; l += MPC3PathStep)
            {
                if (RxReachableHalfPath3Array[l].Distance > 0)
                {
                    RxHalfPath3.Add(RxReachableHalfPath3Array[l]);
                }
            }



            //float startTime2 = Time.realtimeSinceStartup;

            NativeArray <Path3Half> RxNativeArray = new NativeArray <Path3Half>(RxHalfPath3.Count, Allocator.TempJob);
            for (int i = 0; i < RxNativeArray.Length; i++)
            {
                RxNativeArray[i] = RxHalfPath3[i];
            }

            NativeArray <Path3Half> TxNativeArray = new NativeArray <Path3Half>(TxHalfPath3.Count, Allocator.TempJob);
            for (int i = 0; i < TxNativeArray.Length; i++)
            {
                TxNativeArray[i] = TxHalfPath3[i];
            }

            NativeArray <Path3> activepath3  = new NativeArray <Path3>(RxHalfPath3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            NativeArray <float> dtArrayMPC3  = new NativeArray <float>(RxHalfPath3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
            NativeArray <float> PathGainMPC3 = new NativeArray <float>(RxHalfPath3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);

            Path3ActiveSet Rx_path3ActiveSet = new Path3ActiveSet
            {
                SeenMPC3Table  = SeenMPC3Table,
                InputArray     = RxNativeArray,
                CompareArray   = TxNativeArray,
                MaxListsLength = MaxLengthOfSeenMPC3Lists,
                EmptyElement   = empty_path3,
                Speed_of_Light = SpeedofLight,

                Output           = activepath3,
                OutputDelays     = dtArrayMPC3,
                OutputAmplitudes = PathGainMPC3
            };
            JobHandle Jobforpath3ActiveSet = Rx_path3ActiveSet.Schedule(activepath3.Length, MaxLengthOfSeenMPC3Lists, TxjobHandleMPC3);

            Jobforpath3ActiveSet.Complete();


            List <Path3> third_order_paths_full_parallel = new List <Path3>();

            if (MPC3_Tracer)
            {
                int trace_count = 0;
                for (int l = 0; l < activepath3.Length; l++)
                //for (int l = 0; l < 10; l++)
                {
                    if (activepath3[l].Distance > 0)
                    {
                        trace_count += 1;
                        third_order_paths_full_parallel.Add(activepath3[l]);
                        Debug.DrawLine(activepath3[l].Rx_Point, activepath3[l].MPC3_1, Color.green);
                        Debug.DrawLine(activepath3[l].MPC3_1, activepath3[l].MPC3_2, Color.blue);
                        Debug.DrawLine(activepath3[l].MPC3_2, activepath3[l].MPC3_3, Color.yellow);
                        Debug.DrawLine(activepath3[l].MPC3_3, activepath3[l].Tx_Point, Color.red);
                        //if (trace_count == 10)
                        //{ break; }
                    }
                }
            }
            //Debug.Log("Number of 3rd order paths = " + third_order_paths_full_parallel.Count);
            TxNativeArray.Dispose();
            RxNativeArray.Dispose();
            activepath3.Dispose();
            dtArrayMPC3.Dispose();
            PathGainMPC3.Dispose();

            //Debug.Log("Check 2: " + ((Time.realtimeSinceStartup - startTime2) * 1000000f) + " microsec");



            Rx_Seen_MPC3.Dispose();
            Rx_Seen_MPC3_att.Dispose();
            RxReachableHalfPath3Array.Dispose();
            Tx_Seen_MPC3.Dispose();
            Tx_Seen_MPC3_att.Dispose();
            TxReachableHalfPath3Array.Dispose();
        }
        ///////////////////////////////////////////////////////////////////////////////////
        /// complete the works
        ///////////////////////////////////////////////////////////////////////////////////


        Y_output       = new double[Nfft];
        H_output       = new double[Nfft];
        Y_noise_output = new double[Nfft];
        H_noise_output = new double[Nfft];


        Drawing.drawChart(tfTime, X_inputValues, Y_output, "time");
        Drawing.drawChart(tfFreq, X_inputValues, H_output, "frequency");



        //Debug.Log("RSS = " + 10* Math.Log10( RSS ) );
    }
Example #2
0
    private void FixedUpdate()
    {
        FixUpdateCount += 1;
        Rx_MPC1         = Rx_Seen_MPC_Script.seen_MPC1;
        Rx_MPC1_att     = Rx_Seen_MPC_Script.seen_MPC1_att;

        Rx_MPC2     = Rx_Seen_MPC_Script.seen_MPC2;
        Rx_MPC2_att = Rx_Seen_MPC_Script.seen_MPC2_att;

        Rx_MPC3     = Rx_Seen_MPC_Script.seen_MPC3;
        Rx_MPC3_att = Rx_Seen_MPC_Script.seen_MPC3_att;

        Tx_MPC1     = Tx_Seen_MPC_Script.seen_MPC1;
        Tx_MPC1_att = Tx_Seen_MPC_Script.seen_MPC1_att;

        Tx_MPC2     = Tx_Seen_MPC_Script.seen_MPC2;
        Tx_MPC2_att = Tx_Seen_MPC_Script.seen_MPC2_att;

        Tx_MPC3     = Tx_Seen_MPC_Script.seen_MPC3;
        Tx_MPC3_att = Tx_Seen_MPC_Script.seen_MPC3_att;

        //NativeList<JobHandle> jobHandleList_Channel = new NativeList<JobHandle>(Allocator.Temp);

        /*
         * for (int i = 0; i < H.Length; i++)
         * {
         *  H_LoS[i] = new System.Numerics.Complex(0, 0);
         *  H_MPC1[i] = new System.Numerics.Complex(0, 0);
         *  H_MPC2[i] = new System.Numerics.Complex(0, 0);
         *  H_MPC3[i] = new System.Numerics.Complex(0, 0);
         * }
         */

        ///////////////////////////////////////////////////////////////////////////////////
        /// LOS
        ///////////////////////////////////////////////////////////////////////////////////

        float dtLoS        = 0;
        float PathGainLoS  = 0;
        float LOS_distance = 0;

        if (!Physics.Linecast(Tx.transform.position, Rx.transform.position))
        {
            Vector3 LoS_dir = (Tx.transform.position - Rx.transform.position).normalized;
            Vector3 Tx_fwd  = Tx.transform.forward;
            Vector3 Rx_fwd  = Tx.transform.forward;
            float   cos_Tx  = -1;
            float   cos_Rx  = -1;
            float   K_antanne_pattern;

            if (Tx_Antenna_pattern)
            {
                cos_Tx = Vector3.Dot(-LoS_dir, Tx_fwd);
            }
            if (Rx_Antenna_pattern)
            {
                cos_Rx = Vector3.Dot(LoS_dir, Rx_fwd);
            }
            K_antanne_pattern = 0.25f * (1 - cos_Rx - cos_Tx + cos_Rx * cos_Tx);

            flag_LoS = 1;
            if (LoS_Start == 0)
            {
                LoS_Start = FixUpdateCount; Debug.Log("LoS Start " + LoS_Start);
            }                                                                                        // finding the start time of LoS

            if (LOS_Tracer)
            {
                Debug.DrawLine(Tx.transform.position, Rx.transform.position, Color.magenta);
            }

            LOS_distance = (Tx.transform.position - Rx.transform.position).magnitude;
            //LOS_distance = 200;
            dtLoS       = LOS_distance / SpeedofLight;// + 1000/SpeedofLight;
            PathGainLoS = (float)Math.Pow(1 / LOS_distance, 2) * K_antanne_pattern;

            float hbyd           = 3.4f / LOS_distance; // 2h/d; h = 1.7meters
            float Rparallel      = (RelativePermitivity * hbyd - Z) / (RelativePermitivity * hbyd + Z);
            float Rperpendicular = (hbyd - Z) / (hbyd + Z);
            float Rcoef          = (float)Math.Sqrt(0.5f * (Rparallel * Rparallel + Rperpendicular * Rperpendicular));

            //PathGainLoS -= PathGainLoS * Rcoef * Rcoef / 2;
            //float h2byd = 5.78f / LOS_distance; // 2 h^2/2

            EdgeEffect(FixUpdateCount - LoS_Start, out EdgeEffect_LoS);

            // the follwing can be done due to manual calculation of the LoS End
            if (FixUpdateCount > 100 && FixUpdateCount < 126)
            {
                EdgeEffect(124 - FixUpdateCount, out EdgeEffect_LoS);
            }
        }

        /*else
         * {
         *  if (flag_LoS == 1)
         *  {
         *      flag_LoS = 2;
         *      LoS_End = FixUpdateCount;
         *      Debug.Log("LoS End " + LoS_End);
         *      // remember the last LoS channel
         *      for (int i = 0; i < H_LoS.Length; i++)
         *      {
         *          H_old[i] = H_LoS[i];
         *      }
         *  } // finding the end time of LoS
         * }*/

        //Debug.Log("Edge effect coefficient = " + EdgeEffect_LoS);



        var dtLoSParallel       = new NativeArray <float>(1, Allocator.TempJob);
        var distanceLoSParallel = new NativeArray <float>(1, Allocator.TempJob);
        var PathGainLoSParallel = new NativeArray <float>(1, Allocator.TempJob);

        for (int i = 0; i < dtLoSParallel.Length; i++)
        {
            dtLoSParallel[i]       = dtLoS;
            distanceLoSParallel[i] = LOS_distance;
            PathGainLoSParallel[i] = PathGainLoS;
        }

        ChannelParallel channelParallel = new ChannelParallel
        {
            //TimeDelayArray = dtLoSParallel,
            //FrequencyArray = Subcarriers,
            PathsGainArray = PathGainLoSParallel,

            TimeDelayArray = distanceLoSParallel,
            FrequencyArray = InverseWavelength,

            HH = H_LoS,
        };
        JobHandle jobHandleLoSChannel = channelParallel.Schedule(Subcarriers.Length, 8);

        // we add the job to the list of jobs related to channel calculation in order to complete them all at once later
        //jobHandleList_Channel.Add(jobHandleLoSChannel);

        //JobHandle.CompleteAll(jobHandleList_Channel);
        jobHandleLoSChannel.Complete();
        dtLoSParallel.Dispose();
        distanceLoSParallel.Dispose();
        PathGainLoSParallel.Dispose();
        ///////////////////////////////////////////////////////////////////////////////////
        /// MPC1
        ///////////////////////////////////////////////////////////////////////////////////

        var RxArray1     = new NativeArray <int>(Rx_MPC1.Count, Allocator.TempJob);
        var RxArray1_att = new NativeArray <float>(Rx_MPC1.Count, Allocator.TempJob);
        var TxArray1     = new NativeArray <int>(Tx_MPC1.Count, Allocator.TempJob);
        var TxArray1_att = new NativeArray <float>(Tx_MPC1.Count, Allocator.TempJob);

        var possiblePath1 = new NativeArray <Path1>(Tx_MPC1.Count, Allocator.TempJob);
        var dtMPC1Array   = new NativeArray <float>(Tx_MPC1.Count, Allocator.TempJob);
        var PathGainMPC1  = new NativeArray <float>(Tx_MPC1.Count, Allocator.TempJob);

        for (int i = 0; i < Rx_MPC1.Count; i++)
        {
            RxArray1[i]     = Rx_MPC1[i];
            RxArray1_att[i] = Rx_MPC1_att[i];
        }

        for (int i = 0; i < Tx_MPC1.Count; i++)
        {
            TxArray1[i]      = Tx_MPC1[i];
            TxArray1_att[i]  = Tx_MPC1_att[i];
            possiblePath1[i] = empty_path;
        }
        CommonMPC1Parallel commonMPC1Parallel = new CommonMPC1Parallel
        {
            Speed_of_Light = SpeedofLight,
            MPC1           = SeenMPC1Table,
            Array1         = RxArray1,
            Array1_att     = RxArray1_att,
            Array2         = TxArray1,
            Array2_att     = TxArray1_att,
            Rx_Point       = Rx.transform.position,
            Tx_Point       = Tx.transform.position,

            Output           = possiblePath1,
            OutputDelays     = dtMPC1Array,
            OutputAmplitudes = PathGainMPC1,
        };
        JobHandle jobHandleMPC1 = commonMPC1Parallel.Schedule(TxArray1.Length, 2);

        jobHandleMPC1.Complete();

        // transition from NativeArrays to Lists
        List <Path1> first_order_paths_full_parallel = new List <Path1>();

        if (MPC1_Tracer)
        {
            for (int i = 0; i < possiblePath1.Length; i++)
            {
                if (possiblePath1[i].Distance > 0)
                {
                    first_order_paths_full_parallel.Add(possiblePath1[i]);
                    Debug.DrawLine(possiblePath1[i].Rx_Point, possiblePath1[i].MPC1, Color.cyan);
                    Debug.DrawLine(possiblePath1[i].Tx_Point, possiblePath1[i].MPC1, Color.cyan);
                }
            }
        }



        // channel calculation
        ChannelParallel channelParallelMPC1 = new ChannelParallel
        {
            //TimeDelayArray = dtMPC1Array,
            //FrequencyArray = Subcarriers,
            PathsGainArray = PathGainMPC1,
            TimeDelayArray = dtMPC1Array, // changed to distances
            FrequencyArray = InverseWavelength,

            HH = H_MPC1,
        };
        JobHandle jobHandleChannelMPC1 = channelParallelMPC1.Schedule(Subcarriers.Length, 8, jobHandleMPC1);

        // we add the job to the list of jobs related to channel calculation in order to complete them all at once later
        //jobHandleList_Channel.Add(jobHandleChannelMPC1);
        jobHandleChannelMPC1.Complete();


        RxArray1.Dispose();
        RxArray1_att.Dispose();
        TxArray1.Dispose();
        TxArray1_att.Dispose();
        possiblePath1.Dispose();
        dtMPC1Array.Dispose();
        PathGainMPC1.Dispose();
        ///////////////////////////////////////////////////////////////////////////////////
        /// MPC2 Parallel
        ///////////////////////////////////////////////////////////////////////////////////

        var level2MPC2     = new NativeArray <int>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var level2MPC2_att = new NativeArray <float>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var possiblePath2  = new NativeArray <Path2>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var dtArrayMPC2    = new NativeArray <float>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);
        var PathGainMPC2   = new NativeArray <float>(Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists, Allocator.TempJob);

        for (int l = 0; l < Rx_MPC2.Count * MaxLengthOfSeenMPC2Lists; l++)
        {
            level2MPC2[l]     = Rx_MPC2[Mathf.FloorToInt(l / MaxLengthOfSeenMPC2Lists)];
            level2MPC2_att[l] = Rx_MPC2_att[Mathf.FloorToInt(l / MaxLengthOfSeenMPC2Lists)];
            possiblePath2[l]  = empty_path2;
        }

        var TxMPC2Array     = new NativeArray <int>(Tx_MPC2.Count, Allocator.TempJob);
        var TxMPC2Array_att = new NativeArray <float>(Tx_MPC2.Count, Allocator.TempJob);

        for (int l = 0; l < Tx_MPC2.Count; l++)
        {
            TxMPC2Array[l]     = Tx_MPC2[l];
            TxMPC2Array_att[l] = Tx_MPC2_att[l];
        }

        Path2ParallelSearch path2ParallelSearch = new Path2ParallelSearch
        {
            // common data
            SeenMPC2Table  = SeenMPC2Table,
            LookUpTable2   = LookUpTable2,
            LookUpTable2ID = LookUpTable2ID,
            // must be disposed
            Rx_MPC2Array     = level2MPC2,
            Rx_MPC2Array_att = level2MPC2_att,
            Tx_MPC2          = TxMPC2Array,
            Tx_MPC2_att      = TxMPC2Array_att,

            // other data
            Rx_Position    = Rx.transform.position,
            Tx_Position    = Tx.transform.position,
            MaxListsLength = MaxLengthOfSeenMPC2Lists,
            Speed_of_Light = SpeedofLight,

            SecondOrderPaths = possiblePath2,
            OutputDelays     = dtArrayMPC2,
            OutputAmplitudes = PathGainMPC2,
        };
        // create a job handle list
        JobHandle jobHandleMPC2 = path2ParallelSearch.Schedule(level2MPC2.Length, MaxLengthOfSeenMPC2Lists, jobHandleMPC1);

        jobHandleMPC2.Complete();



        /// MPC2
        List <Path2> second_order_paths_full_parallel = new List <Path2>();

        if (MPC2_Tracer)
        {
            for (int l = 0; l < possiblePath2.Length; l++)
            {
                if (possiblePath2[l].Distance > 0)
                {
                    second_order_paths_full_parallel.Add(possiblePath2[l]);
                    Debug.DrawLine(possiblePath2[l].Rx_Point, possiblePath2[l].MPC2_1, Color.white);
                    Debug.DrawLine(possiblePath2[l].MPC2_1, possiblePath2[l].MPC2_2, Color.white);
                    Debug.DrawLine(possiblePath2[l].MPC2_2, possiblePath2[l].Tx_Point, Color.white);
                }
            }
        }

        // channel calculation
        ChannelParallel channelParallelMPC2 = new ChannelParallel
        {
            //TimeDelayArray = dtArrayMPC2,
            //FrequencyArray = Subcarriers,
            PathsGainArray = PathGainMPC2,
            TimeDelayArray = dtArrayMPC2, // changed to distances
            FrequencyArray = InverseWavelength,

            HH = H_MPC2,
        };
        JobHandle jobHandleChannelMPC2 = channelParallelMPC2.Schedule(Subcarriers.Length, 8, jobHandleMPC2);

        // we add the job to the list of jobs related to channel calculation in order to complete them all at once later
        //jobHandleList_Channel.Add(jobHandleChannelMPC1);
        jobHandleChannelMPC2.Complete();

        level2MPC2.Dispose();
        level2MPC2_att.Dispose();
        possiblePath2.Dispose();
        TxMPC2Array.Dispose();
        TxMPC2Array_att.Dispose();
        dtArrayMPC2.Dispose();
        PathGainMPC2.Dispose();

        ///////////////////////////////////////////////////////////////////////////////////
        /// MPC3
        ///////////////////////////////////////////////////////////////////////////////////


        // define how many elements should be processed in a single core
        int innerloopBatchCount = MaxLengthOfSeenMPC3Lists;

        Vector3 Rx_Point = Rx.transform.position;
        Vector3 Tx_Point = Tx.transform.position;

        NativeArray <int>       Rx_Seen_MPC3              = new NativeArray <int>(Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
        NativeArray <float>     Rx_Seen_MPC3_att          = new NativeArray <float>(Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
        NativeArray <Path3Half> RxReachableHalfPath3Array = new NativeArray <Path3Half>(Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);

        for (int l = 0; l < Rx_MPC3.Count * MaxLengthOfSeenMPC3Lists; l++)
        {
            Rx_Seen_MPC3[l]              = Rx_MPC3[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
            Rx_Seen_MPC3_att[l]          = Rx_MPC3_att[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
            RxReachableHalfPath3Array[l] = empty_path3Half;
        }

        NativeArray <int>       Tx_Seen_MPC3              = new NativeArray <int>(Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
        NativeArray <float>     Tx_Seen_MPC3_att          = new NativeArray <float>(Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
        NativeArray <Path3Half> TxReachableHalfPath3Array = new NativeArray <Path3Half>(Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);

        for (int l = 0; l < Tx_MPC3.Count * MaxLengthOfSeenMPC3Lists; l++)
        {
            Tx_Seen_MPC3[l]              = Tx_MPC3[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
            Tx_Seen_MPC3_att[l]          = Tx_MPC3_att[Mathf.FloorToInt(l / MaxLengthOfSeenMPC3Lists)];
            TxReachableHalfPath3Array[l] = empty_path3Half;
        }

        HalfPath3Set RxhalfPath3Set = new HalfPath3Set
        {
            // common data
            SeenMPC3Table  = SeenMPC3Table,
            LookUpTable3   = LookUpTable3,
            LookUpTable3ID = LookUpTable3ID,
            MaxListsLength = MaxLengthOfSeenMPC3Lists,

            // Car specific data
            Point = Rx_Point,
            // must be disposed
            Seen_MPC3          = Rx_Seen_MPC3,
            Seen_MPC3_att      = Rx_Seen_MPC3_att,
            ReachableHalfPath3 = RxReachableHalfPath3Array,
        };
        // create a job handle list
        NativeList <JobHandle> jobHandleList = new NativeList <JobHandle>(Allocator.Temp);

        JobHandle RxjobHandleMPC3 = RxhalfPath3Set.Schedule(Rx_Seen_MPC3.Length, innerloopBatchCount, jobHandleMPC2);

        jobHandleList.Add(RxjobHandleMPC3);

        HalfPath3Set TxhalfPath3Set = new HalfPath3Set
        {
            // common data
            SeenMPC3Table  = SeenMPC3Table,
            LookUpTable3   = LookUpTable3,
            LookUpTable3ID = LookUpTable3ID,
            MaxListsLength = MaxLengthOfSeenMPC3Lists,

            // Car specific data
            Point = Tx_Point,
            // must be disposed
            Seen_MPC3          = Tx_Seen_MPC3,
            Seen_MPC3_att      = Tx_Seen_MPC3_att,
            ReachableHalfPath3 = TxReachableHalfPath3Array,
        };

        JobHandle TxjobHandleMPC3 = TxhalfPath3Set.Schedule(Tx_Seen_MPC3.Length, innerloopBatchCount, jobHandleMPC2);

        jobHandleList.Add(TxjobHandleMPC3);

        JobHandle.CompleteAll(jobHandleList);



        // storing nonempty path3s
        List <Path3Half> TxHalfPath3 = new List <Path3Half>();
        List <Path3Half> RxHalfPath3 = new List <Path3Half>();

        // introducing a little bit of randomness to the third order of paths selection
        int MPC3PathStep = 3; // otherwise, the sets of possible third order of paths become too big

        for (int l = 0; l < TxReachableHalfPath3Array.Length; l += MPC3PathStep)
        {
            if (TxReachableHalfPath3Array[l].Distance > 0)
            {
                TxHalfPath3.Add(TxReachableHalfPath3Array[l]);
            }
        }
        for (int l = 0; l < RxReachableHalfPath3Array.Length; l += MPC3PathStep)
        {
            if (RxReachableHalfPath3Array[l].Distance > 0)
            {
                RxHalfPath3.Add(RxReachableHalfPath3Array[l]);
            }
        }



        //float startTime2 = Time.realtimeSinceStartup;

        NativeArray <Path3Half> RxNativeArray = new NativeArray <Path3Half>(RxHalfPath3.Count, Allocator.TempJob);

        for (int i = 0; i < RxNativeArray.Length; i++)
        {
            RxNativeArray[i] = RxHalfPath3[i];
        }

        NativeArray <Path3Half> TxNativeArray = new NativeArray <Path3Half>(TxHalfPath3.Count, Allocator.TempJob);

        for (int i = 0; i < TxNativeArray.Length; i++)
        {
            TxNativeArray[i] = TxHalfPath3[i];
        }

        NativeArray <Path3> activepath3  = new NativeArray <Path3>(RxHalfPath3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
        NativeArray <float> dtArrayMPC3  = new NativeArray <float>(RxHalfPath3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);
        NativeArray <float> PathGainMPC3 = new NativeArray <float>(RxHalfPath3.Count * MaxLengthOfSeenMPC3Lists, Allocator.TempJob);

        Path3ActiveSet Rx_path3ActiveSet = new Path3ActiveSet
        {
            SeenMPC3Table  = SeenMPC3Table,
            InputArray     = RxNativeArray,
            CompareArray   = TxNativeArray,
            MaxListsLength = MaxLengthOfSeenMPC3Lists,
            EmptyElement   = empty_path3,
            Speed_of_Light = SpeedofLight,

            Output           = activepath3,
            OutputDelays     = dtArrayMPC3,
            OutputAmplitudes = PathGainMPC3
        };
        JobHandle Jobforpath3ActiveSet = Rx_path3ActiveSet.Schedule(activepath3.Length, MaxLengthOfSeenMPC3Lists, TxjobHandleMPC3);

        Jobforpath3ActiveSet.Complete();

        // channel calculation
        ChannelParallel channelParallelMPC3 = new ChannelParallel
        {
            //TimeDelayArray = dtArrayMPC3,
            //FrequencyArray = Subcarriers,
            PathsGainArray = PathGainMPC3,
            TimeDelayArray = dtArrayMPC3, // changed to distances
            FrequencyArray = InverseWavelength,

            HH = H_MPC3,
        };
        JobHandle jobHandleChannelMPC3 = channelParallelMPC3.Schedule(Subcarriers.Length, 8, Jobforpath3ActiveSet);

        // we add the job to the list of jobs related to channel calculation in order to complete them all at once later
        //jobHandleList_Channel.Add(jobHandleChannelMPC1);
        jobHandleChannelMPC3.Complete();

        List <Path3> third_order_paths_full_parallel = new List <Path3>();

        if (MPC3_Tracer)
        {
            int trace_count = 0;
            for (int l = 0; l < activepath3.Length; l++)
            //for (int l = 0; l < 10; l++)
            {
                if (activepath3[l].Distance > 0)
                {
                    trace_count += 1;
                    third_order_paths_full_parallel.Add(activepath3[l]);
                    Debug.DrawLine(activepath3[l].Rx_Point, activepath3[l].MPC3_1, Color.green);
                    Debug.DrawLine(activepath3[l].MPC3_1, activepath3[l].MPC3_2, Color.blue);
                    Debug.DrawLine(activepath3[l].MPC3_2, activepath3[l].MPC3_3, Color.yellow);
                    Debug.DrawLine(activepath3[l].MPC3_3, activepath3[l].Tx_Point, Color.red);
                    //if (trace_count == 10)
                    //{ break; }
                }
            }
        }
        //Debug.Log("Number of 3rd order paths = " + third_order_paths_full_parallel.Count);
        TxNativeArray.Dispose();
        RxNativeArray.Dispose();
        activepath3.Dispose();
        dtArrayMPC3.Dispose();
        PathGainMPC3.Dispose();

        //Debug.Log("Check 2: " + ((Time.realtimeSinceStartup - startTime2) * 1000000f) + " microsec");



        Rx_Seen_MPC3.Dispose();
        Rx_Seen_MPC3_att.Dispose();
        RxReachableHalfPath3Array.Dispose();
        Tx_Seen_MPC3.Dispose();
        Tx_Seen_MPC3_att.Dispose();
        TxReachableHalfPath3Array.Dispose();

        ///////////////////////////////////////////////////////////////////////////////////
        /// complete the works
        ///////////////////////////////////////////////////////////////////////////////////
        /// LoS
        // this part should be moved to the end at least after the completion of the list of the works
        //jobHandleList_Channel.Complete();

        //double asd = System.Numerics.Complex.Abs( H_MPC2[0]);


        double factor = 10000000 * 32; // this corresponds to a -110 dBm noise floor; 32 comes from the sqrt of 1024


        for (int i = 0; i < H.Length; i++)
        {
            double u1            = 1.0 - rand.NextDouble(); //uniform(0,1] random doubles
            double u2            = 1.0 - rand.NextDouble();
            double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2) / factor;
            //H[i] = H_LoS[i];
            //H[i] = H_MPC1[i];
            //H[i] = H_MPC2[i];

            //H[i] = H_LoS[i] + H_MPC1[i];
            H[i]      = H_LoS[i] * EdgeEffect_LoS + H_MPC1[i] + H_MPC2[i] + H_MPC3[i] + randStdNormal;
            H_pure[i] = H_LoS[i] * EdgeEffect_LoS + H_MPC1[i] + H_MPC2[i] + H_MPC3[i];
            //H_noise[i] = randStdNormal;
            //H[i] = H_MPC3[i];

            // zeroing all the inputs
            // H_LoS[i] = new System.Numerics.Complex(0,0);
            H_MPC1[i] = new System.Numerics.Complex(0, 0);
            H_MPC2[i] = new System.Numerics.Complex(0, 0);
            H_MPC3[i] = new System.Numerics.Complex(0, 0);
        }



        System.Numerics.Complex[] outputSignal_Freq = FastFourierTransform.FFT(H, false);
        System.Numerics.Complex[] outputNoise_Freq  = FastFourierTransform.FFT(H_noise, false);

        Y_output       = new double[H.Length];
        H_output       = new double[H.Length];
        Y_noise_output = new double[H.Length];
        H_noise_output = new double[H.Length];
        //get module of complex number
        double RSS = 0;

        for (int ii = 0; ii < H.Length; ii++)
        {
            Y_output[ii] = 10 * Math.Log10(System.Numerics.Complex.Abs(outputSignal_Freq[ii])); // + 0.0000000000001);
            H_output[ii] = 10 * Math.Log10(System.Numerics.Complex.Abs(H[ii]));                 // + 0.0000000000001);

            //Y_noise_output[ii] = 10 * Math.Log10(System.Numerics.Complex.Abs(outputNoise_Freq[ii]));// + 0.0000000000001);
            //H_noise_output[ii] = 10 * Math.Log10(System.Numerics.Complex.Abs(H_noise[ii]));// + 0.0000000000001);

            // calculatig pure signal's RSSI, should be clarified
            //RSSI += System.Numerics.Complex.Abs(H_pure[ii]);
            RSS += 1000 * Math.Pow(System.Numerics.Complex.Abs(H_pure[ii]), 2);
        }
        //Drawing.drawChart(tfTime, X_inputValues, Y_noise_output, "time");
        //Drawing.drawChart(tfFreq, X_inputValues, H_noise_output, "frequency");

        Drawing.drawChart(tfTime, X_inputValues, Y_output, "time");
        Drawing.drawChart(tfFreq, X_inputValues, H_output, "frequency");



        //Debug.Log("RSS = " + 10* Math.Log10( RSS ) );
    }