Main Content

La traduzione di questa pagina non è aggiornata. Fai clic qui per vedere l'ultima versione in inglese.

Semantiche dei sottosistemi di Simulink

Questo insieme di esempi mostra diversi tipi di sottosistemi di Simulink® e le semantiche utilizzate per la loro simulazione. Ciascun esempio fornisce una descrizione del modello e delle sottigliezze che regolano il modo in cui il modello viene eseguito.

Vengono forniti gli esempi per i seguenti tipi di sottosistema.

  • Sottosistemi virtuali e non virtuali

  • Sottosistemi a chiamata di funzione

  • Sottosistemi attivati

  • Sottosistemi abilitati

  • Sottosistemi abilitati e attivati

  • Sottosistemi di azione If e sottosistemi di azione di commutazione del caso

  • Sottosistemi iteratori while

  • Per ciascun sottosistema

  • Sottosistemi iteratori for

Subsystem Semantics Examples

Aprire il modello.

open('SimulinkSubsystemSemantics.prj');
open_system('sl_subsys_semantics');

Panoramica sui sottosistemi virtuali e non virtuali

Il software Simulink prevede due classi di sottosistemi.

  1. I sottosistemi virtuali forniscono una gerarchia grafica nei modelli. I sottosistemi virtuali non hanno alcun impatto sull'esecuzione del modello. Durante l'esecuzione del modello, il motore di Simulink appiattisce tutti i sottosistemi virtuali.

  2. I sottosistemi non virtuali forniscono l'esecuzione del modello e la gerarchia grafica nei modelli. I sottosistemi non virtuali vengono eseguiti come unità singola, nota come esecuzione atomica. Tutti i sottosistemi non virtuali appaiono con un bordo in grassetto nell'area di disegno di Simulink.

Virtual and nonvirtual subsystems

open_system('sl_subsys_semantics');
open_system('sl_subsys_semantics/Virtual and nonvirtual subsystem overview');  

Per creare un sottosistema non virtuale, fare clic con il pulsante destro del mouse sul blocco Subsystem e selezionare Block Parameters (Subsystem) (Parametri del blocco (Sottosistema)). Nella finestra di dialogo dei parametri del blocco, selezionare Treat as atomic unit (Tratta come unità atomica) e fare clic su Apply (Applica).

The block parameters dialog box for the Subsystem2 block

Il sottosistema virtuale produce un elenco di esecuzione piatto, mentre il sottosistema non virtuale include la gerarchia di esecuzione. Per visualizzare l'ordine di esecuzione, nell'Editor di Simulink, nella scheda Debug, selezionare Information Overlays (Sovrapposizioni di informazioni) e fare clic su Execution order (Ordine di esecuzione).

Blocks in a virtual and a nonvirtual subsystem display numbers showing the execution order

L'elenco dei blocchi dell'ordine di esecuzione che appare nell'area di disegno di Simulink visualizza l'ordine di esecuzione.

The execution order block list

L'elenco dei blocchi dell'ordine di esecuzione mostra che il sottosistema non virtuale Subsystem2 è stato eseguito come unità singola.

Un sottosistema non virtuale determina un loop algebrico all'interno della gerarchia di esecuzione. Quando si aggiorna il diagramma, il software emette l'avviso per il loop algebrico.

set_param(gcs,'SimulationCommand','Update')
Warning: Block diagram 'sl_subsys_overview' contains 1 algebraic loop(s). To see more details about the loops use the command <a href="matlab:Simulink.BlockDiagram.getAlgebraicLoops(bdroot);">Simulink.BlockDiagram.getAlgebraicLoops('sl_subsys_overview') </a> or the command line Simulink debugger by typing <a href="matlab:sldebug(bdroot);">sldebug('sl_subsys_overview') </a> in the MATLAB command window. To eliminate this message, set Algebraic loop to "none".

Sottosistemi a chiamata di funzione

Un blocco Function-Call Subsystem contiene un sottosistema a esecuzione condizionata che viene eseguito ogni volta che la porta di controllo riceve un evento di chiamata di funzione. I sottosistemi a chiamata di funzione implementano funzioni richiamabili utilizzando i blocchi di Simulink. Uno Stateflow® Chart (Stateflow), un blocco Function-Call Generator, un blocco MATLAB Function, un blocco S-Function o un blocco Hit Crossing possono fornire eventi a chiamata di funzione.

