// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// trteta.cc --- teta, voltage and ampere functions for trains
// -----
// ChangeLog:
// 2010. 1. 18
//  Moved the main routine of ttvi_power() to train::_ParamFunc class.
// 2010. 1. 17
//  Moved the main routine of ttvi_brake() to train::_ParamFunc class.
// 2007. 11. 22
//  Redirected log messages to l_file.
// -----

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>

#include "train.hh"
#include "StrPrintf.hh"

#define INVLIM	1e-5
// #define EMCCV	1750.0

#define ANTEIDIV	3.0
#define ANTEIDIFF	50.0

#define REGEN_OFF_TETA	5.0

// リミットサイクル発見後は修正量を FAILCAR に制限 (列車). Default = 10.0
#define FAILCAR gc_ccalfail_failcar

// リミットサイクル発見後は絞り込み特性上の修正量を絞込幅の FAILSHIBO 分の1
// に制限 (列車). Default = 100
#define FAILSHIBO gc_ccalfail_failctp


//#define DEBUG

// ----
// Subprogram of train::teta_vi(). Accelerating. Main part has now been moved
// to train::_ParamFunc class.
// train::teta_vi () のサブプログラム、力行時。主要部分は train::_ParamFunc
// クラスに移動した。
// ----
void
train :: ttvi_power
()
{
  train_ParamFunc * __pf = getNewParamFuncCalculator () ;
  if ( ! __pf )
  {
    cerr << "Error: memory allocation failed in ttvi_power()" << endl ;
    exit ( 1 ) ;
  }
  __pf -> ttvi_power () ;
  a = __pf -> getCurrent () ;
  di = __pf -> get_Di_Dtheta () ;
  a_wo_capper = __pf -> getCurrentWithoutCapper () ;
  a_main_circuit = __pf -> getMainCircuitCurrent () ;
  noshibo = __pf -> getCurrentWithoutLimiter () ;
  is_limiting_regen = __pf -> isLimitingRegen () ;
  rnotch_for_capper = __pf -> getNotchRateForCapper () ;
  * trn_ess = __pf -> getESS () ;
  delete __pf ;
  return ;
}




// ----
// ttvi_brake() is now member of class train::_ParamFunc. This function
// creates one instance of train::_ParamFunc, execute ttvi_brake() , then
// delete the instance.
// ttvi_brake() はクラス train::_ParamFunc のメンバに移動。この関数は，
// train::_ParamFunc のインスタンスを生成，ttvi_brake() を実行後当該
// インスタンスを破棄する。
// ----
void
train :: ttvi_brake
()
{
  train_ParamFunc * __pf = getNewParamFuncCalculator () ;
  __pf -> ttvi_brake () ;
  a = __pf -> getCurrent () ;
  di = __pf -> get_Di_Dtheta () ;
  a_wo_capper = __pf -> getCurrentWithoutCapper () ;
  a_main_circuit = __pf -> getMainCircuitCurrent () ;
  noshibo = __pf -> getCurrentWithoutLimiter () ;
  is_limiting_regen = __pf -> isLimitingRegen () ;
  rnotch_for_capper = __pf -> getNotchRateForCapper () ;
  * trn_ess = __pf -> getESS () ;
  delete __pf ;
  return ;
}



// 補機電流の計算
void
train :: ttvi_auxcurr
()
{
  // ----
  // Preserve main circuit current WITHOUT auxiliaries.
  // 補機分を除いた主回路電流は保存. （天野くん = 2010. 6. 7.）
  // ----
  shibo = a_main_circuit ;

  // 補機電流計算
  a_max_regen = noshibo ;

  if ( sw_aux_power )
  {
    // 電力一定モデリング→  a と di に足す
    // 電流ではないが, auxcurr 変数を共用していることに注意
    a -= auxcurr * 1000 / v ;
    a_max_regen -= auxcurr * 1000 / v ;
    di += auxcurr * 1000 / ( v * v ) ;
  }
  else
  {
    // 電流一定モデリング→ a に足すだけ, 簡単！
    a -= auxcurr ;
    a_max_regen -= auxcurr ;
  }
}


