RISOLUTORE DI EXCEL IN VB.NET

di il
7 risposte

RISOLUTORE DI EXCEL IN VB.NET

Buongiorno.
Vado subito al dunque, ho 5 variabili:

* I valori di partenza assegnati a queste variabili sono stati calcolati in base a dei dati da seriale, quindi variano ogni volta.
* Questi valori sono quelli della mia prova attuale

Dim A As Double = -62.17
Dim B As Double = 1.08
Dim C As Double = 2.39
Dim D As Double = 9.24

Dim Solution As Double
Avrei bisogno di minizzare il valore di Solution cambiando i valori di A,B,C e D.
I valori di A,B e C sono vincolati nel seguente modo:
1) -360 < A < +360
2) B > 0
3) C > 0
Solution è un calcolo risultante da una media di valori calcolati utilizzando A,B,C e D.
Quindi Solution varia in base al valore di A,B,C e D.

Tornando al titolo, vorrei emulare quello che viene fatto in excel con il solver.
Infatti, in excel, cambiando dei valori di 4 celle vincolate, riesco a minimizzare il valore di una 5a cella.

Vorrei capire per prima cosa se è possibile farlo e se è possibile farlo spero possiate indicarmi la giusta via, grazie in anticipo.
Rimango in attesa..

7 Risposte

  • Re: RISOLUTORE DI EXCEL IN VB.NET

    La risposta è sì qualunque cosa sia: è dura che un linguaggio di programmazione non riesca a fare le cose che fa uno spreadsheet.

    Ma esattamente tu cosa vuoi fare? Hai dato un sacco di dati inutili, ma non quelli necessari.

    Solution = (A+B+C+D)/4 ?

    Hai un array di valori Solution e ad ogni nuova lettura devi aggiornare il minimo di tutto il set?
  • Re: RISOLUTORE DI EXCEL IN VB.NET

    Si hai ragione posto il codice completo di questa routine allora.
    
    		'Split Main String
            For i As Integer = 12 To 260 Step 2
                Readings((i - 12) / 2) = Readed(i)
                Time((i - 12) / 2) = Readed(i + 1)
            Next
    
            For i As Integer = 0 To 124
                ReadingsNum(i) = Convert.ToDouble(Readings(i))
                ReadingsNum(i) = FormatNumber(ReadingsNum(i), 2)
                TimeNum(i) = Convert.ToDouble(Time(i))
                TimeNum(i) = FormatNumber(TimeNum(i), 2)
            Next
    
            For i As Integer = 0 To 124
                If Discriminant = "2" Then
                    ReadingsMm(i) = Abs(ReadingsNum(i) / 100)
                Else
                    ReadingsMm(i) = Abs(ReadingsNum(i) / 1000)
                End If
                ReadingsSec(i) = Abs(TimeNum(i) / 1000)
            Next
    
            For i As Integer = 0 To 123
                TimeStep(i) = Abs(TimeNum(i + 1) - TimeNum(i))
                Calc1(i) = Round((ReadingsMm(i + 1) - ReadingsMm(i)) / (ReadingsSec(i + 1) - ReadingsSec(i)), 6)
            Next
    
    	ArrCounter = 0
            InternalArrCounter = 0
    
            For i As Integer = 0 To 124
                Model(i) = Round(Sin((ReadingsSec(i) / Wave_Length + Phase / 360) * 2 * PI) * Half_Amplitude + Level, 6)
                ModelPlus90(i) = Round(Sin((ReadingsSec(i) / Wave_Length + (Phase + 90) / 360) * 2 * PI) * Half_Amplitude + Level, 6)
            Next
    
            For i As Integer = 0 To 124
                Diff(i) = Abs(Round(ReadingsMm(i) - Model(i), 6))
                SqDiff(i) = Abs(Round((ReadingsMm(i) - Model(i)) ^ 2, 6))
            Next
    
            Level = Round(ReadingsMm.Average, 5)
            SqDiffRes = Round(SqDiff.Sum, 5)
    
            For i As Integer = 1 To 123
                If (Calc1(i) > 0 And Calc1(i + 1) < 0) Or (Calc1(i) = 0 And Calc1(i - 1) > 0) Then
                    ArrCounter = ArrCounter + 1
                End If
            Next
    
            ArrCounter = ArrCounter - 1
    
            ReDim Calc2(ArrCounter)
    
            For i As Integer = 1 To 123
                If (Calc1(i) > 0 And Calc1(i + 1) < 0) Or (Calc1(i) = 0 And Calc1(i - 1) > 0) Then
                    Calc2(InternalArrCounter) = ReadingsSec(i)
                    InternalArrCounter = InternalArrCounter + 1
                End If
            Next
    
    
            Half_Amplitude = Abs(Round((ReadingsMm.Max - ReadingsMm.Min) / 2, 5))
            Wave_Length = Round((Calc2.Max - Calc2.Min) / (InternalArrCounter - 1), 5)
            Phase = Round(90 - (360 / Wave_Length * Calc2.Min), 5)
    
    Questi le variabili reali non quelle semplificate:

    A = Phase
    B = Half_Amplitude
    C = Wave_Length
    D = Level
    Solution = SqDiffRes


    Come puoi vedere non ho scritto tutto perchè è abbastanza lunga la cosa ma SqDiffRes è derivante da una serie di calcoli ricavati da dati in degli array.
  • Re: RISOLUTORE DI EXCEL IN VB.NET

    Se non esponi il problema in modo matematicamente chiaro non è possibile aiutarti. Il codice viene dopo.

    Cosa stai tentando di calcolare? Il minimo di una funzione di quattro variabili in un determinato dominio? Stai facendo il best fit in base al principio dei minimi quadrati?
  • Re: RISOLUTORE DI EXCEL IN VB.NET

    Ok ok, non so esattamente cosa dovrei fare in vb.net, ti so dire che cosa faccio attualmente su excel però:

    Su excel ho una sinusoide modello che rappresenta quella ideale e questa che viene invece calcolata in base ai dati, dopodichè come dicevi tu, tramite il risolutore riesco ad ottenere il best fit con quella sinusoide.
    Dovrei fare la stessa cosa su vb.net e non ho idea di come implementare questo modello di risolutore.
  • Re: RISOLUTORE DI EXCEL IN VB.NET

    Quello che devi fare tu è di applicare il metodo "GRG non lineare" sui dati che hai.

    Cerca su internet la spiegazione matematica di questo sistema e poi sviluppa una funzione su VB.NET che la applica, comunque la vedo abbastanza dura dato che si tratta di una cosa non proprio semplice.
  • Re: RISOLUTORE DI EXCEL IN VB.NET

    SirJo ha scritto:


    Quello che devi fare tu è di applicare il metodo "GRG non lineare" sui dati che hai.

    Cerca su internet la spiegazione matematica di questo sistema e poi sviluppa una funzione su VB.NET che la applica, comunque la vedo abbastanza dura dato che si tratta di una cosa non proprio semplice.
    Ok immaginavo, sono circa due giorni che ci sto impazzendo dietro ma non ho idea di come fare. Le ho provate veramente tutte. Extreme Matematics, Matrix, Solver Foundation ma niente. Idee? Sapreste dove indirizzarmi?
  • Re: RISOLUTORE DI EXCEL IN VB.NET

    Ha ragione SirJo, la regressione sinusoidale è un problema complesso.

    Io farei così:

    1) Il livello è esattamente la media di tutti i campioni; te lo calcoli e ti prepari un nuovo array in cui sottrai il livello da tutti i campioni, così hai eliminato una variabile

    2) Devi stimare la frequenza angolare: a questo punto il nuovo array dei campioni seguirà una legge del tipo f(t) = A*sin(?t+?).
    dato che vale la relazione ?²f(t)+f''(t) = 0, allora ? = sqrt(abs(f''(t)/f(t))) per qualsiasi t.
    Quindi ti fai l'array delle derivate seconde, poi l'array dei rapporti tra f'' e f, scarti i valori ottenuti tramite divisione per zero o per denominatori troppo piccoli (scegli tu il limite da fissare), poi ? è la radice quadrata della media dei valori che ti rimangono.

    3) Dato che, espandendo il sin, si può anche scrivere f(t) = a*sin(?t) + b*cos(?t) e dato che conosci ?, a questo punto i due parametri che ti mancano (a e b) si possono ottenere con una semplice regressione lineare.
Devi accedere o registrarti per scrivere nel forum
7 risposte