Function Call Subsystem

Per ulteriori informazioni, vedere Function-Call Subsystem.

Questi esempi mostrano gli utilizzi validi e non validi dei sottosistemi a chiamata di funzione.

close_system('sl_subsys_overview',0)
open_system('s_Function_call_subsystems')

Function-Call Subsystem examples

Chiamata di funzione annidata

In questo modello, Chart è un inizializzatore della chiamata di funzione che esegue la funzione [d1,d2]=f(). La funzione f, a sua volta, esegue la funzione g. Dopo aver richiamato f e g, Chart utilizza i valori d1 e d2 calcolati da f e g.

open_system('sl_subsys_fcncall1')

Two function-call subsystems for a nested function-call event

close_system('sl_subsys_fcncall1')

Chiamata di funzione annidata con condivisione dei dati

Il blocco Chart esegue la funzione [d1,d2]=f() e f, a sua volta, esegue g. Dopo aver richiamato f, Chart utilizza i valori d1 e d2 calcolati da f e g. Le funzioni f e g condividono i dati tramite il segnale s(f/Out2 feeds g/In1). Simulink tratta il segnale s come se il segnale fosse un archivio di dati.

open_system ('sl_subsys_fcncall2')

Two function-call subsystems for nested function-call events with output from one subsystem being fed to another

In generale, gli input di un sottosistema a chiamata di funzione devono essere eseguiti prima dell'inizializzatore della chiamata di funzione (Chart), tranne quando il segnale proviene da un blocco eseguito da un inizializzatore della chiamata di funzione comune. In questo esempio, f() è un inizializzatore della chiamata di funzione di g(). Tuttavia, Chart è un inizializzatore della chiamata di funzione di f(), che rende quindi Chart un inizializzatore della chiamata di funzione comune sia di f() che di g().

In questo senso, il segnale s sottostante può essere considerato come un archivio di dati da cui f() e g() leggono e scrivono in qualsiasi ordine definito d Chart.

close_system('sl_subsys_fcncall2')

Condivisione dei dati tra due sottosistemi a chiamata di funzione con inizializzatore comune

In questo modello, d1 e d2 sono calcolati rispettivamente utilizzando g() e f(). Il grafico utilizza d1 e d2 come input e richiama g() e f(). Le funzioni f e g condividono i dati tramite il segnale s, in altre parole, (f/Out1) alimenta (g/In1). Il modello tratta il segnale s come se il segnale fosse un archivio di dati.

open_system ('sl_subsys_fcncall3')

Two function-call subsystems that use the same function-call event source

In generale, gli input di un sottosistema a chiamata di funzione devono essere eseguiti prima dell'inizializzatore della chiamata di funzione (Chart), tranne quando il segnale proviene da un blocco eseguito da un inizializzatore della chiamata di funzione comune. In questo esempio, Chart è un inizializzatore della chiamata di funzione comune sia di f() che di g(). Pertanto, il segnale s può essere considerato come un archivio di dati.

close_system('sl_subsys_fcncall3')

Sottosistema abilitato contenente un inizializzatore della chiamata di funzione con condivisione dei dati

Questo sottosistema abilitato contiene un diagramma Stateflow che richiama le funzioni f() e g(). Il sottosistema abilitato nel modello sl_subsys_fcncall3 è un inizializzatore della chiamata di funzione comune sia di f() che di g(), quindi il software tratta il segnale d2 come un archivio di dati.

open_system ('sl_subsys_fcncall4')

Two function-call subsystems that use function-call events from the same enabled subsystem

close_system('sl_subsys_fcncall4')

Sottosistema a chiamata di funzione con blocchi Merge

Questo modello contiene un diagramma che esegue due chiamate di funzione. Il modello utilizza i blocchi Merge per mappare più segnali su una singola posizione nella memoria. I segnali f/d1_out e g/d1_out vengono uniti in un'unica posizione nella memoria e rinviati a Chart come d1. I segnali f/k_out e g/k_out vengono uniti in un'unica posizione nella memoria e rinviati a f/k_in. L'unione dei segnali in un'unica posizione nella memoria e la loro trasmissione a Chart consentono a Chart di prendere decisioni complesse su come calcolare i valori.

open_system ('sl_subsys_fcncall5')