// ----
// Subprogram of teta_vi(), managing on-board ESS's
// teta_vi() のサブプログラム, ESSがらみ
// ----
void
train :: ttvi_ess
()
{
  // ----
  // Charge / discharge control of the on-board ESS.
  // 車載エネルギー蓄積装置の充放電制御.
  // ----
  train_ParamFunc * __pf = getNewParamFuncCalculator () ;
  __pf -> ttvi_ess () ;
  __pf -> ttvi_RegenLimiter () ;
  a = __pf -> getCurrent () ;
  di = __pf -> get_Di_Dtheta () ;
  a_wo_capper = __pf -> getCurrentWithoutCapper () ;
  a_main_circuit = __pf -> getMainCircuitCurrent () ;
  noshibo = __pf -> getCurrentWithoutLimiter () ;
  is_limiting_regen = __pf -> isLimitingRegen () ;
  rnotch_for_capper = __pf -> getNotchRateForCapper () ;
  ( * trn_ess ) = __pf -> getESS () ;
  delete __pf ;
}



// teta から volt, ampere へ（仮想関数）
void
train :: teta_vi
()
{
  rnotch_for_capper = 1.0 ;
  is_limiting_regen = false ;
  is_limiting_max_curr = false ;

  // 電圧決定、混雑率チェック
  tetavisub ( rnotch ) ;

  switch ( stat )
  {
  case Power :		// 力行時
  case Const_vel :	// 定速走行時もここでよさそう
  L_casePower:
    // rnotch <0 なら回生へ
    if ( rnotch < - INVLIM ) goto L_caseBrake ;
    // rnotch =0 なら惰行へ
    if ( rnotch < INVLIM ) goto L_caseCoast ;
#ifdef DEBUG
    cerr << "car " << carno << ": ttvi_power to start" << endl ;
#endif
    ttvi_power () ;
#ifdef DEBUG
    cerr << "car " << carno << ": ttvi_power ended" << endl ;
#endif
    break ;

  case Coast :		// 惰行時
  case Stn_stop :	// 駅停車時も
  case Between_stop :	// 駅間停車時もここでよさそう
  L_caseCoast:
    // rnotch <0 なら回生へ
    if ( rnotch < - INVLIM ) goto L_caseBrake ;
    // rnotch >0 なら力行へ
    if ( rnotch > INVLIM ) goto L_casePower ;
    // 電流ゼロ
    a_wo_capper = a_main_circuit = noshibo = a = di = 0.0 ;
    // ----
    // ESS-related processes.
    // ESS がらみの処理.
    // ----
#ifdef DEBUG
    cerr << "car " << carno << ": ttvi_ess to start" << endl ;
#endif
    ttvi_ess () ;
#ifdef DEBUG
    cerr << "car " << carno << ": ttvi_ess ended" << endl ;
#endif
    break ;

  case Brake :		// ブレーキ時
  case Regenerate :	// 「回生のみ」時も
  L_caseBrake:
#ifdef DEBUG
    cerr << "car " << carno << ": ttvi_brake to start" << endl ;
#endif
    // rnotch >0 なら力行へ
    if ( rnotch > INVLIM ) goto L_casePower ;
    // rnotch =0 なら惰行へ
    if ( rnotch > - INVLIM ) goto L_caseCoast ;
    ttvi_brake () ;
#ifdef DEBUG
    cerr << "car " << carno << ": ttvi_brake ended" << endl ;
#endif
    break ;
  }

  ttvi_auxcurr () ;		// 補機電流の計算
}


// teta_vi のサブプログラム
// 2007. 10. 1. Moved from train.cc
void
train :: tetavisub
( double snotch )
{
  teta_v_only () ;

  // 混雑率をチェック
  double miv , mav ;
  if ( snotch >= 0.0 )
  {
    miv = pdata . minvol ;
    mav = pdata . maxvol ;
  }
  else
  {
    miv = bdata . minvol ;
    mav = bdata . maxvol ;
  }
  if ( v < miv ) vset ( miv ) ;
  if ( v > mav ) vset ( mav ) ;
  if ( conges < 0 )
  {
    std :: cerr << "Error: congestion rate must be positive" << std :: endl ;
    exit ( 25 ) ;	// error 25: 混雑率設定エラー
  }
}


// 電圧のみセット
// 2007. 10. 1. Moved from train.hh header file
void
train :: teta_v_only
()
{
  v = calculateVoltageFromCarTeta ( tt ) ;
  dv = 1.0 ;
}


// 電圧値のセット
// 2007. 10. 1. Moved from train.cc
void
train :: vset
( double mv )
{
  v = mv ;
  tt = calculateCarTetaFromVoltage ( v ) ;
}


