text: # -*- coding: utf-8 -*-
  
  '''
  Reuben Brewer, Ph.D.
  reuben.brewer@gmail.com
  www.reubotics.com
  
  Apache 2 License
  Software Revision C, 09/03/2021
  
  Verified working on: Python 2.7 and 3 for Windows 8.1 64-bit and Raspberry Pi Buster (no Mac testing yet).
  '''
  
  __author__ = 'reuben.brewer'
  
  from LowPassFilter_ReubenPython2and3Class import *
  from MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3Class import *
  
  import os, sys, platform
  import time, datetime
  import threading
  import collections
  import math, numpy
  import traceback
  import re
  import random
  from random import randint
  
  ###############
  if sys.version_info[0] < 3:
      from Tkinter import * #Python 2
      import tkFont
      import ttk
  else:
      from tkinter import * #Python 3
      import tkinter.font as tkFont #Python 3
      from tkinter import ttk
  ###############
  
  ###############
  if sys.version_info[0] < 3:
      from builtins import raw_input as input
  else:
      from future.builtins import input as input #"sudo pip3 install future" (Python 3) AND "sudo pip install future" (Python 2)
  ###############
  
  ##########################################################################################################
  ##########################################################################################################
  def getPreciseSecondsTimeStampString():
      ts = time.time()
  
      return ts
  ##########################################################################################################
  ##########################################################################################################
  
  ##########################################################################################################
  ##########################################################################################################
  def UpdateFrequencyCalculation():
      global CurrentTime_MainLoopThread
      global LastTime_MainLoopThread
      global DataStreamingFrequency_MainLoopThread
      global DataStreamingDeltaT_MainLoopThread
      global Counter_MainLoopThread
  
      try:
          DataStreamingDeltaT_MainLoopThread = CurrentTime_MainLoopThread - LastTime_MainLoopThread
  
          if DataStreamingDeltaT_MainLoopThread != 0.0:
              DataStreamingFrequency_MainLoopThread = 1.0 / DataStreamingDeltaT_MainLoopThread
  
          LastTime_MainLoopThread = CurrentTime_MainLoopThread
          Counter_MainLoopThread = Counter_MainLoopThread + 1
  
      except:
          exceptions = sys.exc_info()[0]
          print("UpdateFrequencyCalculation ERROR, Exceptions: %s" % exceptions)
          traceback.print_exc()
  ##########################################################################################################
  ##########################################################################################################
  
  ##########################################################################################################
  ##########################################################################################################
  if __name__ == '__main__':
  
      #################################################
      #################################################
      global my_platform
  
      if platform.system() == "Linux":
  
          if "raspberrypi" in platform.uname():  # os.uname() doesn't work in windows
              my_platform = "pi"
          else:
              my_platform = "linux"
  
      elif platform.system() == "Windows":
          my_platform = "windows"
  
      elif platform.system() == "Darwin":
          my_platform = "mac"
  
      else:
          my_platform = "other"
  
      print("The OS platform is: " + my_platform)
      #################################################
      #################################################
  
      #################################################
      #################################################
      global USE_LOWPASSFILTER_FLAG
      USE_LOWPASSFILTER_FLAG = 1
  
      global USE_PLOTTER_FLAG
      USE_PLOTTER_FLAG = 1
  
      global USE_SPECKLE_NOISE_FLAG
      USE_SPECKLE_NOISE_FLAG = 1
      #################################################
      #################################################
      
      ################################################
      ################################################
      global EXIT_PROGRAM_FLAG
      EXIT_PROGRAM_FLAG = 0
  
      global LowPassFilter_ReubenPython2and3ClassObject
  
      global LOWPASSFILTER_OPEN_FLAG
      LOWPASSFILTER_OPEN_FLAG = -1
      
      global MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject
  
      global PLOTTER_OPEN_FLAG
      PLOTTER_OPEN_FLAG = -1
  
      global CurrentTime_MainLoopThread
      CurrentTime_MainLoopThread = -11111.0
  
      global LastTime_MainLoopThread
      LastTime_MainLoopThread = -11111.0
  
      global DataStreamingFrequency_MainLoopThread
      DataStreamingFrequency_MainLoopThread = -11111.0
  
      global DataStreamingDeltaT_MainLoopThread
      DataStreamingDeltaT_MainLoopThread = -11111.0
  
      global StartingTime_MainLoopThread
      StartingTime_MainLoopThread = -1
  
      global Counter_MainLoopThread
      Counter_MainLoopThread = 0
  
      global SINUSOIDAL_MOTION_INPUT_ROMtestTimeToPeakAngle
      SINUSOIDAL_MOTION_INPUT_ROMtestTimeToPeakAngle = 1.0
  
      global SINUSOIDAL_MOTION_INPUT_MinValue
      SINUSOIDAL_MOTION_INPUT_MinValue = -90.0
  
      global SINUSOIDAL_MOTION_INPUT_MaxValue
      SINUSOIDAL_MOTION_INPUT_MaxValue = 90.0
  
      global NoiseCounter
      NoiseCounter = 0
  
      global NoiseAmplitude_Percent0to1OfSinuisoidalInputAmplitude
      NoiseAmplitude_Percent0to1OfSinuisoidalInputAmplitude = 0.1
  
      ####################################################
      ####################################################
      if USE_LOWPASSFILTER_FLAG == 1:
          try:
              LowPassFilter_ReubenPython2and3ClassObject_setup_dict = dict([("UseMedianFilterFlag", 0),
                                                                          ("UseExponentialSmoothingFilterFlag", 1),
                                                                          ("ExponentialSmoothingFilterLambda", 0.2)])
  
              LowPassFilter_ReubenPython2and3ClassObject = LowPassFilter_ReubenPython2and3Class(LowPassFilter_ReubenPython2and3ClassObject_setup_dict)
              time.sleep(0.1)
              LOWPASSFILTER_OPEN_FLAG = LowPassFilter_ReubenPython2and3ClassObject.OBJECT_CREATED_SUCCESSFULLY_FLAG
  
          except:
              exceptions = sys.exc_info()[0]
              print("LowPassFilter_ReubenPython2and3Class __init__: Exceptions: %s" % exceptions)
      ####################################################
      ####################################################
  
      #################################################
      #################################################
      global MyPlotterPureTkinter_MostRecentDict
      MyPlotterPureTkinter_MostRecentDict = dict()
  
      global MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict_StandAlonePlottingProcess_ReadyForWritingFlag
      MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict_StandAlonePlottingProcess_ReadyForWritingFlag = -1
  
  
  
      MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_GUIparametersDict = dict([("EnableInternal_MyPrint_Flag", 1),
                                                                                                  ("NumberOfPrintLines", 10),
                                                                                                  ("UseBorderAroundThisGuiObjectFlag", 0),
                                                                                                  ("GraphCanvasWidth", 1280),
                                                                                                  ("GraphCanvasHeight", 700),
                                                                                                  ("GraphCanvasWindowStartingX", 0),
                                                                                                  ("GraphCanvasWindowStartingY", 0),
                                                                                                  ("GUI_RootAfterCallbackInterval_Milliseconds_IndependentOfParentRootGUIloopEvents", 20)])
  
      global MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_setup_dict
      MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_setup_dict = dict([("GUIparametersDict", MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_GUIparametersDict),
                                                                                          ("ParentPID", os.getpid()),
                                                                                          ("WatchdogTimerExpirationDurationSeconds_StandAlonePlottingProcess", 0.0),
                                                                                          ("MarkerSize", 3),
                                                                                          ("CurvesToPlotNamesAndColorsDictOfLists", dict([("NameList", ["raw", "smoothed"]),("ColorList", ["Red", "Green"])])),
                                                                                          ("NumberOfDataPointToPlot", 50),
                                                                                          ("XaxisNumberOfTickMarks", 10),
                                                                                          ("YaxisNumberOfTickMarks", 10),
                                                                                          ("XaxisNumberOfDecimalPlacesForLabels", 3),
                                                                                          ("YaxisNumberOfDecimalPlacesForLabels", 3),
                                                                                          ("XaxisAutoscaleFlag", 1),
                                                                                          ("YaxisAutoscaleFlag", 0),
                                                                                          ("X_min", 0.0),
                                                                                          ("X_max", 20.0),
                                                                                          ("Y_min", 1.1*SINUSOIDAL_MOTION_INPUT_MinValue),
                                                                                          ("Y_max", 1.1*SINUSOIDAL_MOTION_INPUT_MaxValue),
                                                                                          ("XaxisDrawnAtBottomOfGraph", 0),
                                                                                          ("XaxisLabelString", "Time (sec)"),
                                                                                          ("YaxisLabelString", "Y-units (units)"),
                                                                                          ("ShowLegendFlag", 1)])
  
      if USE_PLOTTER_FLAG == 1:
          try:
              MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject = MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3Class(MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_setup_dict)
              time.sleep(0.25)
              PLOTTER_OPEN_FLAG = MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject.OBJECT_CREATED_SUCCESSFULLY_FLAG
  
          except:
              exceptions = sys.exc_info()[0]
              print("MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject, exceptions: %s" % exceptions)
              traceback.print_exc()
      #################################################
      #################################################
  
      ####################################################
      ####################################################
      if LOWPASSFILTER_OPEN_FLAG != 1:
          print("Failed to open LowPassFilter_ReubenPython2and3ClassObject.")
          input("Press any key (and enter) to exit.")
          sys.exit()
      ####################################################
      ####################################################
  
      #################################################
      #################################################
      if USE_PLOTTER_FLAG == 1 and PLOTTER_OPEN_FLAG != 1:
          print("Failed to open MyPlotterPureTkinterClass_Object.")
          input("Press any key (and enter) to exit.")
          sys.exit()
      #################################################
      #################################################
  
      ####################################################
      ####################################################
      random.seed()
      ####################################################
      ####################################################
  
      ####################################################
      ####################################################
      ####################################################
  
      StartingTime_MainLoopThread = getPreciseSecondsTimeStampString()
      while(CurrentTime_MainLoopThread <= 20.0):
          ####################################################
          ####################################################
          CurrentTime_MainLoopThread = getPreciseSecondsTimeStampString() - StartingTime_MainLoopThread
          ####################################################
          ####################################################
  
          ####################################################
          ####################################################
          time_gain = math.pi / (2.0 * SINUSOIDAL_MOTION_INPUT_ROMtestTimeToPeakAngle)
          desired_angle_deg_1 = 0.5*(SINUSOIDAL_MOTION_INPUT_MaxValue + SINUSOIDAL_MOTION_INPUT_MinValue) + math.exp(0.1*CurrentTime_MainLoopThread)*0.5 * abs(SINUSOIDAL_MOTION_INPUT_MaxValue - SINUSOIDAL_MOTION_INPUT_MinValue) * math.sin(time_gain * CurrentTime_MainLoopThread)  # AUTOMATIC SINUSOIDAL MOVEMENT
  
          if USE_SPECKLE_NOISE_FLAG == 1:
              NoiseCounter = NoiseCounter + 1
              if NoiseCounter == 1:
                  NoiseAmplitude = NoiseAmplitude_Percent0to1OfSinuisoidalInputAmplitude*abs(SINUSOIDAL_MOTION_INPUT_MaxValue - SINUSOIDAL_MOTION_INPUT_MinValue)
                  NoiseValue = random.uniform(-1.0*NoiseAmplitude, NoiseAmplitude)
                  desired_angle_deg_1 = desired_angle_deg_1 + NoiseValue
                  NoiseCounter = 0
  
          LowPassFilter_ReubenPython2and3ClassObject.AddDataPointFromExternalProgram(desired_angle_deg_1)
          ####################################################
          ####################################################
  
          ####################################################
          ####################################################
          dict_temp = LowPassFilter_ReubenPython2and3ClassObject.GetMostRecentDataDict()
          raw = dict_temp["SignalInRaw"]
          smoothed = dict_temp["SignalOutSmoothed"]
          frequency = dict_temp["DataStreamingFrequency"]
          #print("frequency: " + str(frequency))
          ####################################################
          ####################################################
  
          ####################################################
          ####################################################
          if USE_PLOTTER_FLAG == 1:
  
              ####################################################
              MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict = MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject.GetMostRecentDataDict()
              #print(str(MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict))
  
              if "StandAlonePlottingProcess_ReadyForWritingFlag" in MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict:
                  MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict_StandAlonePlottingProcess_ReadyForWritingFlag = MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict["StandAlonePlottingProcess_ReadyForWritingFlag"]
              else:
                  pass
                  ####################################################
  
                  ####################################################
              if MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject_MostRecentDict_StandAlonePlottingProcess_ReadyForWritingFlag == 1:
                  MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject.ExternalAddPointOrListOfPointsToPlot("raw", CurrentTime_MainLoopThread, raw)
                  MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject.ExternalAddPointOrListOfPointsToPlot("smoothed", CurrentTime_MainLoopThread, smoothed)
                  ####################################################
  
          ####################################################
          ####################################################
  
          ####################################################
          ####################################################
          UpdateFrequencyCalculation()
          time.sleep(0.030)  ######## MUST HAVE AT LEAST A SMALL TIMEOUT OR ELSE THE MOTORS RUNS AWAY
          ####################################################
          ####################################################
  
      ####################################################
      ####################################################
      ####################################################
  
      MyPlotterPureTkinterStandAloneProcess_ReubenPython2and3ClassObject.ExternalSendEndCommandToStandAloneProcess()
  
      print("Exiting main program 'test_program_for_LowPassFilter_ReubenPython2and3Class.")
  ##########################################################################################################
  ##########################################################################################################