Function-call subsystems with Merge block

close_system('sl_subsys_fcncall5')

Inizializzatori multipli di sottosistema a chiamata di funzione

Questo sottosistema a chiamata di funzione è chiamato da due diversi inizializzatori della chiamata di funzione Chart1 e Chart2. La connessione dei dati tra Chart1/out1 e Chart2/d1 garantisce che Chart1 venga eseguito prima di Chart2. È necessario prestare attenzione quando si creano sottosistemi a chiamata di funzione con più chiamate.

Ad esempio, se si rimuove la connessione dei dati tra Chart1 e Chart2, è necessario aggiungere delle priorità a Chart1 e Chart2 per specificare l'ordine di esecuzione relativo di questi blocchi. In caso contrario, l'ordine di esecuzione risulterà ambiguo.

Tuttavia, il software non segnala un errore per questa condizione, poiché la stessa può essere valida per casi specifici. Ad esempio, se si rimuovono tutti gli stati da f() e si elimina la linea che collega Chart1/out1 a Chart2/d1, l'ordine in cui Chart1 e Chart2 sono eseguiti non ha importanza.

open_system ('sl_subsys_fcncall6')

Function-call events from two different sources are set up to execute one function-call subsystem

close_system('sl_subsys_fcncall6')

Sottosistema abilitato contenente sottosistemi a chiamata di funzione che specificano il comportamento di ripristino

Questo sottosistema abilitato contiene due sottosistemi a chiamata di funzione. Il sottosistema a chiamata di funzione sinistro è configurato per mantenere il valore dei propri stati quando è abilitato e per mantenere il valore del proprio output quando è disabilitato. Il sottosistema a chiamata di funzione destro è configurato per ripristinare il valore dei propri stati quando è abilitato e per ripristinare il valore del proprio output quando è disabilitato.

open_system ('sl_subsys_fcncall7')

Function-call subsystems are inside enabled subsystem

close_system('sl_subsys_fcncall7')

Sottosistemi a chiamata di funzione con specifica di esecuzione periodica

Questo diagramma Stateflow pianifica l'ordine di esecuzione dei sottosistemi a chiamata di funzione nel modello. Tuttavia, i sottosistemi a chiamata di funzione vengono eseguiti esattamente una volta per ciascun passo temporale. Le chiamate di funzione non specificano l'esecuzione condizionale ma controllano l'ordine relativo di esecuzione dei sottosistemi. Questa impostazione può risultare utile quando i dati vengono trasferiti tra i sottosistemi utilizzando gli archivi di dati, per garantire la corretta sequenza di lettura e scrittura dagli archivi di dati. Poiché i sottosistemi a chiamata di funzione sono destinati a essere eseguiti incondizionatamente, è necessario specificare che hanno un tempo di campionamento periodico utilizzando il parametro tempo di campionamento dei blocchi Trigger nei sottosistemi. Di conseguenza, durante la simulazione, il motore di Simulink verifica che i sottosistemi a chiamata di funzione periodica vengano eseguiti esattamente una volta per passo temporale.

Inoltre, quando viene generato codice, il tempo trascorso all'interno dei sottosistemi a chiamata di funzione è rappresentato da un valore letterale (il tempo di campionamento specificato e costante), anziché essere mantenuto e calcolato dai timer come avviene di prassi per un sottosistema a chiamata di funzione. Pertanto, il codice generato è significativamente più efficiente.

Per visualizzare il tempo di campionamento dei sottosistemi, nell' Editor di Simulink, nella scheda Debug, selezionare Information Overlays (Sovrapposizioni di informazioni) e fare clic su Colors (Colori).

open_system ('sl_subsys_fcncall8')

Sample time is displayed for function-call subsystems executed periodically

Il colore del tempo di campionamento dei sottosistemi a chiamata di funzione è rosso anziché ciano, ad indicare un tempo di campionamento periodico anziché attivato. Se le connessioni della chiamata di funzione vengono scambiate, il risultato viene ritardato di un passo temporale a causa dell'interazione modificata tra i blocchi Data Store Read e Data Store Write dei sottosistemi.

close_system('sl_subsys_fcncall8')

Inizializzatore della chiamata di funzione con produzione di eventi attivi e inattivi