// 媒介変数の最大値
double
train :: getMaximumTeta
()
{
  return getMaximumTeta ( rnotch ) ;
}


// 媒介変数の最大値
double
train :: getMaximumTeta
( double snotch )
{
  double max_volt
    = ( snotch >= 0.0 ) ? pdata . maxvol : bdata . maxvol ;
  return getTetaFromVoltage ( max_volt ) ;
}


// 媒介変数の最小値
double
train :: getMinimumTeta
()
{
  return getMinimumTeta ( rnotch ) ;
}


// 媒介変数の最小値
double
train :: getMinimumTeta
( double snotch )
{
  double min_volt
    = ( snotch >= 0.0 ) ? pdata . minvol : bdata . minvol ;
  return getTetaFromVoltage ( min_volt ) ;
}


// 電圧から媒介変数を求める
double
train :: getTetaFromVoltage
()
{
  return getTetaFromVoltage ( v ) ;
}


// 電圧から媒介変数を求める
double
train :: getTetaFromVoltage
( double v_in )
{
  
}



// teta に加える
// 2007. 10. 1. Moved from train.cc
void
train :: add_to_teta
( double tx ,
  bool sw_fail )
{
  if ( sw_fail )
  {
    if ( tx > FAILCAR ) tx = FAILCAR ;
    if ( tx < - FAILCAR ) tx = - FAILCAR ;
  }
  double xtt = tt + tx ;
  if ( calculateVoltageFromCarTeta ( xtt ) > bdata . startvol
       && rnotch < 0.0 && ( ! sw_regendead ) )
  {
    if ( calculateVoltageFromCarTeta ( tt ) < bdata . startvol )
    {
      tx = calculateCarTetaFromVoltage ( bdata . startvol ) - tt + INVLIM ;
    }
    else
    {
      if ( tx > REGEN_OFF_TETA ) tx = REGEN_OFF_TETA ;
      if ( tx < - REGEN_OFF_TETA ) tx = - REGEN_OFF_TETA ;
    }
  }
  if ( sw_fail && isLimitingRegen () )
  {
    double txm = getRegenTaperWidth ( FAILSHIBO ) ;
    if ( tx > txm ) tx = txm ;
    if ( tx < - txm ) tx = - txm ;
  }
  tt += tx ;
}


// teta から電圧を求める
double
calculateVoltageFromCarTeta
( double tt_in )
{
  return tt_in + nominal_volt ;
}


// 電圧から teta を求める
double
calculateCarTetaFromVoltage
( double v_in )
{
  return v_in - nominal_volt ;
}



// ----
// Sub_program of train::teta_vi(). When the train is in regenerative
// brake mode. Regeneration "taper" characteristics routine.
// train::teta_vi() のサブプログラム. 列車が回生時の処理. 回生絞込特性
// を表現するルーチン.
// ----
double
train_ParamFunc :: ttvi_brake_shibori
( double tvv ,
  double tmpx ,
  double tfmax ,
  double tflim )
  const
{
  if ( __sw_shibori_parallel )
  {
    // 絞り込み方式: Ｂタイプ
    return tfmax - tflim * ( tvv - __bd . startvol ) / tmpx ;
  }
  else
  {
    // 絞り込み方式: Ａタイプ
    return tflim * ( __bd . regendvol - tvv ) / tmpx ;
  }
}



// ----
// Subprogram of teta_vi(), managing on-board ESS's
// teta_vi() のサブプログラム, ESSがらみ
// ----
void
train_ParamFunc :: ttvi_ess
()
{
  if ( ! trn_ess )
  {
    cerr << "Error in train_ParamFunc::ttvi_ess(): null pointer" << endl ;
    exit ( 1 ) ;
  }

  // ----
  // Charge / discharge control of the on-board ESS.
  // 車載エネルギー蓄積装置の充放電制御.
  // ----
  trn_ess -> calculateVoltagesAndCurrents ( this ) ;
}



// ----
// Subprogram of teta_vi(), managing on-board ESS's, after regen limiter
// processing.
// teta_vi() のサブプログラム, ESSがらみ, 回生絞込処理終了後.
// ----
void
train_ParamFunc :: ttvi_ess_ProcessRegenLimiter
()
{
  trn_ess -> processRegenerationLimiter ( this ) ;
}



