Beispiel #1
0
//---------------------------------------------------------
void CrolPlayer::UpdateVoice(int const voice, CVoiceData & voiceData)
{
    TNoteEvents const & nEvents = voiceData.note_events;

    if (nEvents.empty() || (voiceData.mEventStatus & CVoiceData::kES_NoteEnd))
    {
        return; // no note data to process, don't bother doing anything.
    }

    TInstrumentEvents const & iEvents = voiceData.instrument_events;
    TVolumeEvents     const & vEvents = voiceData.volume_events;
    TPitchEvents      const & pEvents = voiceData.pitch_events;

    if ((voiceData.mEventStatus & CVoiceData::kES_InstrEnd) == 0)
    {
        if (voiceData.next_instrument_event < iEvents.size())
        {
            if (iEvents[voiceData.next_instrument_event].time == mCurrTick)
            {
                send_ins_data_to_chip(voice, iEvents[voiceData.next_instrument_event].ins_index);
                ++voiceData.next_instrument_event;
            }
        }
        else
        {
            voiceData.mEventStatus |= CVoiceData::kES_InstrEnd;
        }
    }

    if ((voiceData.mEventStatus & CVoiceData::kES_VolumeEnd) == 0)
    {
        if (voiceData.next_volume_event < vEvents.size())
        {
            if (vEvents[voiceData.next_volume_event].time == mCurrTick)
            {
                SVolumeEvent const & volumeEvent = vEvents[voiceData.next_volume_event];

                uint8_t const volume = (uint8_t)(skMaxVolume * volumeEvent.multiplier);

                SetVolume(voice, volume);

                ++voiceData.next_volume_event; // move to next volume event
            }
        }
        else
        {
            voiceData.mEventStatus |= CVoiceData::kES_VolumeEnd;
        }        
    }

    if (voiceData.mForceNote || (voiceData.current_note_duration > voiceData.mNoteDuration-1))
    {
        if (mCurrTick != 0)
        {
            ++voiceData.current_note;
        }

        if (voiceData.current_note < nEvents.size())
        {
            SNoteEvent const & noteEvent = nEvents[voiceData.current_note];

            SetNote(voice, noteEvent.number);
            voiceData.current_note_duration = 0;
            voiceData.mNoteDuration         = noteEvent.duration;
            voiceData.mForceNote            = false;
        }
        else
        {
            SetNote(voice, kSilenceNote);
            voiceData.mEventStatus |= CVoiceData::kES_NoteEnd;
            return;
        }
    }

    if ((voiceData.mEventStatus & CVoiceData::kES_PitchEnd) == 0)
    {
        if ( voiceData.next_pitch_event < pEvents.size() )
        {
            if (pEvents[voiceData.next_pitch_event].time == mCurrTick)
            {
                SetPitch(voice, pEvents[voiceData.next_pitch_event].variation);
                ++voiceData.next_pitch_event;
            }
        }
        else
        {
            voiceData.mEventStatus |= CVoiceData::kES_PitchEnd;
        }
    }

    ++voiceData.current_note_duration;
}
Beispiel #2
0
void FilterPress::EvalProducts()
{
	try {
		int idPressNote = 0, idWashNote = 1;
		MStreamI QFeed;
		FlwIOs.AddMixtureIn_Id(QFeed, idFeed);
		const double dFeedSolidMass = QFeed.Mass(MP_Sol);
		const double dFeedLiquidMass = QFeed.Mass(MP_Liq);

    MStreamI QWashWater;
		const bool bWashWaterConnected = (FlwIOs.getCount(idWash) > 0);
		if (bWashWaterConnected)
			FlwIOs.AddMixtureIn_Id(QWashWater, idWash);

		//MStream QUnwashedCake = QFeed; BAD idea, QUnwashedCake becomes a reference to QFeed!!!!
		MStreamI QUnwashedCake;
    QUnwashedCake = QFeed;
		QUnwashedCake.ZeroMass();

    MStream&	QFiltrate	= FlwIOs[FlwIOs.First[idFiltrate]].Stream;
    QFiltrate	= QFeed;
    MStream&	QCake		= FlwIOs[FlwIOs.First[idCake]].Stream;
    QCake		= QFeed;

		const bool bWashingsConnected = (FlwIOs.Count[idWashings] > 0);

		//First off: The filtrate & UnwashedCake:

		/*Equations Solved using Mathematica 6.0, under the constrainsts of:
		 - Conservation of mass
		 - Cake Moisture Content
		 - Filtrate Solid Concentration [Either in % or g/L]
			- When using g/L, assume solid and liquid densities don't change [The (Aq) conc's don't]
		*/
		double dSolConcConstFac, dLiqConcConstFac;
		bool bTooWet;
		switch (eFiltrateMethod) {
		case FM_SolidsToFiltrateFrac:
			dSolConcConstFac = dReqSolidsToFiltrate;
			dLiqConcConstFac = dReqSolidsToFiltrate;
			bTooWet = dFeedSolidMass / NZ(dFeedSolidMass + dFeedLiquidMass) < dReqSolidsToFiltrate;
			break;
		case FM_FiltrateConc:
			dSolConcConstFac = dReqFiltSolConc / QFeed.Density(MP_Sol, C_2_K(25));
			dLiqConcConstFac= dReqFiltSolConc / QFeed.Density(MP_Liq, C_2_K(25));
			bTooWet = dFeedSolidMass / NZ(QFeed.Volume(MP_SL, C_2_K(25))) < dReqFiltSolConc;
			break;
		}
		/*Situations where variables can be out of range:
		 - Mass comes in too wet - required loss causes all mass to be sent to filtrate
		 - Mass comes in too dry - mass is drier than required moisture frac.
		*/
		double dFiltSolidFactor, dFiltLiquidFactor, dCakeSolidFactor, dCakeLiquidFactor;
		if (bTooWet)
		{
			SetNote(idPressNote, "Input feed too wet: All feed solids sent to filtrate");
			dFiltSolidFactor = dFiltLiquidFactor = 1;
			dCakeSolidFactor = dCakeLiquidFactor = 0;
		}
		else if (dFeedLiquidMass / NZ(dFeedSolidMass + dFeedLiquidMass) < dReqCakeMoisture)
		{
			SetNote(idPressNote, "Input feed too dry: All feed liquids sent to Cake");
			dFiltSolidFactor = dFiltLiquidFactor = 0;
			dCakeSolidFactor = dCakeLiquidFactor = 1;
		}
		else
		{
			dFiltSolidFactor = (((dFeedLiquidMass * (dReqCakeMoisture - 1) + dFeedSolidMass * dReqCakeMoisture) * dLiqConcConstFac)
									/ NZ(dReqCakeMoisture * dLiqConcConstFac - (dReqCakeMoisture - 1)*(dSolConcConstFac-1))) / dFeedSolidMass;
			dFiltLiquidFactor = - (((dFeedLiquidMass * (dReqCakeMoisture - 1) + dFeedSolidMass * dReqCakeMoisture) * (dSolConcConstFac - 1))
									/ NZ(dReqCakeMoisture * dLiqConcConstFac - (dReqCakeMoisture - 1)*(dSolConcConstFac - 1))) / dFeedLiquidMass;

			dCakeSolidFactor = 1 - dFiltSolidFactor;
			dCakeLiquidFactor = 1 - dFiltLiquidFactor;
		}

		for (int i = 0; i < gs_MVDefn.Count(); i++)
			if (gs_MVDefn[i].IsSolid())
			{
				QFiltrate.M[i] = QFeed.M[i] * dFiltSolidFactor;
				QUnwashedCake.M[i] = QFeed.M[i] * dCakeSolidFactor;
			}
			else if (gs_MVDefn[i].IsLiquid())
			{
				QFiltrate.M[i] = QFeed.M[i] * dFiltLiquidFactor;
				QUnwashedCake.M[i] = QFeed.M[i] * dCakeLiquidFactor;
			}

		//Now, wash it:
		//First, add the washwater solids, and record what mass of solids we add.
		//The equations associated with this are exceedingly ugly.
		if (FlwIOs.getCount(idWash) > 0) {
			//Short variables to create fewer errors translating the equations
			double WS = QWashWater.Mass(MP_Sol);
			double WL = QWashWater.Mass(MP_Liq);
			double CS = QUnwashedCake.Mass(MP_Sol);
			double CL = QUnwashedCake.Mass(MP_Liq);
			double a, rWS, rWL, rCS, rCL;
			double m = dReqCakeMoisture;
			double w;
			switch (eWashMethod)
			{
			case WM_ConstantEfficiency:
				w = dReqWashEfficiency;
			case WM_WashRatio:
				dWashRatio = WL / NZ(CL);
				w = 1 - pow(1-dReqWashEfficiency, dWashRatio);
			}
			switch (eFiltrateMethod) {
			case FM_SolidsToFiltrateFrac:
				a = dReqSolidsToFiltrate;
				rWS = rWL = rCS = rCL = 1;
				break;
			case FM_FiltrateConc:
				a = dReqFiltSolConc;
				rWS = QWashWater.Density(MP_Sol, C_2_K(25));
				rWL = QWashWater.Density(MP_Liq, C_2_K(25));
				rCS = QUnwashedCake.Density(MP_Sol, C_2_K(25));
				rCL = QUnwashedCake.Density(MP_Liq, C_2_K(25));
				break;
			}
			/*Possible situations where variables are out of range:
			 - A: Too much wash liquid - all solids are sent out in washings ['Fix' by sending everyhing to washings. Assume we will not end up with only washing solids]
			 - B: Not enough wash liquid - required wash efficiency impossible ['Fix' by putting all wash water in cake]
			 - C: Cake comes in dry [And very dry] - wash efficiency is higher than requested even if no cake moisture is displaced. 
				[Fix by sending everything].
			 - D: Wash water has FAAR too many solids - cake moisture is lower than required. [Fix by putting everything into cake]
			 - Cake should never come in too wet.
			 */
			//CO - Cake Out. WO - Washings out.
			double dCLtoCO, dCStoCO, dWStoCO;
			
			double dTemp = (WS*rCL*rCS*rWL*(a-rWS)+(a*WL*rCL*rCS+(CS*rCL*(a-rCS)+a*CL*rCS)*rWL)*rWS)
				/ NZ(CS*(m*a*(1-w)*rCS*rWL+rCL*((1-m)*a*rWL+rCS*(m*a*w-(1-m)*rWL)))*rWS + WS*rCL*rCS*((1-m)*rWL*(a-rWS)+m*a*rWS));

			double dWLtoCO = m * (w*CS + WS) * dTemp;
			if (dWLtoCO > WL)
			{ //Case B - not enough wash liquid
				SetNote(idWashNote, "Not enough wash water: All wash water sent to cake");
				//double dTemp1 = (WS*rCL*rCS*(a-rWS)+(CS*rCL*(a-rCS)+a*CL*rCS)*rWS)
				//			/ NZ(CS*((1-m)*rCL*(a-rCS)+m*a*rCS)*rWS + WS*rCS*((1-m)*rCL*(a-rWS) + m*a*rWS));
				double dTemp1 = 1 / (CS * ((1-m) * rCL * (a-rCS) + m*a*rCS) * rWS + WS * rCS * ((1-m) * rCL * (a-rWS) + m*a*rWS));
				double dTemp2 = WS * rCL * rCS * (a-rWS) + (CS * rCL * (a-rCS) + a*(CL+WL)*rCS)*rWS;
				
				dWLtoCO = WL;
				dCLtoCO = (m*CS*CS*rCL*(a-rCS)*rWS + CS*((-(1-m)*WL*rCL*(a-rCS) + m*a*CL*rCS)*rWS+m*WS*rCL*(rCS*(a-2*rWS)+a*rWS))
							+ WS*rCS*(-(1-m)*WL*rCL*(a-rWS) + m*(WS*rCL*(a-rWS) + a*CL*rWS))) * dTemp1;
				dCStoCO = (1-m) * CS * dTemp1 * dTemp2;
				dWStoCO = (1-m) * WS * dTemp1 * dTemp2;
			}
			else
			{
				//dWLtoCO already set.
				dCLtoCO = m * (1-w) * CS * dTemp;
				dCStoCO = (1-m) * CS * dTemp;
				dWStoCO = (1-m) * WS * dTemp;
			}

			if (dCLtoCO > CL) { //Case C - not enough cake moisture [Can only happen if cake comes in with moisture content v. low.]
				dCLtoCO = CL;	//Although this results in a lower than required moisture content, well, the cake is comming in drier than required.
				SetNote(idWashNote, "Cake too dry"); }
			
			//Simple Cons of Mass:
			double dWLtoWO = WL - dWLtoCO;
			double dCLtoWO = CL - dCLtoCO;
			double dWStoWO = WS - dWStoCO;
			double dCStoWO = CS - dCStoCO;

			double dWLtoCOFrac,dCLtoCOFrac,dWStoCOFrac,dCStoCOFrac,dWLtoWOFrac,dCLtoWOFrac,dWStoWOFrac,dCStoWOFrac;
			if (dCStoCO < 0) //Case A, Too wet: Everything sent with washings
			{
				SetNote(idWashNote, "Too much liquid in WashWater. Everything sent to washings");
				dWLtoCOFrac=dCLtoCOFrac=dWStoCOFrac=dCStoCOFrac=0;
				dWLtoWOFrac=dCLtoWOFrac=dWStoWOFrac=dCStoWOFrac=1;
			}
			else if ((CL+WL)/NZ(CS+WS+CL+WL) < m)	//Case D, Too Dry: Send everything to cake.
			{
				SetNote(idWashNote, "Not enough liquid in washing stage. Everything sent to cake");
				dWLtoCOFrac=dCLtoCOFrac=dWStoCOFrac=dCStoCOFrac=1;
				dWLtoWOFrac=dCLtoWOFrac=dWStoWOFrac=dCStoWOFrac=0;
			}
			else
			{
				//Here's where we handle if we have any other zeros.
				//Also handle if a variable manages to slip by the other checks [It is possible with outlandish input parameters.]
				dWLtoCOFrac = WL > 0 ? dWLtoCO / WL : 0;
				dCLtoCOFrac = CL > 0 ? dCLtoCO / CL : 0;
				dWStoCOFrac = WS > 0 ? dWStoCO / WS : 0;
				dCStoCOFrac = CS > 0 ? dCStoCO / CS : 0;
				dWLtoWOFrac = WL > 0 ? dWLtoWO / WL : 0;
				dCLtoWOFrac = CL > 0 ? dCLtoWO / CL : 0;
				dWStoWOFrac = WS > 0 ? dWStoWO / WS : 0;
				dCStoWOFrac = CS > 0 ? dCStoWO / CS : 0;
			}

			dWashEfficiency = CL > 0 ? 1 - dCLtoCOFrac : dNAN;

		  //MStream QWashingOutput = QCake; BAD idea, QWashingOutput becomes a reference to QCake!!!!
			MStreamI QWashingOutput;
			QWashingOutput = QCake;
			QWashingOutput.ZeroMass();

			for (int i = 0; i < gs_MVDefn.Count(); i++)
				if (gs_MVDefn[i].IsSolid())
				{
					QWashingOutput.M[i] = QUnwashedCake.M[i] * dCStoWOFrac + QWashWater.M[i] * dWStoWOFrac;
					QCake.M[i] = QUnwashedCake.M[i] * dCStoCOFrac + QWashWater.M[i] * dWStoCOFrac;
				}
				else if (gs_MVDefn[i].IsLiquid())
				{
					QWashingOutput.M[i] = QUnwashedCake.M[i] * dCLtoWOFrac + QWashWater.M[i] * dWLtoWOFrac;
					QCake.M[i] = QUnwashedCake.M[i] * dCLtoCOFrac + QWashWater.M[i] * dWLtoCOFrac;
				}

			double dInputHf;
			
			MStream* pQWashingOutput;
			if (bWashingsConnected) //bWashingsConnected indicates whether OUTPUT washings are connected.
			{
				dInputHf = QUnwashedCake.totHf() + QWashWater.totHf();
				pQWashingOutput = &QWashingOutput;
			}
			else
			{
				dInputHf = QUnwashedCake.totHf() + QWashWater.totHf() + QFiltrate.totHf();
				for (int i = 0; i < gs_MVDefn.Count(); i++)
					QFiltrate.M[i] += QWashingOutput.M[i];
				pQWashingOutput = &QFiltrate;	//For thermal property managing
			}

			double dgbTi = pQWashingOutput->T;
			bool converged = false;
			for (int i = 0; i < 10 && !converged; i++)
			{
				double dbgTt = pQWashingOutput->T;

				double dOutputHf = QCake.totHf() + pQWashingOutput->totHf();

				double deltaT = -(dOutputHf - dInputHf) / NZ(pQWashingOutput->totCp() + QCake.totCp());

				pQWashingOutput->T += deltaT;
				QCake.T = pQWashingOutput->T;

				converged = abs(dInputHf - dOutputHf) < 1; //TODO: Check what sort of convergence we require.
			}

			double dbgT = pQWashingOutput->T;
			double dbgT2 = QWashingOutput.T;

			if (bWashingsConnected)
			{
				MStream& QWashings = FlwIOs[FlwIOs.First[idWashings]].Stream;
				QWashings = QWashingOutput;
			}
		}
		else //If we have no washings
		{
			if (bWashingsConnected)
			{
				MStream& QWashings = FlwIOs[FlwIOs.First[idWashings]].Stream;
				QWashings.ZeroMass();
			}
			QCake = QUnwashedCake;
		}

		//Vent:
		if (FlwIOs.Count[idVent] > 0)
		{
			MStream& QVent = FlwIOs[FlwIOs.First[idVent]].Stream;
			QVent = QCake;
			QVent.ZeroMass();
			MStreamI QWashWater;
			if (FlwIOs.Count[idWash] > 0)
				QWashWater = FlwIOs[FlwIOs.First[idWash]].Stream;
			else
				QWashWater.ZeroMass();

			for (int i = 0; i < gs_MVDefn.Count(); i++)
				if (gs_MVDefn[i].IsGas())
					QVent.M[i] = QCake.M[i] + QWashWater.M[i];
		}
		
		//Update "Actual" values.
		dCakeSolids = QCake.MassFrac(MP_Sol);
		dFiltSolids = QFiltrate.MassFrac(MP_Sol);
		dCakeSolConc = QCake.Mass(MP_Sol) / NZ(QCake.Volume(MP_All, C_2_K(25.0)));
		dFiltSolConc = QFiltrate.Mass(MP_Sol) / NZ(QFiltrate.Volume(MP_All, C_2_K(25.0)));
		if (bWashWaterConnected)
		{
			double CFeed = QFeed.SpecieConc(MP_Liq, nWashCompSpecie, C_2_K(25.0));
			double CCake = QCake.SpecieConc(MP_Liq, nWashCompSpecie, C_2_K(25.0));
			double CWash = QWashWater.SpecieConc(MP_Liq, nWashCompSpecie, C_2_K(25.0));
			dWashCompEff = (CFeed - CCake) / NZ(CFeed - CWash);
		}
		else
		{
			dWashCompEff = 0;
			dWashEfficiency = 0;
		}
	}
  catch (MMdlException &e)
    {
    Log.Message(MMsg_Error, e.Description);
    }
  catch (MFPPException &e)
    {
    e.ClearFPP();
    Log.Message(MMsg_Error, e.Description);
    }
  catch (MSysException &e)
    {
    Log.Message(MMsg_Error, e.Description);
    }
  catch (...)
    {
    Log.Message(MMsg_Error, "Some Unknown Exception occured");
    }
}
Beispiel #3
0
void
ZProcess::ParseXML_Document( )
{
   // For each node we store data

   // If it's a Process Node, and the Root node
   if ( IsRoot( ) && IsTag( "<PROCESS>" ) )
   {
      // Handle Attributes
      if ( IsValidAttribute( "name" ) )
         SetProcessName( GetAttributeValue( ) );
   }

   // If it's the WriteLog Node in a Process node
   if ( IsTag( "<WRITELOG>" ) && IsChildOf( "<PROCESS>" ) )
   {
      // Set the WriteLog File Name
      SetWriteLogValue( GetTextValue( ) );

      // Handle Attributes
      if ( IsValidAttribute( "name" ) )
         this->SetWriteLogName( GetAttributeValue( ) );
   }

   // If it's the KillApp Node in a Process node
   if ( IsTag("<SHUTDOWN>") && IsChildOf( "<PROCESS>") )
   {
      // Set the KillApp command name
      SetKillAppValue( GetTextValue( ) );

      // Handle Attributes
      if ( IsValidAttribute( "delay" ) )
      {
         int delay;
         sscanf( GetAttributeValue( ) , "%d" , &delay );
         SetKillAppDelay( delay );
      }
   }

   // If it's the Startup Node in a Process node
   if ( IsTag("<STARTUP>") && IsChildOf( "<PROCESS>") )
   {
      // Set the Startup command name
      SetStartupValue( GetTextValue( ) );

      // Handle Attributes
      if ( IsValidAttribute( "delay" ) )
      {
         int delay;
         sscanf( GetAttributeValue( ) , "%d" , &delay );
         SetStartupDelay( delay );
      }
   }

   // If it's the NOTE node in a PROCESS node
   if ( IsTag("<NOTE>") && IsChildOf( "<PROCESS>") )
   {
      // do nothing ... just checking
   }

   // If it's the CDATA section on NOTE node
   if ( IsChildOf( "<NOTE>" ) && IsCDataSection( ) )
   {
      // Set the Note value
      CString val;

      val = GetTextValue( );
      SetNote( val );
   }
}