Questo diagramma Stateflow specifica che l'evento activate è legato allo stato ON. Quando lo stato ON cambia in attivo, il sottosistema a chiamata di funzione Integrate, inizializzato da quell'evento, viene abilitato. Inoltre, quando lo stato cambia in inattivo, il sottosistema a chiamata di funzione inizializzato da quell'evento viene disabilitato. Se il sottosistema a chiamata di funzione è configurato per ripristinare gli stati quando viene abilitato o gli output quando viene disabilitato, tali azioni si verificheranno. In questo esempio, il sottosistema ripristina i propri stati e output dopo essere stato rispettivamente abilitato e disabilitato.

open_system ('sl_subsys_fcncall9')

Function-call subsystem using active and inactive function-call events, respectively

close_system('sl_subsys_fcncall9')

Interpretazione degli output dei sottosistemi a chiamata di funzione

1) Il valore restituito della chiamata di funzione è il collegamento diretto tra l'output di un sottosistema a chiamata di funzione e il suo inizializzatore. Ad esempio, il diagramma Stateflow Chart1 di seguito è un inizializzatore della una chiamata di funzione che esegue la funzione d1=f1(). Dopo aver richiamato f1, il grafico utilizza il valore restituito d1 calcolato da f1 nello stesso intervallo temporale.

2) Nel secondo esempio, l'esecuzione del blocco Unit Delay non viene attivata da Chart2. Pertanto, durante l'esecuzione di Chart2, il segnale d2 mantiene il proprio valore dal passo temporale precedente in cui è stato richiamo il ritardo di unità.

open_system ('sl_subsys_fcncall10')

Observe function-call subsystem output by delaying and feeding the function-call subsystem output into the stateflow chart that initiates the function-call event

close_system('sl_subsys_fcncall10')

Diramazione dei segnali della chiamata di funzione

Questo diagramma Stateflow inizializza un segnale periodico di chiamata di funzione con un periodo di 1, durante l'intervallo temporale in cui il segnale di input u è pari a 1. Per ciascuna chiamata di funzione richiamata, i sottosistemi vengono eseguiti nell'ordine f seguito da h seguito da g. Questo ordine di esecuzione è il risultato dell'ordine specificato nei blocchi di divisione della chiamata di funzione, dove la porta annotata con un punto viene eseguita per prima.

L'esportazione di questo modello nelle release antecedenti alla R2015b produce un errore poiché il segnale b viene trattato come una violazione della dipendenza dai dati.

open_system ('sl_subsys_fcncall11')

Function-call subsystems respond to branched function-call signals

Questo diagramma Stateflow inizializza un segnale periodico di chiamata di funzione con un periodo di 1, durante l'intervallo temporale in cui il segnale di input u è pari a 1.

Per ciascuna funzione di chiamata richiamata, il sottosistema f1 viene eseguito prima del sottosistema g1. Questo ordine di esecuzione è il risultato dell'ordine specificato nel blocco di divisione della chiamata di funzione, dove la porta annotata con un punto viene eseguita per prima.

L'esportazione di questo modello nelle release antecedenti alla R2015b produce un errore poiché il segnale b viene trattato come una violazione della dipendenza dai dati quando il parametro input di latch per i segnali di feedback degli output del sottosistema a chiamata di funzione sul blocco Inport del sottosistema f1 viene cancellato.

Function-call subsystems for branched function-call signals

close_system('sl_subsys_fcncall11')

Sottosistemi a chiamata di funzione illegali

Questo elenco identifica i sottosistemi a chiamata di funzione illegali elencati. Le misure correttive sono spiegate nel corrispondente sottosistema del modello.

open_system('s_Function_call_subsystems')
  1. Errore di ordine di esecuzione ambiguo

  2. Violazione della dipendenza dai dati che coinvolge il blocco guidato dall'inizializzatore della chiamata di funzione

  3. Violazione della dipendenza dai dati che coinvolge il blocco tra due sottosistemi a chiamata di funzione

  4. Errore di ordine di esecuzione ambiguo a causa del feedback dell'output della chiamata di funzione modificata

  5. Errore di ordine di esecuzione ambiguo a causa del feedback dell'output della chiamata di funzione modificata tra due sottosistemi

  6. Violazione della dipendenza dai dati che coinvolge un blocco merge e un diagramma Stateflow

  7. Violazione della dipendenza dai dati che coinvolge il sottosistema atomico e il blocco gain

  8. Violazione della dipendenza dei dati del ciclo del sottosistema a chiamata di funzione

  9. Violazione della dipendenza dai dati indiretta

  10. Violazione della dipendenza dai dati annidata

  11. Sottosistemi a chiamata di funzione con specifica di esecuzione periodica errata

  12. Input dei sottosistemi a chiamata di funzione calcolati all'interno del contesto richiamato

  13. Violazione della dipendenza dai dati che coinvolge il segnale di chiamata della funzione ramificata e il blocco che collega i sottosistemi a chiamata di funzione