// ----
// Subprogram of train::teta_vi(). Regen Limiter (taper characteristics).
// train::teta_vi() のサブプログラム. 回生絞込の処理.
// ----
void
train_ParamFunc :: ttvi_RegenLimiter
()
{
  double _vlow = __vlow_b ;
  double _vhigh = __vhigh_b ;
  double _ampmax = __ampmax_b ;
  double _tfmax = __constf_b ;
  double _amplim = __bd . pbfull . mcurr ;
  double _tflim = fabs ( __bd . pbfull . tracf ) ;

  // 定数と速度から電圧、電流の決定
  double _vl = _vlow * __v / __bd . ec ;
  double _vh = _vhigh * __v / __bd . ec ;
  double _x = __bd . ec / _vlow ;
  double _rvl = _x / __v ;
  double _dvrl = _x / ( __v + __dv ) - _rvl ;
  double _dvh = _vhigh * __dv / __bd . ec ;
  double _tracf ;
  if ( __vel < __bd . regenoff )
  {
    _tracf = 0.0 ;
  }
  else if ( __vel < _vl )
  {
    _tracf = fabs ( __rnotch * _tfmax ) ;
  }
  else if ( __vel < _vh )
  {
    _tracf = fabs ( __rnotch * _tfmax * _vl / __vel ) ;
  }
  else
  {
    _tracf = fabs ( __rnotch * _tfmax * _vl * _vh / ( __vel * __vel ) ) ;
  }

  _tracf *= __rnotch_for_capper ;

  // ----
  // Controls for the "taper characteristics" of the regeneration overvoltage
  // limiter.
  // 絞り込み制御（過電圧抑制制御の「テーパ特性」）部分.
  // ----
  if ( __sw_regendead && __a > 0 )
  {
    // 狭義の回生失効中
    __a = __di = 0.0 ;
  }
  else if ( __a > 0 )
  {
    double _tmpx = __bd . regendvol - __bd . startvol ;
    if ( __sw_torque_shibori )
    {
      // モータ電流による絞り込み判定
      double _tfs = ttvi_brake_shibori ( __v , _tmpx , _tfmax , _tflim ) ;
      if ( _tracf > _tfs )
      {
	// 絞り込み
	__is_limiting_regen = true ;
	if ( _tracf > INVLIM )
	{
	  __a = __noshibo * _tfs / _tracf ;
	  __di = - __dv * _tflim * __noshibo / ( _tmpx * _tracf ) ;
	}
	else
	{
	  __a = __di = 0.0 ;
	}
      }
      // ----
      // Change 2010. 2. 6. __a will remain unchanged.
      // ----
//       else
//       {
// 	__a = __noshibo ;
//       }
    }
    else
    {
      // 直流側電流による絞り込み判定
      double _as = ttvi_brake_shibori ( __v , _tmpx , _ampmax , _amplim ) ;
      if ( _as < 0 )
      {
        _as = 0 ;
      }
      if ( __a > _as )
      {
	// 絞り込み
	__is_limiting_regen = true ;
	__a = _as ;
	__di = - __dv * _amplim / _tmpx ;
      }
      // ----
      // Change 2010. 2. 6. __a will remain unchanged.
      // ----
//       else
//       {
// 	__a = __noshibo ;
//       }
    }
    if ( __sw_regenoffantei )
    {
      if ( __a < 0.0 )
      {
	double _vxband = __bd . maxvol - __bd . regendvol ;
	__a = 0.0 ;
	double _v_x = __v - _vxband ;
	double _as ;
	if ( __sw_torque_shibori )
	{
	  // モータ電流による絞り込み
	  double _tfs
            = ttvi_brake_shibori ( _v_x , _tmpx , _tfmax , _tflim ) ;
	  if ( _tracf > INVLIM )
          {
            _as = __noshibo * _tfs / _tracf ;
          }
          else
          {
            _as = 0.0 ;
          }
	}
        else
        {
          _as = ttvi_brake_shibori ( _v_x , _tmpx , _ampmax , _amplim ) ;
        }
        __di = - _as / _vxband ;
      }
    }
    // ----
    // Change 2010. 2. 6. __a will remain unchanged.
    // ----
//     else if ( __a < 0 )
//     {
//       __a = 0.0 ;
//       __di = 0.0 ;
//     }
  }

  // ----
  // Processing ESS-related routines.
  // ESS がらみの処理.
  // ----
  ttvi_ess_ProcessRegenLimiter () ;
}