close_system('s_Function_call_subsystems',0)

Sottosistemi di azione If e sottosistemi di azione di commutazione del caso

I sottosistemi di azione If vengono eseguiti a ciascun passo temporale quando una condizione logica è vera. I sottosistemi di azione di commutazione del caso vengono eseguiti quando un segnale presenta uno dei valori specificati.

If Action Subsystem

Switch Case Action Subsystem

Per ulteriori informazioni, vedere If Action Subsystem e Switch Case Action Subsystem.

Questi esempi mostrano come utilizzare i sottosistemi di azione If e i sottosistemi di azione di commutazione del caso.

open_system('sl_subsys_semantics')
open_system('sl_subsys_semantics/If Action and Switch Case Action subsystems')

If and Switch Case Action Subsystems examples

close_system('sl_subsys_semantics/If Action and Switch Case Action subsystems')

Sottosistemi attivati

I sottosistemi attivati consentono di implementare il sistema di attivazione del software, il sistema di attivazione dell'hardware o una combinazione dei due. È possibile aggiungere il blocco Triggered Subsystem dal browser delle librerie di Simulink. In alternativa, è possibile creare questo sottosistema inserendo il blocco Trigger all'interno di un blocco Subsystem.

Triggered Subsystems

Per ulteriori informazioni, vedere Triggered Subsystem.

Questi esempi mostrano come utilizzare i sottosistemi attivati.

open_system('sl_subsys_semantics');
open_system('sl_subsys_semantics/Triggered subsystems')

Triggered Subsystem examples

L'attivazione del software è definita in questo codice:

if (trigger_signal_edge_detected) {

out(t) = f(in(t));

}

L'attivazione dell'hardware è definita in questo codice:

if (trigger_signal_edge_detected) {

out(t) = f(in(t-h)); // h == last step size

}

Ciascuna porta di input di un sottosistema attivato configura se l'input debba essere o non essere bloccato. Un input bloccato fornisce la semantica di attivazione dell'hardware per quella porta di input. Il software contrassegna una porta di input bloccato con il simbolo <L>.

close_system('sl_subsys_semantics/Triggered subsystems')

Sottosistemi abilitati

I sottosistemi abilitati consentono di creare sottosistemi ad esecuzione condizionata che vengono eseguiti solo quando il segnale di abilitazione è maggiore di zero. I sottosistemi abilitati consentono di controllare il valore iniziale dei segnali di output e di ripristinare o meno gli stati ogni volta che il sottosistema viene abilitato.

È possibile aggiungere il blocco Enabled Subsystem dal browser delle librerie di Simulink. In alternativa, è possibile creare questo sottosistema inserendo il blocco Enable all'interno di un blocco Subsystem.

Enabled Subsystem

Per ulteriori informazioni, vedere Enabled Subsystem.

Gli esempi seguenti mostrano come utilizzare i sottosistemi abilitati.

open_system('sl_subsys_semantics');
open_system('sl_subsys_semantics/Enabled subsystems')      

Enabled Subsystem examples

close_system('sl_subsys_semantics/Enabled subsystems')

Sottosistema abilitato e attivato

Questi sottosistemi illustrano l'opzione per gli stati e il ripristino dell'outport. Il sottosistema abilitato e attivato viene eseguito quando si verificano entrambe le condizioni di abilitazione e attivazione.

È possibile aggiungere il blocco Enabled and Triggered Subsystem dal browser delle librerie di Simulink. In alternativa, è possibile creare questo sottosistema inserendo sia il blocco Enable che il blocco Trigger all'interno di un blocco Subsystem.

Per ulteriori informazioni, vedere Enabled and Triggered Subsystem.

Questo esempio mostra come utilizzare i sottosistemi abilitati e attivati.

open_system('sl_subsys_semantics')
open_system('sl_subsys_enabtrig1.slx')  

Enabled and Triggered Subsystems

close_system('sl_subsys_enabtrig1.slx')        

Sottosistemi ripristinabili

I sottosistemi ripristinabili consentono di ripristinare gli stati dei blocchi all'interno del sottosistema in base al segnale di ripristino. È possibile aggiungere il blocco Resettable Subsystem dal browser delle librerie di Simulink.

Resettable Subsystem

Per ulteriori informazioni, vedere Resettable Subsystem.

Questi esempi mostrano come utilizzare i sottosistemi ripristinabili.

open_system('sl_subsys_semantics')
open_system('sl_subsys_semantics/Resettable subsystems')

Resettable Subsystem examples

close_system('sl_subsys_semantics/Resettable subsystems')

Sottosistema for each

Il sottosistema for each ripete l'esecuzione durante un passo temporale di simulazione su ciascun elemento o subarray di un segnale di input o di un array di parametri della maschera. È possibile aggiungere il blocco For Each Subsystem dal browser delle librerie di Simulink. In alternativa, è possibile creare questo blocco inserendo un blocco For Each all'interno di un blocco Subsystem. Un sottosistema for each ripete l'algoritmo su singoli elementi o subarray di un segnale di input. Un sottosistema for each mantiene gli stati del blocco separati per ciascun elemento o subarray che elabora il sottosistema.

For Each Subsystem

Per ulteriori informazioni, vedere For Each Subsystem.

Questi esempi mostrano come utilizzare i sottosistemi for each.

open_system('sl_subsys_semantics');
open_system('sl_subsys_semantics/For Each subsystems')

For Each Subsystem examples

close_system('sl_subsys_semantics/For Each subsystems')

Sottosistema iteratore while

Il sottosistema iteratore while ripete l'esecuzione durante un passo temporale di simulazione quando una condizione logica è true. È possibile aggiungere il blocco While Iterator Subsystem dal browser delle librerie di Simulink. In alternativa, è possibile creare questo sottosistema inserendo un blocco While Iterator all'interno di un blocco Subsystem. Un sottosistema iteratore while esegue più iterazioni per ciascun passo temporale del modello. Il numero di iterazioni è controllato dalla condizione while dell'iteratore.

Il sottosistema iteratore while è simile a un sottosistema a chiamata di funzione, in quanto può essere eseguito per un numero qualsiasi di iterazioni in un determinato passo temporale.

Il sottosistema iteratore while si differenzia da un sottosistema a chiamata di funzione perché non contiene un iniziatore separato, come un diagramma Stateflow. Inoltre, il sottosistema iteratore while ha accesso al numero di iterazione corrente, prodotto facoltativamente dal blocco While Iterator.

While Iterator Subsystem

Per ulteriori informazioni, vedere While Iterator Subsystem.

Questi esempi mostrano come utilizzare i sottosistemi iteratori while.

open_system('sl_subsys_semantics');
open_system('sl_subsys_semantics/While Iterator subsystems')

While Iterator Subsystem example

close_system('sl_subsys_semantics/While Iterator subsystems')

Sottosistema iteratore for

Il sottosistema iteratore for ripete l'esecuzione durante un passo temporale di simulazione per un numero specificato di iterazioni. È possibile aggiungere il blocco While Iterator Subsystem dal browser delle librerie di Simulink. In alternativa, è possibile creare questo sottosistema inserendo un blocco For Iterator all'interno di un blocco Subsystem. Il sottosistema iteratore for esegue un numero fisso di iterazioni per ciascun passo temporale del modello. Il numero di iterazioni può essere un input esterno al sottosistema for o specificato internamente nel blocco For Iterator.

Un sottosistema iteratore for è molto simile a un sottosistema iteratore while, con la restrizione che il numero di iterazioni per ciascun passo temporale è fisso.

For Iterator Subsystem

Per ulteriori informazioni, vedere For Iterator Subsystem.

Gli esempi seguenti mostrano come utilizzare i sottosistemi iteratori for.

open_system('sl_subsys_semantics');
open_system('sl_subsys_semantics/For Iterator subsystems')   

For Iterator Subsystem Example

close_system('sl_subsys_semantics/For Iterator subsystems')

Vedi anche

Argomenti complementari