// ----
// Subprogram of train::teta_vi(). When the train is in regen brake mode.
// train::teta_vi() のサブプログラム. 列車が回生時の処理.
// ----
void
train_ParamFunc :: ttvi_brake
()
{
  double _vlow = __vlow_b ;
  double _vhigh = __vhigh_b ;
  double _ampmax = __ampmax_b ;
  double _tfmax = __constf_b ;
  double _amplim = __bd . pbfull . mcurr ;
  double _tflim = fabs ( __bd . pbfull . tracf ) ;

  // 定数と速度から電圧、電流の決定
  double _vl = _vlow * __v / __bd . ec ;
  double _vh = _vhigh * __v / __bd . ec ;
  double _x = __bd . ec / _vlow ;
  double _rvl = _x / __v ;
  double _dvrl = _x / ( __v + __dv ) - _rvl ;
  double _dvh = _vhigh * __dv / __bd . ec ;
//   double _tracf ;
  if ( __vel < __bd . regenoff )
  {
//     _tracf = 0.0 ;
    __noshibo = __di = 0 ;
  }
  else if ( __vel < _vl )
  {
//     _tracf = fabs ( __rnotch * _tfmax ) ;
    __noshibo = - __rnotch * _ampmax * ( __vel - __bd . regenoff ) ;
    __noshibo /= _vl - __bd . regenoff ;
    __di = - __rnotch * _ampmax * ( __vel - __bd . regenoff ) * _dvrl ;
  }
  else if ( __vel < _vh )
  {
//     _tracf = fabs ( __rnotch * _tfmax * _vl / __vel ) ;
    __noshibo = - __rnotch * _ampmax ;
    __di = 0.0 ;
  }
  else
  {
//     _tracf = fabs ( __rnotch * _tfmax * _vl * _vh / ( __vel * __vel ) ) ;
    __noshibo = - __rnotch * _ampmax * _vh / __vel ;
    __di = - __rnotch * _ampmax * _dvh / __vel ;
  }
  __di += __noshibo * __dnch / __rnotch ;	// 電流微分値の補正

  __a_wo_capper = __a_main_circuit = __a = __noshibo ;

#ifdef DEBUG
  cerr << StrPrintf ( "vl, vh, vel = %.3f %.3f %.3f" , _vl , _vh , __vel )
       << endl ;
#endif

  // ----
  // Processing ESS-related routines.
  // ESS がらみの処理.
  // ----
  ttvi_ess () ;
#ifdef DEBUG
  cerr << "  pos: " << __pos << "  vel: " << __vel
       << ", train_ParamFunc::ttvi_power, ttvi_ess ended" << endl ;
#endif

  // ----
  // Processing regen limiter related routines.
  // 回生絞込がらみの処理.
  // ----
  ttvi_RegenLimiter () ;

//   _tracf *= __rnotch_for_capper ;

//   // ----
//   // Controls for the "taper characteristics" of the regeneration overvoltage
//   // limiter.
//   // 絞り込み制御（過電圧抑制制御の「テーパ特性」）部分.
//   // ----
//   if ( __sw_regendead )
//   {
//     // 狭義の回生失効中
//     __a = __di = 0.0 ;
//   }
//   else
//   {
//     double _tmpx = __bd . regendvol - __bd . startvol ;
//     if ( __sw_torque_shibori )
//     {
//       // モータ電流による絞り込み判定
//       double _tfs = ttvi_brake_shibori ( __v , _tmpx , _tfmax , _tflim ) ;
//       if ( _tracf > _tfs )
//       {
// 	// 絞り込み
// 	__is_limiting_regen = true ;
// 	if ( _tracf > INVLIM )
// 	{
// 	  __a = __noshibo * _tfs / _tracf ;
// 	  __di = - __dv * _tflim * __noshibo / ( _tmpx * _tracf ) ;
// 	}
// 	else
// 	{
// 	  __a = __di = 0.0 ;
// 	}
//       }
//       // ----
//       // Change 2010. 2. 6. __a will remain unchanged.
//       // ----
// //       else
// //       {
// // 	__a = __noshibo ;
// //       }
//     }
//     else
//     {
//       // 直流側電流による絞り込み判定
//       double _as = ttvi_brake_shibori ( __v , _tmpx , _ampmax , _amplim ) ;
//       if ( __a > _as )
//       {
// 	// 絞り込み
// 	__is_limiting_regen = true ;
// 	__a = _as ;
// 	__di = - __dv * _amplim / _tmpx ;
//       }
//       // ----
//       // Change 2010. 2. 6. __a will remain unchanged.
//       // ----
// //       else
// //       {
// // 	__a = __noshibo ;
// //       }
//     }
//     if ( __sw_regenoffantei )
//     {
//       if ( __a < 0.0 )
//       {
// 	double _vxband = __bd . maxvol - __bd . regendvol ;
// 	__a = 0.0 ;
// 	double _v_x = __v - _vxband ;
// 	double _as ;
// 	if ( __sw_torque_shibori )
// 	{
// 	  // モータ電流による絞り込み
// 	  double _tfs
//             = ttvi_brake_shibori ( _v_x , _tmpx , _tfmax , _tflim ) ;
// 	  if ( _tracf > INVLIM )
//           {
//             _as = __noshibo * _tfs / _tracf ;
//           }
//           else
//           {
//             _as = 0.0 ;
//           }
// 	}
//         else
//         {
//           _as = ttvi_brake_shibori ( _v_x , _tmpx , _ampmax , _amplim ) ;
//         }
//         __di = - _as / _vxband ;
//       }
//     }
//     // ----
//     // Change 2010. 2. 6. __a will remain unchanged.
//     // ----
// //     else if ( __a < 0 )
// //     {
// //       __a = 0.0 ;
// //       __di = 0.0 ;
// //     }
//   }

//   // ----
//   // Processing ESS-related routines.
//   // ESS がらみの処理.
//   // ----
//   ttvi_ess_ProcessRegenLimiter () ;
}



// ----
// Subprogram of train::teta_vi(). When the train is in acceleration mode.
// train::teta_vi() のサブプログラム. 列車が力行時の処理.
// ----
void
train_ParamFunc :: ttvi_power
()
{
  // 混雑率から定数の決定
  double vlow = __vlow_p ;
  double vhigh = __vhigh_p ;
  double ampmax = __ampmax_p ;

  // 定数と速度から電圧、電流の決定
  double vl = vlow * __v / __pd . ec ;
  double vh = vhigh * __v / __pd . ec ;

#ifdef DEBUG
  cerr << "  pos: " << __pos << "  vel: " << __vel
       << ", in train_ParamFunc::ttvi_power" << endl ;
#endif
  tv_p_ne ( vh , vhigh , vl , vlow , ampmax ) ;
#ifdef DEBUG
  cerr << "  tv_p_ne ended" << endl ;
#endif

  __a *= - __rnotch ;		// 電流の補正
  __di *= - __rnotch ;
  __di += __a * __dnch / __rnotch ;	// 電流微分の補正

  // noshibo にも値を記憶させておく
  __a_wo_capper = __a_main_circuit = __noshibo = __a ;

  // ----
  // Processing ESS-related routines.
  // ESS がらみの処理.
  // ----
  ttvi_ess () ;
  ttvi_RegenLimiter () ;
}



// 力行・定トルク領域
void
train_ParamFunc :: tv_p_tc
( double & a1 ,
  double vl ,
  double vlow ,
  double ampmax )
{
  double zeroc = tv_p_tc ( a1 , vl , ampmax ) ;
  __di = ( __pd . zerocur * __pd . ec ) * ( __vel - vl ) ;
  __di /= __v * __v * vl ;
  __di += ( zeroc - ampmax ) * __vel * vlow / ( vl * vl * __pd . ec ) ;
}



// 力行・定トルク領域
double
train_ParamFunc :: tv_p_tc
( double & a1 ,
  double vl ,
  double ampmax )
  const
{
  double zeroc = __pd . zerocur * __pd . ec / __v ;
  a1 = zeroc + ( ampmax - zeroc ) * __vel / vl ;
  return zeroc ;
}



// 力行・通常時
void
train_ParamFunc :: tv_p_ne
( double vh ,
  double vhigh ,
  double vl ,
  double vlow ,
  double ampmax )
{
  if ( __vel < vl )
  {
    tv_p_tc ( __a , vl , vlow , ampmax ) ;
  }
  else if ( __vel < vh )
  {
    __a = ampmax ;
    __di = 0.0 ;
  }
  else
  {
    double dvh = vhigh * __dv / __pd . ec ;
    __a = ampmax * vh / __vel ;
    __di = ampmax * dvh / __vel ;
  }
}
